/-
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, Sébastien Gouëzel

Uniform embeddings of uniform spaces. Extension of uniform continuous functions.
-/
import topology.uniform_space.cauchy

open filter topological_space lattice set classical
local attribute [instance, priority 0] prop_decidable
variables {α : Type*} {β : Type*} {γ : Type*} [uniform_space α]
universe u

local notation `𝓤` := uniformity

def uniform_embedding [uniform_space β] (f : α → β) :=
function.injective f ∧
comap (λx:α×α, (f x.1, f x.2)) (𝓤 β) = 𝓤 α

theorem uniform_embedding_def [uniform_space β] {f : α → β} :
  uniform_embedding f ↔ function.injective f ∧ ∀ s, s ∈ 𝓤 α ↔
    ∃ t ∈ 𝓤 β, ∀ x y : α, (f x, f y) ∈ t → (x, y) ∈ s :=
by rw [uniform_embedding, eq_comm, filter.ext_iff]; simp [subset_def]

theorem uniform_embedding_def' [uniform_space β] {f : α → β} :
  uniform_embedding f ↔ function.injective f ∧ uniform_continuous f ∧
    ∀ s, s ∈ 𝓤 α →
      ∃ t ∈ 𝓤 β, ∀ x y : α, (f x, f y) ∈ t → (x, y) ∈ s :=
by simp [uniform_embedding_def, uniform_continuous_def]; exact
⟨λ ⟨I, H⟩, ⟨I, λ s su, (H _).2 ⟨s, su, λ x y, id⟩, λ s, (H s).1⟩,
 λ ⟨I, H₁, H₂⟩, ⟨I, λ s, ⟨H₂ s,
   λ ⟨t, tu, h⟩, sets_of_superset _ (H₁ t tu) (λ ⟨a, b⟩, h a b)⟩⟩⟩

lemma uniform_embedding.uniform_continuous [uniform_space β] {f : α → β}
  (hf : uniform_embedding f) : uniform_continuous f :=
(uniform_embedding_def'.1 hf).2.1

lemma uniform_embedding.uniform_continuous_iff [uniform_space β] [uniform_space γ] {f : α → β}
  {g : β → γ} (hg : uniform_embedding g) : uniform_continuous f ↔ uniform_continuous (g ∘ f) :=
by simp [uniform_continuous, tendsto]; rw [← hg.2, ← map_le_iff_le_comap, filter.map_map]

lemma uniform_embedding.embedding [uniform_space β] {f : α → β} (h : uniform_embedding f) : embedding f :=
begin
  refine ⟨h.left, eq_of_nhds_eq_nhds $ assume a, _⟩,
  rw [nhds_induced_eq_comap, nhds_eq_uniformity, nhds_eq_uniformity, ← h.right,
    comap_lift'_eq, comap_lift'_eq2];
    { refl <|> exact monotone_preimage }
end

lemma uniform_embedding.dense_embedding [uniform_space β] {f : α → β}
  (h : uniform_embedding f) (hd : ∀x, x ∈ closure (range f)) : dense_embedding f :=
{ dense   := hd,
  inj     := h.left,
  induced := assume a, by rw [h.embedding.2, nhds_induced_eq_comap] }

lemma closure_image_mem_nhds_of_uniform_embedding
  [uniform_space α] [uniform_space β] {s : set (α×α)} {e : α → β} (b : β)
  (he₁ : uniform_embedding e) (he₂ : dense_embedding e) (hs : s ∈ 𝓤 α) :
  ∃a, closure (e '' {a' | (a, a') ∈ s}) ∈ nhds b :=
have s ∈ comap (λp:α×α, (e p.1, e p.2)) (𝓤 β),
  from he₁.right.symm ▸ hs,
let ⟨t₁, ht₁u, ht₁⟩ := this in
have ht₁ : ∀p:α×α, (e p.1, e p.2) ∈ t₁ → p ∈ s, from ht₁,
let ⟨t₂, ht₂u, ht₂s, ht₂c⟩ := comp_symm_of_uniformity ht₁u in
let ⟨t, htu, hts, htc⟩ := comp_symm_of_uniformity ht₂u in
have preimage e {b' | (b, b') ∈ t₂} ∈ comap e (nhds b),
  from preimage_mem_comap $ mem_nhds_left b ht₂u,
let ⟨a, (ha : (b, e a) ∈ t₂)⟩ := inhabited_of_mem_sets (he₂.comap_nhds_neq_bot) this in
have ∀b' (s' : set (β × β)), (b, b') ∈ t → s' ∈ 𝓤 β →
  {y : β | (b', y) ∈ s'} ∩ e '' {a' : α | (a, a') ∈ s} ≠ ∅,
  from assume b' s' hb' hs',
  have preimage e {b'' | (b', b'') ∈ s' ∩ t} ∈ comap e (nhds b'),
    from preimage_mem_comap $ mem_nhds_left b' $ inter_mem_sets hs' htu,
  let ⟨a₂, ha₂s', ha₂t⟩ := inhabited_of_mem_sets (he₂.comap_nhds_neq_bot) this in
  have (e a, e a₂) ∈ t₁,
    from ht₂c $ prod_mk_mem_comp_rel (ht₂s ha) $ htc $ prod_mk_mem_comp_rel hb' ha₂t,
  have e a₂ ∈ {b'':β | (b', b'') ∈ s'} ∩ e '' {a' | (a, a') ∈ s},
    from ⟨ha₂s', mem_image_of_mem _ $ ht₁ (a, a₂) this⟩,
  ne_empty_of_mem this,
have ∀b', (b, b') ∈ t → nhds b' ⊓ principal (e '' {a' | (a, a') ∈ s}) ≠ ⊥,
begin
  intros b' hb',
  rw [nhds_eq_uniformity, lift'_inf_principal_eq, lift'_neq_bot_iff],
  exact assume s, this b' s hb',
  exact monotone_inter monotone_preimage monotone_const
end,
have ∀b', (b, b') ∈ t → b' ∈ closure (e '' {a' | (a, a') ∈ s}),
  from assume b' hb', by rw [closure_eq_nhds]; exact this b' hb',
⟨a, (nhds b).sets_of_superset (mem_nhds_left b htu) this⟩

lemma uniform_embedding_comap {f : α → β} [u : uniform_space β] (hf : function.injective f) :
  @uniform_embedding α β (uniform_space.comap f u) u f :=
⟨hf, rfl⟩

lemma uniform_embedding_subtype_emb {α : Type*} {β : Type*} [uniform_space α] [uniform_space β]
  (p : α → Prop) {e : α → β} (ue : uniform_embedding e) (de : dense_embedding e) :
  uniform_embedding (de.subtype_emb p) :=
⟨(de.subtype p).inj,
  by simp [comap_comap_comp, (∘), dense_embedding.subtype_emb, uniformity_subtype, ue.right.symm]⟩

lemma uniform_embedding.prod {α' : Type*} {β' : Type*}
  [uniform_space α] [uniform_space β] [uniform_space α'] [uniform_space β']
  {e₁ : α → α'} {e₂ : β → β'} (h₁ : uniform_embedding e₁) (h₂ : uniform_embedding e₂) :
  uniform_embedding (λp:α×β, (e₁ p.1, e₂ p.2)) :=
⟨assume ⟨a₁, b₁⟩ ⟨a₂, b₂⟩,
  by simp [prod.mk.inj_iff]; exact assume eq₁ eq₂, ⟨h₁.left eq₁, h₂.left eq₂⟩,
  by simp [(∘), uniformity_prod, h₁.right.symm, h₂.right.symm, comap_inf, comap_comap_comp]⟩

/-- A set is complete iff its image under a uniform embedding is complete. -/
lemma is_complete_image_iff [uniform_space β] {m : α → β} {s : set α}
  (hm : uniform_embedding m) : is_complete (m '' s) ↔ is_complete s :=
begin
  refine ⟨λ c f hf fs, _, λ c f hf fs, _⟩,
  { let f' := map m f,
    have cf' : cauchy f' := cauchy_map (uniform_embedding.uniform_continuous hm) hf,
    have f's : f' ≤ principal (m '' s),
    { simp only [filter.le_principal_iff, set.mem_image, filter.mem_map],
      exact mem_sets_of_superset (filter.le_principal_iff.1 fs) (λx hx, ⟨x, hx, rfl⟩) },
    rcases c f' cf' f's with ⟨y, yms, hy⟩,
    rcases mem_image_iff_bex.1 yms with ⟨x, xs, rfl⟩,
    rw [map_le_iff_le_comap, ← nhds_induced_eq_comap, ← (uniform_embedding.embedding hm).2] at hy,
    exact ⟨x, xs, hy⟩ },
  { rw filter.le_principal_iff at fs,
    let f' := comap m f,
    have cf' : cauchy f',
    { have : comap m f ≠ ⊥,
      { refine comap_neq_bot (λt ht, _),
        have A : t ∩ m '' s ∈ f := filter.inter_mem_sets ht fs,
        have : t ∩ m '' s ≠ ∅,
        { by_contradiction h,
          simp only [not_not, ne.def] at h,
          simpa [h, empty_in_sets_eq_bot, hf.1] using A },
        rcases ne_empty_iff_exists_mem.1 this with ⟨x, ⟨xt, xms⟩⟩,
        rcases mem_image_iff_bex.1 xms with ⟨y, ys, yx⟩,
        rw ← yx at xt,
        exact ⟨y, xt⟩ },
      apply cauchy_comap _ hf this,
      simp only [hm.2, le_refl] },
    have : f' ≤ principal s := by simp [f']; exact
      ⟨m '' s, by simpa using fs, by simp [preimage_image_eq s hm.1]⟩,
    rcases c f' cf' this with ⟨x, xs, hx⟩,
    existsi [m x, mem_image_of_mem m xs],
    rw [(uniform_embedding.embedding hm).2, nhds_induced_eq_comap] at hx,
    calc f = map m f' : (map_comap $ filter.mem_sets_of_superset fs $ image_subset_range _ _).symm
      ... ≤ map m (comap m (nhds (m x))) : map_mono hx
      ... ≤ nhds (m x) : map_comap_le }
end

lemma complete_space_extension [uniform_space β] {m : β → α}
  (hm : uniform_embedding m)
  (dense : ∀x, x ∈ closure (range m))
  (h : ∀f:filter β, cauchy f → ∃x:α, map m f ≤ nhds x) :
  complete_space α :=
⟨assume (f : filter α), assume hf : cauchy f,
let
  p : set (α × α) → set α → set α := λs t, {y : α| ∃x:α, x ∈ t ∧ (x, y) ∈ s},
  g := (𝓤 α).lift (λs, f.lift' (p s))
in
have mp₀ : monotone p,
  from assume a b h t s ⟨x, xs, xa⟩, ⟨x, xs, h xa⟩,
have mp₁ : ∀{s}, monotone (p s),
  from assume s a b h x ⟨y, ya, yxs⟩, ⟨y, h ya, yxs⟩,

have f ≤ g, from
  le_infi $ assume s, le_infi $ assume hs, le_infi $ assume t, le_infi $ assume ht,
  le_principal_iff.mpr $
  mem_sets_of_superset ht $ assume x hx, ⟨x, hx, refl_mem_uniformity hs⟩,

have g ≠ ⊥, from neq_bot_of_le_neq_bot hf.left this,

have comap m g ≠ ⊥, from comap_neq_bot $ assume t ht,
  let ⟨t', ht', ht_mem⟩ := (mem_lift_sets $ monotone_lift' monotone_const mp₀).mp ht in
  let ⟨t'', ht'', ht'_sub⟩ := (mem_lift'_sets mp₁).mp ht_mem in
  let ⟨x, (hx : x ∈ t'')⟩ := inhabited_of_mem_sets hf.left ht'' in
  have h₀ : nhds x ⊓ principal (range m) ≠ ⊥,
    by simp [closure_eq_nhds] at dense; exact dense x,
  have h₁ : {y | (x, y) ∈ t'} ∈ nhds x ⊓ principal (range m),
    from @mem_inf_sets_of_left α (nhds x) (principal (range m)) _ $ mem_nhds_left x ht',
  have h₂ : range m ∈ nhds x ⊓ principal (range m),
    from @mem_inf_sets_of_right α (nhds x) (principal (range m)) _ $ subset.refl _,
  have {y | (x, y) ∈ t'} ∩ range m ∈ nhds x ⊓ principal (range m),
    from @inter_mem_sets α (nhds x ⊓ principal (range m)) _ _ h₁ h₂,
  let ⟨y, xyt', b, b_eq⟩ := inhabited_of_mem_sets h₀ this in
  ⟨b, b_eq.symm ▸ ht'_sub ⟨x, hx, xyt'⟩⟩,

have cauchy g, from
  ⟨‹g ≠ ⊥›, assume s hs,
  let
    ⟨s₁, hs₁, (comp_s₁ : comp_rel s₁ s₁ ⊆ s)⟩ := comp_mem_uniformity_sets hs,
    ⟨s₂, hs₂, (comp_s₂ : comp_rel s₂ s₂ ⊆ s₁)⟩ := comp_mem_uniformity_sets hs₁,
    ⟨t, ht, (prod_t : set.prod t t ⊆ s₂)⟩ := mem_prod_same_iff.mp (hf.right hs₂)
  in
  have hg₁ : p (preimage prod.swap s₁) t ∈ g,
    from mem_lift (symm_le_uniformity hs₁) $ @mem_lift' α α f _ t ht,
  have hg₂ : p s₂ t ∈ g,
    from mem_lift hs₂ $ @mem_lift' α α f _ t ht,
  have hg : set.prod (p (preimage prod.swap s₁) t) (p s₂ t) ∈ filter.prod g g,
    from @prod_mem_prod α α _ _ g g hg₁ hg₂,
  (filter.prod g g).sets_of_superset hg
    (assume ⟨a, b⟩ ⟨⟨c₁, c₁t, hc₁⟩, ⟨c₂, c₂t, hc₂⟩⟩,
      have (c₁, c₂) ∈ set.prod t t, from ⟨c₁t, c₂t⟩,
      comp_s₁ $ prod_mk_mem_comp_rel hc₁ $
      comp_s₂ $ prod_mk_mem_comp_rel (prod_t this) hc₂)⟩,

have cauchy (filter.comap m g),
  from cauchy_comap (le_of_eq hm.right) ‹cauchy g› (by assumption),

let ⟨x, (hx : map m (filter.comap m g) ≤ nhds x)⟩ := h _ this in
have map m (filter.comap m g) ⊓ nhds x ≠ ⊥,
  from (le_nhds_iff_adhp_of_cauchy (cauchy_map hm.uniform_continuous this)).mp hx,
have g ⊓ nhds x ≠ ⊥,
  from neq_bot_of_le_neq_bot this (inf_le_inf (assume s hs, ⟨s, hs, subset.refl _⟩) (le_refl _)),

⟨x, calc f ≤ g : by assumption
  ... ≤ nhds x : le_nhds_of_cauchy_adhp ‹cauchy g› this⟩⟩

lemma totally_bounded_preimage [uniform_space α] [uniform_space β] {f : α → β} {s : set β}
  (hf : uniform_embedding f) (hs : totally_bounded s) : totally_bounded (f ⁻¹' s) :=
λ t ht, begin
  rw ← hf.2 at ht,
  rcases mem_comap_sets.2 ht with ⟨t', ht', ts⟩,
  rcases totally_bounded_iff_subset.1
    (totally_bounded_subset (image_preimage_subset f s) hs) _ ht' with ⟨c, cs, hfc, hct⟩,
  refine ⟨f ⁻¹' c, finite_preimage hf.1 hfc, λ x h, _⟩,
  have := hct (mem_image_of_mem f h), simp at this ⊢,
  rcases this with ⟨z, zc, zt⟩,
  rcases cs zc with ⟨y, yc, rfl⟩,
  exact ⟨y, zc, ts (by exact zt)⟩
end

section uniform_extension

variables
  [uniform_space β]
  [uniform_space γ]
  {e : β → α}
  (h_e : uniform_embedding e)
  (h_dense : ∀x, x ∈ closure (range e))
  {f : β → γ}
  (h_f : uniform_continuous f)

local notation `ψ` := (h_e.dense_embedding h_dense).extend f

lemma uniformly_extend_of_emb (b : β) : ψ (e b) = f b :=
dense_embedding.extend_e_eq _ b

lemma uniformly_extend_exists [complete_space γ] (a : α) :
  ∃c, tendsto f (comap e (nhds a)) (nhds c) :=
let de := (h_e.dense_embedding h_dense) in
have cauchy (nhds a), from cauchy_nhds,
have cauchy (comap e (nhds a)), from
  cauchy_comap (le_of_eq h_e.right) this de.comap_nhds_neq_bot,
have cauchy (map f (comap e (nhds a))), from
  cauchy_map h_f this,
complete_space.complete this

lemma uniformly_extend_spec [complete_space γ] (h_f : uniform_continuous f) (a : α) :
  tendsto f (comap e (nhds a)) (nhds (ψ a)) :=
let de := (h_e.dense_embedding h_dense) in
begin
  by_cases ha : a ∈ range e,
  { rcases ha with ⟨b, rfl⟩,
    rw [uniformly_extend_of_emb, de.induced],
    exact h_f.continuous.tendsto _ },
  { simp only [dense_embedding.extend, dif_neg ha],
    exact (@lim_spec _ _ (id _) _ $ uniformly_extend_exists h_e h_dense h_f _) }
end

lemma uniform_continuous_uniformly_extend [cγ : complete_space γ] : uniform_continuous ψ :=
assume d hd,
let ⟨s, hs, hs_comp⟩ := (mem_lift'_sets $
  monotone_comp_rel monotone_id $ monotone_comp_rel monotone_id monotone_id).mp (comp_le_uniformity3 hd) in
have h_pnt : ∀{a m}, m ∈ nhds a → ∃c, c ∈ f '' preimage e m ∧ (c, ψ a) ∈ s ∧ (ψ a, c) ∈ s,
  from assume a m hm,
  have nb : map f (comap e (nhds a)) ≠ ⊥,
    from map_ne_bot (h_e.dense_embedding h_dense).comap_nhds_neq_bot,
  have (f '' preimage e m) ∩ ({c | (c, ψ a) ∈ s } ∩ {c | (ψ a, c) ∈ s }) ∈ map f (comap e (nhds a)),
    from inter_mem_sets (image_mem_map $ preimage_mem_comap $ hm)
      (uniformly_extend_spec h_e h_dense h_f _ (inter_mem_sets (mem_nhds_right _ hs) (mem_nhds_left _ hs))),
  inhabited_of_mem_sets nb this,
have preimage (λp:β×β, (f p.1, f p.2)) s ∈ 𝓤 β,
  from h_f hs,
have preimage (λp:β×β, (f p.1, f p.2)) s ∈ comap (λx:β×β, (e x.1, e x.2)) (𝓤 α),
  by rwa [h_e.right.symm] at this,
let ⟨t, ht, ts⟩ := this in
show preimage (λp:(α×α), (ψ p.1, ψ p.2)) d ∈ 𝓤 α,
  from (𝓤 α).sets_of_superset (interior_mem_uniformity ht) $
  assume ⟨x₁, x₂⟩ hx_t,
  have nhds (x₁, x₂) ≤ principal (interior t),
    from is_open_iff_nhds.mp is_open_interior (x₁, x₂) hx_t,
  have interior t ∈ filter.prod (nhds x₁) (nhds x₂),
    by rwa [nhds_prod_eq, le_principal_iff] at this,
  let ⟨m₁, hm₁, m₂, hm₂, (hm : set.prod m₁ m₂ ⊆ interior t)⟩ := mem_prod_iff.mp this in
  let ⟨a, ha₁, _, ha₂⟩ := h_pnt hm₁ in
  let ⟨b, hb₁, hb₂, _⟩ := h_pnt hm₂ in
  have set.prod (preimage e m₁) (preimage e m₂) ⊆ preimage (λp:(β×β), (f p.1, f p.2)) s,
    from calc _ ⊆ preimage (λp:(β×β), (e p.1, e p.2)) (interior t) : preimage_mono hm
    ... ⊆ preimage (λp:(β×β), (e p.1, e p.2)) t : preimage_mono interior_subset
    ... ⊆ preimage (λp:(β×β), (f p.1, f p.2)) s : ts,
  have set.prod (f '' preimage e m₁) (f '' preimage e m₂) ⊆ s,
    from calc set.prod (f '' preimage e m₁) (f '' preimage e m₂) =
      (λp:(β×β), (f p.1, f p.2)) '' (set.prod (preimage e m₁) (preimage e m₂)) : prod_image_image_eq
    ... ⊆ (λp:(β×β), (f p.1, f p.2)) '' preimage (λp:(β×β), (f p.1, f p.2)) s : mono_image this
    ... ⊆ s : image_subset_iff.mpr $ subset.refl _,
  have (a, b) ∈ s, from @this (a, b) ⟨ha₁, hb₁⟩,
  hs_comp $ show (ψ x₁, ψ x₂) ∈ comp_rel s (comp_rel s s),
    from ⟨a, ha₂, ⟨b, this, hb₂⟩⟩

lemma uniform_extend_subtype {α : Type*} {β : Type*} {γ : Type*}
  [uniform_space α] [uniform_space β] [uniform_space γ] [complete_space γ]
  {p : α → Prop} {e : α → β} {f : α → γ} {b : β} {s : set α}
  (hf : uniform_continuous (λx:subtype p, f x.val))
  (he : uniform_embedding e) (hd : ∀x:β, x ∈ closure (range e))
  (hb : closure (e '' s) ∈ nhds b) (hs : is_closed s) (hp : ∀x∈s, p x) :
  ∃c, tendsto f (comap e (nhds b)) (nhds c) :=
have de : dense_embedding e,
  from he.dense_embedding hd,
have de' : dense_embedding (de.subtype_emb p),
  by exact de.subtype p,
have ue' : uniform_embedding (de.subtype_emb p),
  from uniform_embedding_subtype_emb _ he de,
have b ∈ closure (e '' {x | p x}),
  from (closure_mono $ mono_image $ hp) (mem_of_nhds hb),
let ⟨c, (hc : tendsto (f ∘ subtype.val) (comap (de.subtype_emb p) (nhds ⟨b, this⟩)) (nhds c))⟩ :=
  uniformly_extend_exists ue' de'.dense hf _ in
begin
  rw [nhds_subtype_eq_comap] at hc,
  simp [comap_comap_comp] at hc,
  change (tendsto (f ∘ @subtype.val α p) (comap (e ∘ @subtype.val α p) (nhds b)) (nhds c)) at hc,
  rw [←comap_comap_comp, tendsto_comap'_iff] at hc,
  exact ⟨c, hc⟩,
  exact ⟨_, hb, assume x,
    begin
      change e x ∈ (closure (e '' s)) → x ∈ range subtype.val,
      rw [←closure_induced, closure_eq_nhds, mem_set_of_eq, (≠), nhds_induced_eq_comap, de.induced],
      change x ∈ {x | nhds x ⊓ principal s ≠ ⊥} → x ∈ range subtype.val,
      rw [←closure_eq_nhds, closure_eq_of_is_closed hs],
      exact assume hxs, ⟨⟨x, hp x hxs⟩, rfl⟩,
      exact de.inj
    end⟩
end
end uniform_extension


-- import category_theory.functor.left_derived
-- import category_theory.monoidal.tor
-- import category_theory.monoidal.braided

import algebra.category.Module.basic
import linear_algebra.direct_sum.finsupp

lemma linear_map.map_ite {R : Type*} [comm_ring R] (L M N : Type*)
  [add_comm_monoid L] [add_comm_monoid M] [add_comm_monoid N]
  [module R L] [module R M] [module R N] (f f' : L →ₗ[R] M) (g : M →ₗ[R] N)
  (p : Prop) [decidable p] (x) :
  g ((if p then f else f') x) = if p then g (f x) else g (f' x) :=
begin
  split_ifs;
  refl,
end

lemma linear_map.comp_ite {R : Type*} [comm_ring R] (L M N : Type*)
  [add_comm_monoid L] [add_comm_monoid M] [add_comm_monoid N]
  [module R L] [module R M] [module R N] (f f' : L →ₗ[R] M) (g : M →ₗ[R] N)
  (p : Prop) [decidable p] :
  g.comp (if p then f else f') = if p then g.comp f else g.comp f' :=
begin
  split_ifs;
  refl,
end

lemma linear_map.map_dite {R : Type*} [comm_ring R] (L M N : Type*)
  [add_comm_monoid L] [add_comm_monoid M] [add_comm_monoid N]
  [module R L] [module R M] [module R N] (g : M →ₗ[R] N)
  (p : Prop) [decidable p]
  (f : p → (L →ₗ[R] M)) (f' : ¬ p → (L →ₗ[R] M)) (x) :
  g ((if H : p
  then f H
  else f' H) x) = if H : p then g (f H x) else g (f' H x) :=
begin
  split_ifs;
  refl,
end

lemma linear_map.comp_sum {R : Type*} [comm_ring R] (L M N : Type*)
  [add_comm_monoid L] [add_comm_monoid M] [add_comm_monoid N]
  [module R L] [module R M] [module R N] (g : M →ₗ[R] N) {ι : Type*} (s : finset ι)
  (f : ι → (L →ₗ[R] M)) : g.comp (s.sum f) = s.sum (λ x, g.comp $ f x) :=
begin
  classical,
  induction s using finset.induction_on with _ _ h ih,
  { rw [finset.sum_empty, linear_map.comp_zero, finset.sum_empty], },
  { rw [finset.sum_insert h, linear_map.comp_add, finset.sum_insert h, ih], },
end

lemma linear_map.ite_apply {R : Type*} [comm_ring R] (L M : Type*)
  [add_comm_monoid L] [add_comm_monoid M]
  [module R L] [module R M]
  (p : Prop) [decidable p]
  (f : (L →ₗ[R] M)) (f' : (L →ₗ[R] M)) (x) :
  (if p
  then f
  else f') x = if p then f x else f' x :=
begin
  split_ifs;
  refl,
end

lemma linear_map.dite_apply {R : Type*} [comm_ring R] (L M : Type*)
  [add_comm_monoid L] [add_comm_monoid M]
  [module R L] [module R M]
  (p : Prop) [decidable p]
  (f : p → (L →ₗ[R] M)) (f' : ¬ p → (L →ₗ[R] M)) (x) :
  (if H : p
  then f H
  else f' H) x = if H : p then f H x else f' H x :=
begin
  split_ifs;
  refl,
end

open_locale direct_sum

lemma direct_sum.dite_apply (R : Type*) [comm_ring R]
  (p : Prop) [decidable p]
  {ι : Type*}  (M : (ι → Type*))  [∀ i , add_comm_monoid (M i)] [∀ i , module R (M i)]
  (x : p → ⨁ i, M i)
  (x' : ¬ p → ⨁ i, M i) (y) :
  (if H : p then x H else x' H) y =
  if H : p then x H y else x' H y :=
begin
  split_ifs;
  refl,
end

lemma direct_sum.apply_dite (R : Type*) [comm_ring R]
  (p : Prop) [decidable p]
  {ι : Type*}  (M : (ι → Type*))  [∀ i , add_comm_monoid (M i)] [∀ i , module R (M i)]
  (x : ⨁ i, M i) (y : p → ι) (y' : ¬ p → ι) :
  x (if H : p then y H else y' H) =
  (if H : p then x _ else x _) :=
begin
  split_ifs;
  refl,
end

open_locale big_operators

lemma finset.sum_subsingleton {ι M : Type*} [add_comm_monoid M]
  (s : set ι) (hs : s.subsingleton) [decidable s.nonempty] (f : ι → M) :
  ∑ i in hs.finite.to_finset, f i =
  if H : s.nonempty then f H.some else 0 :=
begin
  have s_eq : s = if H : s.nonempty then {H.some} else ∅,
  { split_ifs with H,
    { ext1, simp only [set.mem_singleton_iff],
      split,
      { intros h, refine hs h H.some_spec, },
      { intros h, rw h, exact H.some_spec, }, },
    { rwa set.not_nonempty_iff_eq_empty at H, }, },
  split_ifs with H,
  { rw dif_pos H at s_eq,
    transitivity ∑ i in {H.some}, f i,
    { refine finset.sum_congr _ (λ _ _, rfl),
      ext, simp only [set.finite.mem_to_finset, finset.mem_singleton],
      rw ← set.mem_singleton_iff,
      convert iff.rfl, exact s_eq.symm, },
  rw finset.sum_singleton },
  { rw set.not_nonempty_iff_eq_empty at H,
    transitivity ∑ i in ∅, f i,
    { refine finset.sum_congr _ (λ _ _, rfl),
      simpa only [set.finite_to_finset_eq_empty_iff], },
    rw finset.sum_empty, },
end

-- noncomputable theory

-- open category_theory
-- open category_theory.limits

-- universes v u

-- namespace category_theory

-- section

-- variables {C : Type u} [category.{v} C] {D : Type*} [category D]

-- -- Importing `category_theory.abelian.projective` and assuming
-- -- `[abelian C] [enough_projectives C] [abelian D]` suffices to acquire all the following:
-- variables [preadditive C] [has_zero_object C] [has_equalizers C]
--   [has_images C] [has_projective_resolutions C]
-- variables [preadditive D] [has_equalizers D] [has_cokernels D]
--   [has_images D] [has_image_maps D]

-- @[simps]
-- def nat_iso.left_derived {F G : C ⥤ D} [F.additive] [G.additive] (α : F ≅ G) (n : ℕ) :
--   F.left_derived n ≅ G.left_derived n :=
-- { hom := α.hom.left_derived n,
--   inv := α.inv.left_derived n,
--   hom_inv_id' := by rw [←nat_trans.left_derived_comp, iso.hom_inv_id, nat_trans.left_derived_id],
--   inv_hom_id' := by rw [←nat_trans.left_derived_comp, iso.inv_hom_id, nat_trans.left_derived_id], }

-- end

-- section

-- variables {C : Type*} [category C]
--   [monoidal_category C] [symmetric_category C] [preadditive C]
--   [monoidal_preadditive C]
--   [has_zero_object C] [has_equalizers C] [has_cokernels C] [has_images C] [has_image_maps C]
--   [has_projective_resolutions C]

-- /--

-- `(Tor C n).obj X` is left deriving the functor `X ⊗ -`, i.e. `((Tor C n).obj X).obj Y` is
-- - take a projective resolution of `P_* → Y` and apply `X ⊗ -` to yield
-- ```
-- X ⊗ P_n → X ⊗ P_{n-1} → ⋯
-- ```
-- and calculate homology
-- -/
-- def Tor.is_balanced (n : ℕ) (X Y) : ((Tor C n).obj X).obj Y ⟶ ((Tor' C n).obj Y).obj X :=
-- show ((monoidal_category.tensor_left X).left_derived n).obj Y ⟶
--   ((monoidal_category.tensor_right X).left_derived n).obj Y,
-- from
-- (nat_trans.left_derived
-- ({ app := λ Y, (β_ X Y).hom,
--   naturality' := λ Y Y' f, by simp } :
--   monoidal_category.tensor_left X ⟶ monoidal_category.tensor_right X) n).app Y

-- #check nat_iso.hom_app_is_iso

-- end

-- end category_theory


/-
Copyright (c) 2021 Justus Springer. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Justus Springer, Andrew Yang

! This file was ported from Lean 3 source module algebraic_geometry.ringed_space
! leanprover-community/mathlib commit d39590fc8728fbf6743249802486f8c91ffe07bc
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Algebra.Category.Ring.FilteredColimits
import Mathbin.AlgebraicGeometry.SheafedSpace
import Mathbin.Topology.Sheaves.Stalks
import Mathbin.Algebra.Category.Ring.Colimits
import Mathbin.Algebra.Category.Ring.Limits

/-!
# Ringed spaces

We introduce the category of ringed spaces, as an alias for `SheafedSpace CommRing`.

The facts collected in this file are typically stated for locally ringed spaces, but never actually
make use of the locality of stalks. See for instance <https://stacks.math.columbia.edu/tag/01HZ>.

-/

universe v

open CategoryTheory

open TopologicalSpace

open Opposite

open TopCat

open TopCat.Presheaf

namespace AlgebraicGeometry

/-- The type of Ringed spaces, as an abbreviation for `SheafedSpace CommRing`. -/
abbrev RingedSpace : Type _ :=
  SheafedSpace CommRingCat
#align algebraic_geometry.RingedSpace AlgebraicGeometry.RingedSpace

namespace RingedSpace

open SheafedSpace

variable (X : RingedSpace.{v})

/--
If the germ of a section `f` is a unit in the stalk at `x`, then `f` must be a unit on some small
neighborhood around `x`.
-/
theorem isUnit_res_of_isUnit_germ (U : Opens X) (f : X.Presheaf.obj (op U)) (x : U)
    (h : IsUnit (X.Presheaf.germ x f)) :
    ∃ (V : Opens X)(i : V ⟶ U)(hxV : x.1 ∈ V), IsUnit (X.Presheaf.map i.op f) :=
  by
  obtain ⟨g', heq⟩ := h.exists_right_inv
  obtain ⟨V, hxV, g, rfl⟩ := X.presheaf.germ_exist x.1 g'
  let W := U ⊓ V
  have hxW : x.1 ∈ W := ⟨x.2, hxV⟩
  erw [← X.presheaf.germ_res_apply (opens.inf_le_left U V) ⟨x.1, hxW⟩ f, ←
    X.presheaf.germ_res_apply (opens.inf_le_right U V) ⟨x.1, hxW⟩ g, ← RingHom.map_mul, ←
    RingHom.map_one (X.presheaf.germ (⟨x.1, hxW⟩ : W))] at heq
  obtain ⟨W', hxW', i₁, i₂, heq'⟩ := X.presheaf.germ_eq x.1 hxW hxW _ _ HEq
  use W', i₁ ≫ opens.inf_le_left U V, hxW'
  rw [RingHom.map_one, RingHom.map_mul, ← comp_apply, ← X.presheaf.map_comp, ← op_comp] at heq'
  exact isUnit_of_mul_eq_one _ _ heq'
#align algebraic_geometry.RingedSpace.is_unit_res_of_is_unit_germ AlgebraicGeometry.RingedSpace.isUnit_res_of_isUnit_germ

/-- If a section `f` is a unit in each stalk, `f` must be a unit. -/
theorem isUnit_of_isUnit_germ (U : Opens X) (f : X.Presheaf.obj (op U))
    (h : ∀ x : U, IsUnit (X.Presheaf.germ x f)) : IsUnit f :=
  by
  -- We pick a cover of `U` by open sets `V x`, such that `f` is a unit on each `V x`.
  choose V iVU m h_unit using fun x : U => X.is_unit_res_of_is_unit_germ U f x (h x)
  have hcover : U ≤ supᵢ V := by
    intro x hxU
    rw [opens.mem_supr]
    exact ⟨⟨x, hxU⟩, m ⟨x, hxU⟩⟩
  -- Let `g x` denote the inverse of `f` in `U x`.
  choose g hg using fun x : U => IsUnit.exists_right_inv (h_unit x)
  -- We claim that these local inverses glue together to a global inverse of `f`.
  obtain ⟨gl, gl_spec, -⟩ := X.sheaf.exists_unique_gluing' V U iVU hcover g _
  swap
  · intro x y
    apply section_ext X.sheaf (V x ⊓ V y)
    rintro ⟨z, hzVx, hzVy⟩
    rw [germ_res_apply, germ_res_apply]
    apply (IsUnit.mul_right_inj (h ⟨z, (iVU x).le hzVx⟩)).mp
    erw [← X.presheaf.germ_res_apply (iVU x) ⟨z, hzVx⟩ f, ← RingHom.map_mul,
      congr_arg (X.presheaf.germ (⟨z, hzVx⟩ : V x)) (hg x), germ_res_apply, ←
      X.presheaf.germ_res_apply (iVU y) ⟨z, hzVy⟩ f, ← RingHom.map_mul,
      congr_arg (X.presheaf.germ (⟨z, hzVy⟩ : V y)) (hg y), RingHom.map_one, RingHom.map_one]
  apply isUnit_of_mul_eq_one f gl
  apply X.sheaf.eq_of_locally_eq' V U iVU hcover
  intro i
  rw [RingHom.map_one, RingHom.map_mul, gl_spec]
  exact hg i
#align algebraic_geometry.RingedSpace.is_unit_of_is_unit_germ AlgebraicGeometry.RingedSpace.isUnit_of_isUnit_germ

/-- The basic open of a section `f` is the set of all points `x`, such that the germ of `f` at
`x` is a unit.
-/
def basicOpen {U : Opens X} (f : X.Presheaf.obj (op U)) : Opens X
    where
  carrier := coe '' { x : U | IsUnit (X.Presheaf.germ x f) }
  is_open' := by
    rw [isOpen_iff_forall_mem_open]
    rintro _ ⟨x, hx, rfl⟩
    obtain ⟨V, i, hxV, hf⟩ := X.is_unit_res_of_is_unit_germ U f x hx
    use V.1
    refine' ⟨_, V.2, hxV⟩
    intro y hy
    use (⟨y, i.le hy⟩ : U)
    rw [Set.mem_setOf_eq]
    constructor
    · convert RingHom.isUnit_map (X.presheaf.germ ⟨y, hy⟩) hf
      exact (X.presheaf.germ_res_apply i ⟨y, hy⟩ f).symm
    · rfl
#align algebraic_geometry.RingedSpace.basic_open AlgebraicGeometry.RingedSpace.basicOpen

@[simp]
theorem mem_basicOpen {U : Opens X} (f : X.Presheaf.obj (op U)) (x : U) :
    ↑x ∈ X.basicOpen f ↔ IsUnit (X.Presheaf.germ x f) :=
  by
  constructor
  · rintro ⟨x, hx, a⟩
    cases Subtype.eq a
    exact hx
  · intro h
    exact ⟨x, h, rfl⟩
#align algebraic_geometry.RingedSpace.mem_basic_open AlgebraicGeometry.RingedSpace.mem_basicOpen

@[simp]
theorem mem_top_basicOpen (f : X.Presheaf.obj (op ⊤)) (x : X) :
    x ∈ X.basicOpen f ↔ IsUnit (X.Presheaf.germ ⟨x, show x ∈ (⊤ : Opens X) by trivial⟩ f) :=
  mem_basicOpen X f ⟨x, _⟩
#align algebraic_geometry.RingedSpace.mem_top_basic_open AlgebraicGeometry.RingedSpace.mem_top_basicOpen

theorem basicOpen_le {U : Opens X} (f : X.Presheaf.obj (op U)) : X.basicOpen f ≤ U :=
  by
  rintro _ ⟨x, hx, rfl⟩
  exact x.2
#align algebraic_geometry.RingedSpace.basic_open_le AlgebraicGeometry.RingedSpace.basicOpen_le

/-- The restriction of a section `f` to the basic open of `f` is a unit. -/
theorem isUnit_res_basicOpen {U : Opens X} (f : X.Presheaf.obj (op U)) :
    IsUnit (X.Presheaf.map (@homOfLE (Opens X) _ _ _ (X.basicOpen_le f)).op f) :=
  by
  apply is_unit_of_is_unit_germ
  rintro ⟨_, ⟨x, hx, rfl⟩⟩
  convert hx
  rw [germ_res_apply]
  rfl
#align algebraic_geometry.RingedSpace.is_unit_res_basic_open AlgebraicGeometry.RingedSpace.isUnit_res_basicOpen

@[simp]
theorem basicOpen_res {U V : (Opens X)ᵒᵖ} (i : U ⟶ V) (f : X.Presheaf.obj U) :
    @basicOpen X (unop V) (X.Presheaf.map i f) = unop V ⊓ @basicOpen X (unop U) f :=
  by
  induction U using Opposite.rec
  induction V using Opposite.rec
  let g := i.unop; have : i = g.op := rfl; clear_value g; subst this
  ext; constructor
  · rintro ⟨x, hx : IsUnit _, rfl⟩
    rw [germ_res_apply] at hx
    exact ⟨x.2, g x, hx, rfl⟩
  · rintro ⟨hxV, x, hx, rfl⟩
    refine' ⟨⟨x, hxV⟩, (_ : IsUnit _), rfl⟩
    rwa [germ_res_apply]
#align algebraic_geometry.RingedSpace.basic_open_res AlgebraicGeometry.RingedSpace.basicOpen_res

-- This should fire before `basic_open_res`.
@[simp]
theorem basicOpen_res_eq {U V : (Opens X)ᵒᵖ} (i : U ⟶ V) [IsIso i] (f : X.Presheaf.obj U) :
    @basicOpen X (unop V) (X.Presheaf.map i f) = @RingedSpace.basicOpen X (unop U) f :=
  by
  apply le_antisymm
  · rw [X.basic_open_res i f]
    exact inf_le_right
  · have := X.basic_open_res (inv i) (X.presheaf.map i f)
    rw [← comp_apply, ← X.presheaf.map_comp, is_iso.hom_inv_id, X.presheaf.map_id] at this
    erw [this]
    exact inf_le_right
#align algebraic_geometry.RingedSpace.basic_open_res_eq AlgebraicGeometry.RingedSpace.basicOpen_res_eq

@[simp]
theorem basicOpen_mul {U : Opens X} (f g : X.Presheaf.obj (op U)) :
    X.basicOpen (f * g) = X.basicOpen f ⊓ X.basicOpen g :=
  by
  ext1
  dsimp [RingedSpace.basic_open]
  rw [← Set.image_inter Subtype.coe_injective]
  congr
  ext
  simp_rw [map_mul]
  exact IsUnit.mul_iff
#align algebraic_geometry.RingedSpace.basic_open_mul AlgebraicGeometry.RingedSpace.basicOpen_mul

theorem basicOpen_of_isUnit {U : Opens X} {f : X.Presheaf.obj (op U)} (hf : IsUnit f) :
    X.basicOpen f = U := by
  apply le_antisymm
  · exact X.basic_open_le f
  intro x hx
  erw [X.mem_basic_open f (⟨x, hx⟩ : U)]
  exact RingHom.isUnit_map _ hf
#align algebraic_geometry.RingedSpace.basic_open_of_is_unit AlgebraicGeometry.RingedSpace.basicOpen_of_isUnit

end RingedSpace

end AlgebraicGeometry


/-
Copyright (c) 2018 Scott Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Scott Morrison
-/
import category_theory.concrete_category.bundled_hom
import category_theory.concrete_category.reflects_isomorphisms
import algebra.punit_instances
import tactic.elementwise

/-!
# Category instances for monoid, add_monoid, comm_monoid, and add_comm_monoid.

We introduce the bundled categories:
* `Mon`
* `AddMon`
* `CommMon`
* `AddCommMon`
along with the relevant forgetful functors between them.
-/

universes u v

open category_theory

/-- The category of monoids and monoid morphisms. -/
@[to_additive AddMon]
def Mon : Type (u+1) := bundled monoid

/-- The category of additive monoids and monoid morphisms. -/
add_decl_doc AddMon

namespace Mon

/-- `monoid_hom` doesn't actually assume associativity. This alias is needed to make the category
theory machinery work. -/
@[to_additive "`add_monoid_hom` doesn't actually assume associativity. This alias is needed to make
the category theory machinery work."]
abbreviation assoc_monoid_hom (M N : Type*) [monoid M] [monoid N] := monoid_hom M N

@[to_additive]
instance bundled_hom : bundled_hom assoc_monoid_hom :=
⟨λ M N [monoid M] [monoid N], by exactI @monoid_hom.to_fun M N _ _,
 λ M [monoid M], by exactI @monoid_hom.id M _,
 λ M N P [monoid M] [monoid N] [monoid P], by exactI @monoid_hom.comp M N P _ _ _,
 λ M N [monoid M] [monoid N], by exactI @monoid_hom.coe_inj M N _ _⟩

attribute [derive [has_coe_to_sort, large_category, concrete_category]] Mon AddMon

/-- Construct a bundled `Mon` from the underlying type and typeclass. -/
@[to_additive]
def of (M : Type u) [monoid M] : Mon := bundled.of M

/-- Construct a bundled `Mon` from the underlying type and typeclass. -/
add_decl_doc AddMon.of

@[to_additive]
instance : inhabited Mon :=
-- The default instance for `monoid punit` is derived via `punit.comm_ring`,
-- which breaks to_additive.
⟨@of punit $ @group.to_monoid _ $ @comm_group.to_group _ punit.comm_group⟩

@[to_additive]
instance (M : Mon) : monoid M := M.str

@[simp, to_additive] lemma coe_of (R : Type u) [monoid R] : (Mon.of R : Type u) = R := rfl

end Mon

/-- The category of commutative monoids and monoid morphisms. -/
@[to_additive AddCommMon]
def CommMon : Type (u+1) := bundled comm_monoid

/-- The category of additive commutative monoids and monoid morphisms. -/
add_decl_doc AddCommMon

namespace CommMon

@[to_additive]
instance : bundled_hom.parent_projection comm_monoid.to_monoid := ⟨⟩

attribute [derive [has_coe_to_sort, large_category, concrete_category]] CommMon AddCommMon

/-- Construct a bundled `CommMon` from the underlying type and typeclass. -/
@[to_additive]
def of (M : Type u) [comm_monoid M] : CommMon := bundled.of M

/-- Construct a bundled `AddCommMon` from the underlying type and typeclass. -/
add_decl_doc AddCommMon.of

@[to_additive]
instance : inhabited CommMon :=
-- The default instance for `comm_monoid punit` is derived via `punit.comm_ring`,
-- which breaks to_additive.
⟨@of punit $ @comm_group.to_comm_monoid _ punit.comm_group⟩

@[to_additive]
instance (M : CommMon) : comm_monoid M := M.str

@[simp, to_additive] lemma coe_of (R : Type u) [comm_monoid R] : (CommMon.of R : Type u) = R := rfl

@[to_additive has_forget_to_AddMon]
instance has_forget_to_Mon : has_forget₂ CommMon Mon := bundled_hom.forget₂ _ _

end CommMon

-- We verify that the coercions of morphisms to functions work correctly:
example {R S : Mon}     (f : R ⟶ S) : (R : Type) → (S : Type) := f
example {R S : CommMon} (f : R ⟶ S) : (R : Type) → (S : Type) := f

-- We verify that when constructing a morphism in `CommMon`,
-- when we construct the `to_fun` field, the types are presented as `↥R`,
-- rather than `R.α` or (as we used to have) `↥(bundled.map comm_monoid.to_monoid R)`.
example (R : CommMon.{u}) : R ⟶ R :=
{ to_fun := λ x,
  begin
    match_target (R : Type u),
    match_hyp x : (R : Type u),
    exact x * x
  end ,
  map_one' := by simp,
  map_mul' := λ x y,
  begin rw [mul_assoc x y (x * y), ←mul_assoc y x y, mul_comm y x, mul_assoc, mul_assoc], end, }

variables {X Y : Type u}

section
variables [monoid X] [monoid Y]

/-- Build an isomorphism in the category `Mon` from a `mul_equiv` between `monoid`s. -/
@[to_additive add_equiv.to_AddMon_iso "Build an isomorphism in the category `AddMon` from
an `add_equiv` between `add_monoid`s.", simps]
def mul_equiv.to_Mon_iso (e : X ≃* Y) : Mon.of X ≅ Mon.of Y :=
{ hom := e.to_monoid_hom,
  inv := e.symm.to_monoid_hom }

end

section
variables [comm_monoid X] [comm_monoid Y]

/-- Build an isomorphism in the category `CommMon` from a `mul_equiv` between `comm_monoid`s. -/
@[to_additive add_equiv.to_AddCommMon_iso "Build an isomorphism in the category `AddCommMon`
from an `add_equiv` between `add_comm_monoid`s.", simps]
def mul_equiv.to_CommMon_iso (e : X ≃* Y) : CommMon.of X ≅ CommMon.of Y :=
{ hom := e.to_monoid_hom,
  inv := e.symm.to_monoid_hom }

end

namespace category_theory.iso

/-- Build a `mul_equiv` from an isomorphism in the category `Mon`. -/
@[to_additive AddMon_iso_to_add_equiv "Build an `add_equiv` from an isomorphism in the category
`AddMon`."]
def Mon_iso_to_mul_equiv {X Y : Mon} (i : X ≅ Y) : X ≃* Y :=
i.hom.to_mul_equiv i.inv i.hom_inv_id i.inv_hom_id

/-- Build a `mul_equiv` from an isomorphism in the category `CommMon`. -/
@[to_additive "Build an `add_equiv` from an isomorphism in the category
`AddCommMon`."]
def CommMon_iso_to_mul_equiv {X Y : CommMon} (i : X ≅ Y) : X ≃* Y :=
i.hom.to_mul_equiv i.inv i.hom_inv_id i.inv_hom_id

end category_theory.iso

/-- multiplicative equivalences between `monoid`s are the same as (isomorphic to) isomorphisms
in `Mon` -/
@[to_additive add_equiv_iso_AddMon_iso "additive equivalences between `add_monoid`s are the same
as (isomorphic to) isomorphisms in `AddMon`"]
def mul_equiv_iso_Mon_iso {X Y : Type u} [monoid X] [monoid Y] :
  (X ≃* Y) ≅ (Mon.of X ≅ Mon.of Y) :=
{ hom := λ e, e.to_Mon_iso,
  inv := λ i, i.Mon_iso_to_mul_equiv, }

/-- multiplicative equivalences between `comm_monoid`s are the same as (isomorphic to) isomorphisms
in `CommMon` -/
@[to_additive add_equiv_iso_AddCommMon_iso "additive equivalences between `add_comm_monoid`s are
the same as (isomorphic to) isomorphisms in `AddCommMon`"]
def mul_equiv_iso_CommMon_iso {X Y : Type u} [comm_monoid X] [comm_monoid Y] :
  (X ≃* Y) ≅ (CommMon.of X ≅ CommMon.of Y) :=
{ hom := λ e, e.to_CommMon_iso,
  inv := λ i, i.CommMon_iso_to_mul_equiv, }

@[to_additive]
instance Mon.forget_reflects_isos : reflects_isomorphisms (forget Mon.{u}) :=
{ reflects := λ X Y f _,
  begin
    resetI,
    let i := as_iso ((forget Mon).map f),
    let e : X ≃* Y := { ..f, ..i.to_equiv },
    exact ⟨(is_iso.of_iso e.to_Mon_iso).1⟩,
  end }

@[to_additive]
instance CommMon.forget_reflects_isos : reflects_isomorphisms (forget CommMon.{u}) :=
{ reflects := λ X Y f _,
  begin
    resetI,
    let i := as_iso ((forget CommMon).map f),
    let e : X ≃* Y := { ..f, ..i.to_equiv },
    exact ⟨(is_iso.of_iso e.to_CommMon_iso).1⟩,
  end }

/-!
Once we've shown that the forgetful functors to type reflect isomorphisms,
we automatically obtain that the `forget₂` functors between our concrete categories
reflect isomorphisms.
-/
example : reflects_isomorphisms (forget₂ CommMon Mon) := by apply_instance


/-
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.preadditive.additive_functor
import category_theory.monoidal.category

/-!
# Preadditive monoidal categories

A monoidal category is `monoidal_preadditive` if it is preadditive and tensor product of morphisms
is linear in both factors.
-/

noncomputable theory

namespace category_theory

open category_theory.limits
open category_theory.monoidal_category

variables (C : Type*) [category C] [preadditive C] [monoidal_category C]

/--
A category is `monoidal_preadditive` if tensoring is additive in both factors.

Note we don't `extend preadditive C` here, as `abelian C` already extends it,
and we'll need to have both typeclasses sometimes.
-/
class monoidal_preadditive :=
(tensor_zero' : ∀ {W X Y Z : C} (f : W ⟶ X), f ⊗ (0 : Y ⟶ Z) = 0 . obviously)
(zero_tensor' : ∀ {W X Y Z : C} (f : Y ⟶ Z), (0 : W ⟶ X) ⊗ f = 0 . obviously)
(tensor_add' : ∀ {W X Y Z : C} (f : W ⟶ X) (g h : Y ⟶ Z), f ⊗ (g + h) = f ⊗ g + f ⊗ h . obviously)
(add_tensor' : ∀ {W X Y Z : C} (f g : W ⟶ X) (h : Y ⟶ Z), (f + g) ⊗ h = f ⊗ h + g ⊗ h . obviously)

restate_axiom monoidal_preadditive.tensor_zero'
restate_axiom monoidal_preadditive.zero_tensor'
restate_axiom monoidal_preadditive.tensor_add'
restate_axiom monoidal_preadditive.add_tensor'
attribute [simp] monoidal_preadditive.tensor_zero monoidal_preadditive.zero_tensor

variables [monoidal_preadditive C]

local attribute [simp] monoidal_preadditive.tensor_add monoidal_preadditive.add_tensor

instance tensor_left_additive (X : C) : (tensor_left X).additive := {}
instance tensor_right_additive (X : C) : (tensor_right X).additive := {}
instance tensoring_left_additive (X : C) : ((tensoring_left C).obj X).additive := {}
instance tensoring_right_additive (X : C) : ((tensoring_right C).obj X).additive := {}

open_locale big_operators

lemma tensor_sum {P Q R S : C} {J : Type*} (s : finset J) (f : P ⟶ Q) (g : J → (R ⟶ S)) :
  f ⊗ ∑ j in s, g j = ∑ j in s, f ⊗ g j :=
begin
  rw ←tensor_id_comp_id_tensor,
  let tQ := (((tensoring_left C).obj Q).map_add_hom : (R ⟶ S) →+ _),
  change _ ≫ tQ _ = _,
  rw [tQ.map_sum, preadditive.comp_sum],
  dsimp [tQ],
  simp only [tensor_id_comp_id_tensor],
end

lemma sum_tensor {P Q R S : C} {J : Type*} (s : finset J) (f : P ⟶ Q) (g : J → (R ⟶ S)) :
  (∑ j in s, g j) ⊗ f = ∑ j in s, g j ⊗ f :=
begin
  rw ←tensor_id_comp_id_tensor,
  let tQ := (((tensoring_right C).obj P).map_add_hom : (R ⟶ S) →+ _),
  change tQ _ ≫ _ = _,
  rw [tQ.map_sum, preadditive.sum_comp],
  dsimp [tQ],
  simp only [tensor_id_comp_id_tensor],
end

variables {C}

-- In a closed monoidal category, this would hold because
-- `tensor_left X` is a left adjoint and hence preserves all colimits.
-- In any case it is true in any preadditive category.
instance (X : C) : preserves_finite_biproducts (tensor_left X) :=
{ preserves := λ J _ _, by exactI
  { preserves := λ f,
    { preserves := λ b i, is_bilimit_of_total _ begin
      dsimp,
      simp only [←tensor_comp, category.comp_id, ←tensor_sum, ←tensor_id, is_bilimit.total i],
    end } } }

instance (X : C) : preserves_finite_biproducts (tensor_right X) :=
{ preserves := λ J _ _, by exactI
  { preserves := λ f,
    { preserves := λ b i, is_bilimit_of_total _ begin
      dsimp,
      simp only [←tensor_comp, category.comp_id, ←sum_tensor, ←tensor_id, is_bilimit.total i],
    end } } }

variables [has_finite_biproducts C]

/-- The isomorphism showing how tensor product on the left distributes over direct sums. -/
def left_distributor {J : Type*} [decidable_eq J] [fintype J] (X : C) (f : J → C) :
  X ⊗ (⨁ f) ≅ ⨁ (λ j, X ⊗ f j) :=
(tensor_left X).map_biproduct f

@[simp]
lemma left_distributor_hom {J : Type*} [decidable_eq J] [fintype J] (X : C) (f : J → C) :
  (left_distributor X f).hom = ∑ j : J, (𝟙 X ⊗ biproduct.π f j) ≫ biproduct.ι _ j :=
begin
  ext, dsimp [tensor_left, left_distributor],
  simp [preadditive.sum_comp, biproduct.ι_π, comp_dite],
end

@[simp]
lemma left_distributor_inv {J : Type*} [decidable_eq J] [fintype J] (X : C) (f : J → C) :
  (left_distributor X f).inv = ∑ j : J, biproduct.π _ j ≫ (𝟙 X ⊗ biproduct.ι f j) :=
begin
  ext, dsimp [tensor_left, left_distributor],
  simp [preadditive.comp_sum, biproduct.ι_π_assoc, dite_comp],
end

lemma left_distributor_assoc {J : Type*} [decidable_eq J] [fintype J] (X Y : C) (f : J → C) :
   (as_iso (𝟙 X) ⊗ left_distributor Y f) ≪≫ left_distributor X _ =
     (α_ X Y (⨁ f)).symm ≪≫ left_distributor (X ⊗ Y) f ≪≫ biproduct.map_iso (λ j, α_ X Y _) :=
begin
  ext,
  simp only [category.comp_id,  category.assoc, eq_to_hom_refl,
    iso.trans_hom, iso.symm_hom, as_iso_hom, comp_zero, comp_dite,
    preadditive.sum_comp, preadditive.comp_sum,
    tensor_sum, id_tensor_comp, tensor_iso_hom, left_distributor_hom,
    biproduct.map_iso_hom, biproduct.ι_map, biproduct.ι_π,
    finset.sum_dite_irrel, finset.sum_dite_eq', finset.sum_const_zero],
  simp only [←id_tensor_comp, biproduct.ι_π],
  simp only [id_tensor_comp, tensor_dite, comp_dite],
  simp only [category.comp_id, comp_zero, monoidal_preadditive.tensor_zero, eq_to_hom_refl,
    tensor_id, if_true, dif_ctx_congr, finset.sum_congr, finset.mem_univ, finset.sum_dite_eq'],
  simp only [←tensor_id, associator_naturality, iso.inv_hom_id_assoc],
end

/-- The isomorphism showing how tensor product on the right distributes over direct sums. -/
def right_distributor {J : Type*} [decidable_eq J] [fintype J] (X : C) (f : J → C) :
  (⨁ f) ⊗ X ≅ ⨁ (λ j, f j ⊗ X)  :=
(tensor_right X).map_biproduct f

@[simp]
lemma right_distributor_hom {J : Type*} [decidable_eq J] [fintype J] (X : C) (f : J → C) :
  (right_distributor X f).hom = ∑ j : J, (biproduct.π f j ⊗ 𝟙 X) ≫ biproduct.ι _ j :=
begin
  ext, dsimp [tensor_right, right_distributor],
  simp [preadditive.sum_comp, biproduct.ι_π, comp_dite],
end

@[simp]
lemma right_distributor_inv {J : Type*} [decidable_eq J] [fintype J] (X : C) (f : J → C) :
  (right_distributor X f).inv = ∑ j : J, biproduct.π _ j ≫ (biproduct.ι f j ⊗ 𝟙 X) :=
begin
  ext, dsimp [tensor_right, right_distributor],
  simp [preadditive.comp_sum, biproduct.ι_π_assoc, dite_comp],
end

lemma right_distributor_assoc {J : Type*} [decidable_eq J] [fintype J] (X Y : C) (f : J → C) :
   (right_distributor X f ⊗ as_iso (𝟙 Y)) ≪≫ right_distributor Y _ =
     α_ (⨁ f) X Y ≪≫ right_distributor (X ⊗ Y) f ≪≫ biproduct.map_iso (λ j, (α_ _ X Y).symm) :=
begin
  ext,
  simp only [category.comp_id, category.assoc, eq_to_hom_refl, iso.symm_hom,
    iso.trans_hom, as_iso_hom, comp_zero, comp_dite, preadditive.sum_comp, preadditive.comp_sum,
    sum_tensor, comp_tensor_id, tensor_iso_hom, right_distributor_hom,
    biproduct.map_iso_hom, biproduct.ι_map, biproduct.ι_π,
    finset.sum_dite_irrel, finset.sum_dite_eq', finset.sum_const_zero, finset.mem_univ, if_true],
  simp only [←comp_tensor_id, biproduct.ι_π, dite_tensor, comp_dite],
  simp only [category.comp_id, comp_tensor_id, eq_to_hom_refl, tensor_id, comp_zero,
    monoidal_preadditive.zero_tensor,
    if_true, dif_ctx_congr, finset.mem_univ, finset.sum_congr, finset.sum_dite_eq'],
  simp only [←tensor_id, associator_inv_naturality, iso.hom_inv_id_assoc]
end

lemma left_distributor_right_distributor_assoc
  {J : Type*} [decidable_eq J] [fintype J] (X Y : C) (f : J → C) :
  (left_distributor X f ⊗ as_iso (𝟙 Y)) ≪≫ right_distributor Y _ =
    α_ X (⨁ f) Y ≪≫ (as_iso (𝟙 X) ⊗ right_distributor Y _) ≪≫ left_distributor X _ ≪≫
      biproduct.map_iso (λ j, (α_ _ _ _).symm) :=
begin
  ext,
  simp only [category.comp_id, category.assoc, eq_to_hom_refl, iso.symm_hom,
    iso.trans_hom, as_iso_hom, comp_zero, comp_dite, preadditive.sum_comp, preadditive.comp_sum,
    sum_tensor, tensor_sum, comp_tensor_id, tensor_iso_hom,
    left_distributor_hom, right_distributor_hom,
    biproduct.map_iso_hom, biproduct.ι_map, biproduct.ι_π,
    finset.sum_dite_irrel, finset.sum_dite_eq', finset.sum_const_zero, finset.mem_univ, if_true],
  simp only [←comp_tensor_id, ←id_tensor_comp_assoc, category.assoc, biproduct.ι_π,
    comp_dite, dite_comp, tensor_dite, dite_tensor],
  simp only [category.comp_id, category.id_comp, category.assoc, id_tensor_comp,
    comp_zero, zero_comp, monoidal_preadditive.tensor_zero, monoidal_preadditive.zero_tensor,
    comp_tensor_id, eq_to_hom_refl, tensor_id,
    if_true, dif_ctx_congr, finset.sum_congr, finset.mem_univ, finset.sum_dite_eq'],
  simp only [associator_inv_naturality, iso.hom_inv_id_assoc]
end

end category_theory


--

structure S  :=
(g {α} : α → α)

def f (h : Nat → ({α : Type} → α → α) × Bool) : Nat :=
(h 0).1 1

def tst : Nat :=
f fun n => (fun x => x, true)

theorem ex : id (Nat → Nat) :=
by {
  intro;
  assumption
}

def g (i j k : Nat) (a : Array Nat) (h₁ : i < k) (h₂ : k < j) (h₃ : j < a.size) : Nat :=
  let vj := a.get ⟨j, h₃⟩;
  let vi := a.get ⟨i, Nat.ltTrans h₁ (Nat.ltTrans h₂ h₃)⟩;
  vi + vj

set_option pp.all true in
#print g

#check g.proof_1

theorem ex1 {p q r s : Prop} : p ∧ q ∧ r ∧ s → r ∧ s ∧ q ∧ p :=
  fun ⟨hp, hq, hr, hs⟩ => ⟨hr, hs, hq, hp⟩

theorem ex2 {p q r s : Prop} : p ∧ q ∧ r ∧ s → r ∧ s ∧ q ∧ p := by
  intro ⟨hp, hq, hr, hs⟩
  exact ⟨hr, hs, hq, hp⟩


/-
Copyright (c) 2019 Zhouhang Zhou. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Zhouhang Zhou
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.measure_theory.ae_eq_fun
import Mathlib.PostPort

universes u_1 u_2 u_3 u_5 u_4 u_6

namespace Mathlib

/-!
# Integrable functions and `L¹` space

In the first part of this file, the predicate `integrable` is defined and basic properties of
integrable functions are proved.

In the second part, the space `L¹` of equivalence classes of integrable functions under the relation
of being almost everywhere equal is defined as a subspace of the space `L⁰`. See the file
`src/measure_theory/ae_eq_fun.lean` for information on `L⁰` space.

## Notation

* `α →₁ β` is the type of `L¹` space, where `α` is a `measure_space` and `β` is a `normed_group`
  with a `second_countable_topology`. `f : α →ₘ β` is a "function" in `L¹`. In comments, `[f]` is
  also used to denote an `L¹` function.

  `₁` can be typed as `\1`.

## Main definitions

* Let `f : α → β` be a function, where `α` is a `measure_space` and `β` a `normed_group`.
  Then `has_finite_integral f` means `(∫⁻ a, nnnorm (f a)) < ⊤`.

* If `β` is moreover a `measurable_space` then `f` is called `integrable` if
  `f` is `measurable` and `has_finite_integral f` holds.

* The space `L¹` is defined as a subspace of `L⁰` :
  An `ae_eq_fun` `[f] : α →ₘ β` is in the space `L¹` if `edist [f] 0 < ⊤`, which means
  `(∫⁻ a, edist (f a) 0) < ⊤` if we expand the definition of `edist` in `L⁰`.

## Main statements

`L¹`, as a subspace, inherits most of the structures of `L⁰`.

## Implementation notes

Maybe `integrable f` should be mean `(∫⁻ a, edist (f a) 0) < ⊤`, so that `integrable` and
`ae_eq_fun.integrable` are more aligned. But in the end one can use the lemma
`lintegral_nnnorm_eq_lintegral_edist : (∫⁻ a, nnnorm (f a)) = (∫⁻ a, edist (f a) 0)` to switch the
two forms.

To prove something for an arbitrary integrable function, a useful theorem is
`integrable.induction` in the file `set_integral`.

## Tags

integrable, function space, l1

-/

namespace measure_theory

/-! ### Some results about the Lebesgue integral involving a normed group -/

theorem lintegral_nnnorm_eq_lintegral_edist {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] (f : α → β) : (lintegral μ fun (a : α) => ↑(nnnorm (f a))) = lintegral μ fun (a : α) => edist (f a) 0 := sorry

theorem lintegral_norm_eq_lintegral_edist {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] (f : α → β) : (lintegral μ fun (a : α) => ennreal.of_real (norm (f a))) = lintegral μ fun (a : α) => edist (f a) 0 := sorry

theorem lintegral_edist_triangle {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [topological_space.second_countable_topology β] [measurable_space β] [opens_measurable_space β] {f : α → β} {g : α → β} {h : α → β} (hf : ae_measurable f) (hg : ae_measurable g) (hh : ae_measurable h) : (lintegral μ fun (a : α) => edist (f a) (g a)) ≤
  (lintegral μ fun (a : α) => edist (f a) (h a)) + lintegral μ fun (a : α) => edist (g a) (h a) := sorry

theorem lintegral_nnnorm_zero {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] : (lintegral μ fun (a : α) => ↑(nnnorm 0)) = 0 := sorry

theorem lintegral_nnnorm_add {α : Type u_1} {β : Type u_2} {γ : Type u_3} [measurable_space α] {μ : measure α} [normed_group β] [normed_group γ] [measurable_space β] [opens_measurable_space β] [measurable_space γ] [opens_measurable_space γ] {f : α → β} {g : α → γ} (hf : ae_measurable f) (hg : ae_measurable g) : (lintegral μ fun (a : α) => ↑(nnnorm (f a)) + ↑(nnnorm (g a))) =
  (lintegral μ fun (a : α) => ↑(nnnorm (f a))) + lintegral μ fun (a : α) => ↑(nnnorm (g a)) :=
  lintegral_add' (ae_measurable.ennnorm hf) (ae_measurable.ennnorm hg)

theorem lintegral_nnnorm_neg {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] {f : α → β} : (lintegral μ fun (a : α) => ↑(nnnorm (Neg.neg f a))) = lintegral μ fun (a : α) => ↑(nnnorm (f a)) := sorry

/-! ### The predicate `has_finite_integral` -/

/-- `has_finite_integral f μ` means that the integral `∫⁻ a, ∥f a∥ ∂μ` is finite.
  `has_finite_integral f` means `has_finite_integral f volume`. -/
def has_finite_integral {α : Type u_1} {β : Type u_2} [measurable_space α] [normed_group β] (f : α → β) (μ : autoParam (measure α)
  (Lean.Syntax.ident Lean.SourceInfo.none (String.toSubstring "Mathlib.measure_theory.volume_tac")
    (Lean.Name.mkStr (Lean.Name.mkStr (Lean.Name.mkStr Lean.Name.anonymous "Mathlib") "measure_theory") "volume_tac")
    [])) :=
  (lintegral μ fun (a : α) => ↑(nnnorm (f a))) < ⊤

theorem has_finite_integral_iff_norm {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] (f : α → β) : has_finite_integral f ↔ (lintegral μ fun (a : α) => ennreal.of_real (norm (f a))) < ⊤ := sorry

theorem has_finite_integral_iff_edist {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] (f : α → β) : has_finite_integral f ↔ (lintegral μ fun (a : α) => edist (f a) 0) < ⊤ := sorry

theorem has_finite_integral_iff_of_real {α : Type u_1} [measurable_space α] {μ : measure α} {f : α → ℝ} (h : filter.eventually_le (measure.ae μ) 0 f) : has_finite_integral f ↔ (lintegral μ fun (a : α) => ennreal.of_real (f a)) < ⊤ := sorry

theorem has_finite_integral.mono {α : Type u_1} {β : Type u_2} {γ : Type u_3} [measurable_space α] {μ : measure α} [normed_group β] [normed_group γ] {f : α → β} {g : α → γ} (hg : has_finite_integral g) (h : filter.eventually (fun (a : α) => norm (f a) ≤ norm (g a)) (measure.ae μ)) : has_finite_integral f := sorry

theorem has_finite_integral.mono' {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] {f : α → β} {g : α → ℝ} (hg : has_finite_integral g) (h : filter.eventually (fun (a : α) => norm (f a) ≤ g a) (measure.ae μ)) : has_finite_integral f :=
  has_finite_integral.mono hg
    (filter.eventually.mono h fun (x : α) (hx : norm (f x) ≤ g x) => le_trans hx (le_abs_self (g x)))

theorem has_finite_integral.congr' {α : Type u_1} {β : Type u_2} {γ : Type u_3} [measurable_space α] {μ : measure α} [normed_group β] [normed_group γ] {f : α → β} {g : α → γ} (hf : has_finite_integral f) (h : filter.eventually (fun (a : α) => norm (f a) = norm (g a)) (measure.ae μ)) : has_finite_integral g :=
  has_finite_integral.mono hf (filter.eventually_eq.le (filter.eventually_eq.symm h))

theorem has_finite_integral_congr' {α : Type u_1} {β : Type u_2} {γ : Type u_3} [measurable_space α] {μ : measure α} [normed_group β] [normed_group γ] {f : α → β} {g : α → γ} (h : filter.eventually (fun (a : α) => norm (f a) = norm (g a)) (measure.ae μ)) : has_finite_integral f ↔ has_finite_integral g :=
  { mp := fun (hf : has_finite_integral f) => has_finite_integral.congr' hf h,
    mpr := fun (hg : has_finite_integral g) => has_finite_integral.congr' hg (filter.eventually_eq.symm h) }

theorem has_finite_integral.congr {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] {f : α → β} {g : α → β} (hf : has_finite_integral f) (h : filter.eventually_eq (measure.ae μ) f g) : has_finite_integral g :=
  has_finite_integral.congr' hf (filter.eventually_eq.fun_comp h norm)

theorem has_finite_integral_congr {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] {f : α → β} {g : α → β} (h : filter.eventually_eq (measure.ae μ) f g) : has_finite_integral f ↔ has_finite_integral g :=
  has_finite_integral_congr' (filter.eventually_eq.fun_comp h norm)

theorem has_finite_integral_const_iff {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] {c : β} : (has_finite_integral fun (x : α) => c) ↔ c = 0 ∨ coe_fn μ set.univ < ⊤ := sorry

theorem has_finite_integral_const {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [finite_measure μ] (c : β) : has_finite_integral fun (x : α) => c :=
  iff.mpr has_finite_integral_const_iff (Or.inr (measure_lt_top μ set.univ))

theorem has_finite_integral_of_bounded {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [finite_measure μ] {f : α → β} {C : ℝ} (hC : filter.eventually (fun (a : α) => norm (f a) ≤ C) (measure.ae μ)) : has_finite_integral f :=
  has_finite_integral.mono' (has_finite_integral_const C) hC

theorem has_finite_integral.mono_measure {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} {ν : measure α} [normed_group β] {f : α → β} (h : has_finite_integral f) (hμ : μ ≤ ν) : has_finite_integral f :=
  lt_of_le_of_lt (lintegral_mono' hμ (le_refl fun (a : α) => ↑(nnnorm (f a)))) h

theorem has_finite_integral.add_measure {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} {ν : measure α} [normed_group β] {f : α → β} (hμ : has_finite_integral f) (hν : has_finite_integral f) : has_finite_integral f := sorry

theorem has_finite_integral.left_of_add_measure {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} {ν : measure α} [normed_group β] {f : α → β} (h : has_finite_integral f) : has_finite_integral f :=
  has_finite_integral.mono_measure h (measure.le_add_right (le_refl μ))

theorem has_finite_integral.right_of_add_measure {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} {ν : measure α} [normed_group β] {f : α → β} (h : has_finite_integral f) : has_finite_integral f :=
  has_finite_integral.mono_measure h (measure.le_add_left (le_refl ν))

@[simp] theorem has_finite_integral_add_measure {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} {ν : measure α} [normed_group β] {f : α → β} : has_finite_integral f ↔ has_finite_integral f ∧ has_finite_integral f := sorry

theorem has_finite_integral.smul_measure {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] {f : α → β} (h : has_finite_integral f) {c : ennreal} (hc : c < ⊤) : has_finite_integral f := sorry

@[simp] theorem has_finite_integral_zero_measure {α : Type u_1} {β : Type u_2} [measurable_space α] [normed_group β] (f : α → β) : has_finite_integral f := sorry

@[simp] theorem has_finite_integral_zero (α : Type u_1) (β : Type u_2) [measurable_space α] (μ : measure α) [normed_group β] : has_finite_integral fun (a : α) => 0 := sorry

theorem has_finite_integral.neg {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] {f : α → β} (hfi : has_finite_integral f) : has_finite_integral (-f) := sorry

@[simp] theorem has_finite_integral_neg_iff {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] {f : α → β} : has_finite_integral (-f) ↔ has_finite_integral f :=
  { mp := fun (h : has_finite_integral (-f)) => neg_neg f ▸ has_finite_integral.neg h, mpr := has_finite_integral.neg }

theorem has_finite_integral.norm {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] {f : α → β} (hfi : has_finite_integral f) : has_finite_integral fun (a : α) => norm (f a) := sorry

theorem has_finite_integral_norm_iff {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] (f : α → β) : (has_finite_integral fun (a : α) => norm (f a)) ↔ has_finite_integral f :=
  has_finite_integral_congr' (filter.eventually_of_forall fun (x : α) => norm_norm (f x))

theorem all_ae_of_real_F_le_bound {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] {F : ℕ → α → β} {bound : α → ℝ} (h : ∀ (n : ℕ), filter.eventually (fun (a : α) => norm (F n a) ≤ bound a) (measure.ae μ)) (n : ℕ) : filter.eventually (fun (a : α) => ennreal.of_real (norm (F n a)) ≤ ennreal.of_real (bound a)) (measure.ae μ) :=
  filter.eventually.mono (h n) fun (a : α) (h : norm (F n a) ≤ bound a) => ennreal.of_real_le_of_real h

theorem all_ae_tendsto_of_real_norm {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] {F : ℕ → α → β} {f : α → β} (h : filter.eventually (fun (a : α) => filter.tendsto (fun (n : ℕ) => F n a) filter.at_top (nhds (f a))) (measure.ae μ)) : filter.eventually
  (fun (a : α) =>
    filter.tendsto (fun (n : ℕ) => ennreal.of_real (norm (F n a))) filter.at_top (nhds (ennreal.of_real (norm (f a)))))
  (measure.ae μ) :=
  filter.eventually.mono h
    fun (a : α) (h : filter.tendsto (fun (n : ℕ) => F n a) filter.at_top (nhds (f a))) =>
      ennreal.tendsto_of_real (filter.tendsto.comp (continuous.tendsto continuous_norm (f a)) h)

theorem all_ae_of_real_f_le_bound {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] {F : ℕ → α → β} {f : α → β} {bound : α → ℝ} (h_bound : ∀ (n : ℕ), filter.eventually (fun (a : α) => norm (F n a) ≤ bound a) (measure.ae μ)) (h_lim : filter.eventually (fun (a : α) => filter.tendsto (fun (n : ℕ) => F n a) filter.at_top (nhds (f a))) (measure.ae μ)) : filter.eventually (fun (a : α) => ennreal.of_real (norm (f a)) ≤ ennreal.of_real (bound a)) (measure.ae μ) := sorry

theorem has_finite_integral_of_dominated_convergence {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] {F : ℕ → α → β} {f : α → β} {bound : α → ℝ} (bound_has_finite_integral : has_finite_integral bound) (h_bound : ∀ (n : ℕ), filter.eventually (fun (a : α) => norm (F n a) ≤ bound a) (measure.ae μ)) (h_lim : filter.eventually (fun (a : α) => filter.tendsto (fun (n : ℕ) => F n a) filter.at_top (nhds (f a))) (measure.ae μ)) : has_finite_integral f := sorry

/- `∥F n a∥ ≤ bound a` and `∥F n a∥ --> ∥f a∥` implies `∥f a∥ ≤ bound a`,
  and so `∫ ∥f∥ ≤ ∫ bound < ⊤` since `bound` is has_finite_integral -/

theorem tendsto_lintegral_norm_of_dominated_convergence {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [borel_space β] [topological_space.second_countable_topology β] {F : ℕ → α → β} {f : α → β} {bound : α → ℝ} (F_measurable : ∀ (n : ℕ), ae_measurable (F n)) (f_measurable : ae_measurable f) (bound_has_finite_integral : has_finite_integral bound) (h_bound : ∀ (n : ℕ), filter.eventually (fun (a : α) => norm (F n a) ≤ bound a) (measure.ae μ)) (h_lim : filter.eventually (fun (a : α) => filter.tendsto (fun (n : ℕ) => F n a) filter.at_top (nhds (f a))) (measure.ae μ)) : filter.tendsto (fun (n : ℕ) => lintegral μ fun (a : α) => ennreal.of_real (norm (F n a - f a))) filter.at_top (nhds 0) := sorry

/- `∥F n a∥ ≤ bound a` and `F n a --> f a` implies `∥f a∥ ≤ bound a`, and thus by the
  triangle inequality, have `∥F n a - f a∥ ≤ 2 * (bound a). -/

/- On the other hand, `F n a --> f a` implies that `∥F n a - f a∥ --> 0`  -/

/- Therefore, by the dominated convergence theorem for nonnegative integration, have
  ` ∫ ∥f a - F n a∥ --> 0 ` -/

/-! Lemmas used for defining the positive part of a `L¹` function -/

theorem has_finite_integral.max_zero {α : Type u_1} [measurable_space α] {μ : measure α} {f : α → ℝ} (hf : has_finite_integral f) : has_finite_integral fun (a : α) => max (f a) 0 := sorry

theorem has_finite_integral.min_zero {α : Type u_1} [measurable_space α] {μ : measure α} {f : α → ℝ} (hf : has_finite_integral f) : has_finite_integral fun (a : α) => min (f a) 0 := sorry

theorem has_finite_integral.smul {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] {𝕜 : Type u_5} [normed_field 𝕜] [normed_space 𝕜 β] (c : 𝕜) {f : α → β} : has_finite_integral f → has_finite_integral (c • f) := sorry

theorem has_finite_integral_smul_iff {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] {𝕜 : Type u_5} [normed_field 𝕜] [normed_space 𝕜 β] {c : 𝕜} (hc : c ≠ 0) (f : α → β) : has_finite_integral (c • f) ↔ has_finite_integral f := sorry

theorem has_finite_integral.const_mul {α : Type u_1} [measurable_space α] {μ : measure α} {f : α → ℝ} (h : has_finite_integral f) (c : ℝ) : has_finite_integral fun (x : α) => c * f x :=
  has_finite_integral.smul c h

theorem has_finite_integral.mul_const {α : Type u_1} [measurable_space α] {μ : measure α} {f : α → ℝ} (h : has_finite_integral f) (c : ℝ) : has_finite_integral fun (x : α) => f x * c := sorry

/-! ### The predicate `integrable` -/

/-- `integrable f μ` means that `f` is measurable and that the integral `∫⁻ a, ∥f a∥ ∂μ` is finite.
  `integrable f` means `integrable f volume`. -/
def integrable {α : Type u_1} {β : Type u_2} [measurable_space α] [normed_group β] [measurable_space β] (f : α → β) (μ : autoParam (measure α)
  (Lean.Syntax.ident Lean.SourceInfo.none (String.toSubstring "Mathlib.measure_theory.volume_tac")
    (Lean.Name.mkStr (Lean.Name.mkStr (Lean.Name.mkStr Lean.Name.anonymous "Mathlib") "measure_theory") "volume_tac")
    [])) :=
  ae_measurable f ∧ has_finite_integral f

theorem integrable.ae_measurable {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] {f : α → β} (hf : integrable f) : ae_measurable f :=
  and.left hf

theorem integrable.has_finite_integral {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] {f : α → β} (hf : integrable f) : has_finite_integral f :=
  and.right hf

theorem integrable.mono {α : Type u_1} {β : Type u_2} {γ : Type u_3} [measurable_space α] {μ : measure α} [normed_group β] [normed_group γ] [measurable_space β] [measurable_space γ] {f : α → β} {g : α → γ} (hg : integrable g) (hf : ae_measurable f) (h : filter.eventually (fun (a : α) => norm (f a) ≤ norm (g a)) (measure.ae μ)) : integrable f :=
  { left := hf, right := has_finite_integral.mono (integrable.has_finite_integral hg) h }

theorem integrable.mono' {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] {f : α → β} {g : α → ℝ} (hg : integrable g) (hf : ae_measurable f) (h : filter.eventually (fun (a : α) => norm (f a) ≤ g a) (measure.ae μ)) : integrable f :=
  { left := hf, right := has_finite_integral.mono' (integrable.has_finite_integral hg) h }

theorem integrable.congr' {α : Type u_1} {β : Type u_2} {γ : Type u_3} [measurable_space α] {μ : measure α} [normed_group β] [normed_group γ] [measurable_space β] [measurable_space γ] {f : α → β} {g : α → γ} (hf : integrable f) (hg : ae_measurable g) (h : filter.eventually (fun (a : α) => norm (f a) = norm (g a)) (measure.ae μ)) : integrable g :=
  { left := hg, right := has_finite_integral.congr' (integrable.has_finite_integral hf) h }

theorem integrable_congr' {α : Type u_1} {β : Type u_2} {γ : Type u_3} [measurable_space α] {μ : measure α} [normed_group β] [normed_group γ] [measurable_space β] [measurable_space γ] {f : α → β} {g : α → γ} (hf : ae_measurable f) (hg : ae_measurable g) (h : filter.eventually (fun (a : α) => norm (f a) = norm (g a)) (measure.ae μ)) : integrable f ↔ integrable g :=
  { mp := fun (h2f : integrable f) => integrable.congr' h2f hg h,
    mpr := fun (h2g : integrable g) => integrable.congr' h2g hf (filter.eventually_eq.symm h) }

theorem integrable.congr {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] {f : α → β} {g : α → β} (hf : integrable f) (h : filter.eventually_eq (measure.ae μ) f g) : integrable g :=
  { left := ae_measurable.congr (and.left hf) h, right := has_finite_integral.congr (and.right hf) h }

theorem integrable_congr {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] {f : α → β} {g : α → β} (h : filter.eventually_eq (measure.ae μ) f g) : integrable f ↔ integrable g :=
  { mp := fun (hf : integrable f) => integrable.congr hf h,
    mpr := fun (hg : integrable g) => integrable.congr hg (filter.eventually_eq.symm h) }

theorem integrable_const_iff {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] {c : β} : (integrable fun (x : α) => c) ↔ c = 0 ∨ coe_fn μ set.univ < ⊤ := sorry

theorem integrable_const {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [finite_measure μ] (c : β) : integrable fun (x : α) => c :=
  iff.mpr integrable_const_iff (Or.inr (measure_lt_top μ set.univ))

theorem integrable.mono_measure {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} {ν : measure α} [normed_group β] [measurable_space β] {f : α → β} (h : integrable f) (hμ : μ ≤ ν) : integrable f :=
  { left := ae_measurable.mono_measure (integrable.ae_measurable h) hμ,
    right := has_finite_integral.mono_measure (integrable.has_finite_integral h) hμ }

theorem integrable.add_measure {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} {ν : measure α} [normed_group β] [measurable_space β] {f : α → β} (hμ : integrable f) (hν : integrable f) : integrable f :=
  { left := ae_measurable.add_measure (integrable.ae_measurable hμ) (integrable.ae_measurable hν),
    right := has_finite_integral.add_measure (integrable.has_finite_integral hμ) (integrable.has_finite_integral hν) }

theorem integrable.left_of_add_measure {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} {ν : measure α} [normed_group β] [measurable_space β] {f : α → β} (h : integrable f) : integrable f :=
  integrable.mono_measure h (measure.le_add_right (le_refl μ))

theorem integrable.right_of_add_measure {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} {ν : measure α} [normed_group β] [measurable_space β] {f : α → β} (h : integrable f) : integrable f :=
  integrable.mono_measure h (measure.le_add_left (le_refl ν))

@[simp] theorem integrable_add_measure {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} {ν : measure α} [normed_group β] [measurable_space β] {f : α → β} : integrable f ↔ integrable f ∧ integrable f :=
  { mp :=
      fun (h : integrable f) => { left := integrable.left_of_add_measure h, right := integrable.right_of_add_measure h },
    mpr := fun (h : integrable f ∧ integrable f) => integrable.add_measure (and.left h) (and.right h) }

theorem integrable.smul_measure {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] {f : α → β} (h : integrable f) {c : ennreal} (hc : c < ⊤) : integrable f :=
  { left := ae_measurable.smul_measure (integrable.ae_measurable h) c,
    right := has_finite_integral.smul_measure (integrable.has_finite_integral h) hc }

theorem integrable_map_measure {α : Type u_1} {β : Type u_2} {δ : Type u_4} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [measurable_space δ] [opens_measurable_space β] {f : α → δ} {g : δ → β} (hg : ae_measurable g) (hf : measurable f) : integrable g ↔ integrable (g ∘ f) := sorry

theorem lintegral_edist_lt_top {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [opens_measurable_space β] {f : α → β} {g : α → β} (hf : integrable f) (hg : integrable g) : (lintegral μ fun (a : α) => edist (f a) (g a)) < ⊤ := sorry

@[simp] theorem integrable_zero (α : Type u_1) (β : Type u_2) [measurable_space α] (μ : measure α) [normed_group β] [measurable_space β] : integrable fun (_x : α) => 0 := sorry

theorem integrable.add' {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [opens_measurable_space β] {f : α → β} {g : α → β} (hf : integrable f) (hg : integrable g) : has_finite_integral (f + g) := sorry

theorem integrable.add {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [borel_space β] [topological_space.second_countable_topology β] {f : α → β} {g : α → β} (hf : integrable f) (hg : integrable g) : integrable (f + g) :=
  { left := ae_measurable.add (integrable.ae_measurable hf) (integrable.ae_measurable hg),
    right := integrable.add' hf hg }

theorem integrable_finset_sum {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] {ι : Type u_3} [borel_space β] [topological_space.second_countable_topology β] (s : finset ι) {f : ι → α → β} (hf : ∀ (i : ι), integrable (f i)) : integrable fun (a : α) => finset.sum s fun (i : ι) => f i a := sorry

theorem integrable.neg {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [borel_space β] {f : α → β} (hf : integrable f) : integrable (-f) :=
  { left := ae_measurable.neg (integrable.ae_measurable hf),
    right := has_finite_integral.neg (integrable.has_finite_integral hf) }

@[simp] theorem integrable_neg_iff {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [borel_space β] {f : α → β} : integrable (-f) ↔ integrable f :=
  { mp := fun (h : integrable (-f)) => neg_neg f ▸ integrable.neg h, mpr := integrable.neg }

theorem integrable.sub' {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [opens_measurable_space β] {f : α → β} {g : α → β} (hf : integrable f) (hg : integrable g) : has_finite_integral (f - g) := sorry

theorem integrable.sub {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [borel_space β] [topological_space.second_countable_topology β] {f : α → β} {g : α → β} (hf : integrable f) (hg : integrable g) : integrable (f - g) := sorry

theorem integrable.norm {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [opens_measurable_space β] {f : α → β} (hf : integrable f) : integrable fun (a : α) => norm (f a) :=
  { left := ae_measurable.norm (integrable.ae_measurable hf),
    right := has_finite_integral.norm (integrable.has_finite_integral hf) }

theorem integrable_norm_iff {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [opens_measurable_space β] {f : α → β} (hf : ae_measurable f) : (integrable fun (a : α) => norm (f a)) ↔ integrable f := sorry

theorem integrable.prod_mk {α : Type u_1} {β : Type u_2} {γ : Type u_3} [measurable_space α] {μ : measure α} [normed_group β] [normed_group γ] [measurable_space β] [measurable_space γ] [opens_measurable_space β] [opens_measurable_space γ] {f : α → β} {g : α → γ} (hf : integrable f) (hg : integrable g) : integrable fun (x : α) => (f x, g x) := sorry

/-! ### Lemmas used for defining the positive part of a `L¹` function -/

theorem integrable.max_zero {α : Type u_1} [measurable_space α] {μ : measure α} {f : α → ℝ} (hf : integrable f) : integrable fun (a : α) => max (f a) 0 :=
  { left := ae_measurable.max (integrable.ae_measurable hf) (measurable.ae_measurable measurable_const),
    right := has_finite_integral.max_zero (integrable.has_finite_integral hf) }

theorem integrable.min_zero {α : Type u_1} [measurable_space α] {μ : measure α} {f : α → ℝ} (hf : integrable f) : integrable fun (a : α) => min (f a) 0 :=
  { left := ae_measurable.min (integrable.ae_measurable hf) (measurable.ae_measurable measurable_const),
    right := has_finite_integral.min_zero (integrable.has_finite_integral hf) }

theorem integrable.smul {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] {𝕜 : Type u_5} [normed_field 𝕜] [normed_space 𝕜 β] [borel_space β] (c : 𝕜) {f : α → β} (hf : integrable f) : integrable (c • f) :=
  { left := ae_measurable.const_smul (integrable.ae_measurable hf) c,
    right := has_finite_integral.smul c (integrable.has_finite_integral hf) }

theorem integrable_smul_iff {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] {𝕜 : Type u_5} [normed_field 𝕜] [normed_space 𝕜 β] [borel_space β] {c : 𝕜} (hc : c ≠ 0) (f : α → β) : integrable (c • f) ↔ integrable f :=
  and_congr (ae_measurable_const_smul_iff hc) (has_finite_integral_smul_iff hc f)

theorem integrable.const_mul {α : Type u_1} [measurable_space α] {μ : measure α} {f : α → ℝ} (h : integrable f) (c : ℝ) : integrable fun (x : α) => c * f x :=
  integrable.smul c h

theorem integrable.mul_const {α : Type u_1} [measurable_space α] {μ : measure α} {f : α → ℝ} (h : integrable f) (c : ℝ) : integrable fun (x : α) => f x * c := sorry

theorem integrable_smul_const {α : Type u_1} [measurable_space α] {μ : measure α} {𝕜 : Type u_5} [nondiscrete_normed_field 𝕜] [complete_space 𝕜] [measurable_space 𝕜] [borel_space 𝕜] {E : Type u_6} [normed_group E] [normed_space 𝕜 E] [measurable_space E] [borel_space E] {f : α → 𝕜} {c : E} (hc : c ≠ 0) : (integrable fun (x : α) => f x • c) ↔ integrable f := sorry

/-! ### The predicate `integrable` on measurable functions modulo a.e.-equality -/

namespace ae_eq_fun

/-- A class of almost everywhere equal functions is `integrable` if it has a finite distance to
  the origin. It means the same thing as the predicate `integrable` over functions. -/
def integrable {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [opens_measurable_space β] (f : ae_eq_fun α β μ) :=
  f ∈ emetric.ball 0 ⊤

theorem integrable_mk {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [opens_measurable_space β] {f : α → β} (hf : ae_measurable f) : integrable (mk f hf) ↔ integrable f := sorry

theorem integrable_coe_fn {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [opens_measurable_space β] {f : ae_eq_fun α β μ} : integrable ⇑f ↔ integrable f := sorry

theorem integrable_zero {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [opens_measurable_space β] : integrable 0 :=
  emetric.mem_ball_self ennreal.coe_lt_top

theorem integrable.add {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] {f : ae_eq_fun α β μ} {g : ae_eq_fun α β μ} : integrable f → integrable g → integrable (f + g) := sorry

theorem integrable.neg {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] {f : ae_eq_fun α β μ} : integrable f → integrable (-f) := sorry

theorem integrable.sub {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] {f : ae_eq_fun α β μ} {g : ae_eq_fun α β μ} (hf : integrable f) (hg : integrable g) : integrable (f - g) :=
  integrable.add hf (integrable.neg hg)

protected theorem is_add_subgroup {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] : is_add_subgroup (emetric.ball 0 ⊤) :=
  is_add_subgroup.mk fun (_x : ae_eq_fun α β μ) => integrable.neg

theorem integrable.smul {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] {𝕜 : Type u_5} [normed_field 𝕜] [normed_space 𝕜 β] {c : 𝕜} {f : ae_eq_fun α β μ} : integrable f → integrable (c • f) := sorry

end ae_eq_fun

/-! ### The `L¹` space of functions -/

/-- The space of equivalence classes of integrable (and measurable) functions, where two integrable
    functions are equivalent if they agree almost everywhere, i.e., they differ on a set of measure
    `0`. -/
def l1 (α : Type u_1) (β : Type u_2) [measurable_space α] [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [opens_measurable_space β] (μ : measure α) :=
  Subtype fun (f : ae_eq_fun α β μ) => ae_eq_fun.integrable f

namespace l1

protected instance measure_theory.ae_eq_fun.has_coe {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [opens_measurable_space β] : has_coe (l1 α β μ) (ae_eq_fun α β μ) :=
  Mathlib.coe_subtype

protected instance has_coe_to_fun {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [opens_measurable_space β] : has_coe_to_fun (l1 α β μ) :=
  has_coe_to_fun.mk (fun (f : l1 α β μ) => α → β) fun (f : l1 α β μ) => ⇑↑f

@[simp] theorem coe_coe {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [opens_measurable_space β] (f : l1 α β μ) : ⇑↑f = ⇑f :=
  rfl

protected theorem eq {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [opens_measurable_space β] {f : l1 α β μ} {g : l1 α β μ} : ↑f = ↑g → f = g :=
  subtype.eq

protected theorem eq_iff {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [opens_measurable_space β] {f : l1 α β μ} {g : l1 α β μ} : ↑f = ↑g ↔ f = g :=
  { mp := l1.eq, mpr := congr_arg coe }

/- TODO : order structure of l1-/

/-- `L¹` space forms a `emetric_space`, with the emetric being inherited from almost everywhere
  functions, i.e., `edist f g = ∫⁻ a, edist (f a) (g a)`. -/
protected instance emetric_space {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [opens_measurable_space β] : emetric_space (l1 α β μ) :=
  subtype.emetric_space

/-- `L¹` space forms a `metric_space`, with the metric being inherited from almost everywhere
  functions, i.e., `edist f g = ennreal.to_real (∫⁻ a, edist (f a) (g a))`. -/
protected instance metric_space {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [opens_measurable_space β] : metric_space (l1 α β μ) :=
  metric_space_emetric_ball 0 ⊤

protected instance add_comm_group {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] : add_comm_group (l1 α β μ) :=
  subtype.add_comm_group

protected instance inhabited {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] : Inhabited (l1 α β μ) :=
  { default := 0 }

@[simp] theorem coe_zero {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] : ↑0 = 0 :=
  rfl

@[simp] theorem coe_add {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) (g : l1 α β μ) : ↑(f + g) = ↑f + ↑g :=
  rfl

@[simp] theorem coe_neg {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) : ↑(-f) = -↑f :=
  rfl

@[simp] theorem coe_sub {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) (g : l1 α β μ) : ↑(f - g) = ↑f - ↑g :=
  rfl

@[simp] theorem edist_eq {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) (g : l1 α β μ) : edist f g = edist ↑f ↑g :=
  rfl

theorem dist_eq {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) (g : l1 α β μ) : dist f g = ennreal.to_real (edist ↑f ↑g) :=
  rfl

/-- The norm on `L¹` space is defined to be `∥f∥ = ∫⁻ a, edist (f a) 0`. -/
protected instance has_norm {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] : has_norm (l1 α β μ) :=
  has_norm.mk fun (f : l1 α β μ) => dist f 0

theorem norm_eq {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) : norm f = ennreal.to_real (edist (↑f) 0) :=
  rfl

protected instance normed_group {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] : normed_group (l1 α β μ) :=
  normed_group.of_add_dist sorry sorry

protected instance has_scalar {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] {𝕜 : Type u_5} [normed_field 𝕜] [normed_space 𝕜 β] : has_scalar 𝕜 (l1 α β μ) :=
  has_scalar.mk fun (x : 𝕜) (f : l1 α β μ) => { val := x • ↑f, property := sorry }

@[simp] theorem coe_smul {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] {𝕜 : Type u_5} [normed_field 𝕜] [normed_space 𝕜 β] (c : 𝕜) (f : l1 α β μ) : ↑(c • f) = c • ↑f :=
  rfl

protected instance semimodule {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] {𝕜 : Type u_5} [normed_field 𝕜] [normed_space 𝕜 β] : semimodule 𝕜 (l1 α β μ) :=
  semimodule.mk sorry sorry

protected instance normed_space {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] {𝕜 : Type u_5} [normed_field 𝕜] [normed_space 𝕜 β] : normed_space 𝕜 (l1 α β μ) :=
  normed_space.mk sorry

/-- Construct the equivalence class `[f]` of an integrable function `f`. -/
def of_fun {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : α → β) (hf : integrable f) : l1 α β μ :=
  { val := ae_eq_fun.mk f (integrable.ae_measurable hf), property := sorry }

@[simp] theorem of_fun_eq_mk {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : α → β) (hf : integrable f) : ↑(of_fun f hf) = ae_eq_fun.mk f (integrable.ae_measurable hf) :=
  rfl

theorem of_fun_eq_of_fun {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : α → β) (g : α → β) (hf : integrable f) (hg : integrable g) : of_fun f hf = of_fun g hg ↔ filter.eventually_eq (measure.ae μ) f g := sorry

theorem of_fun_zero {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] : of_fun (fun (_x : α) => 0) (integrable_zero α β μ) = 0 :=
  rfl

theorem of_fun_add {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : α → β) (g : α → β) (hf : integrable f) (hg : integrable g) : of_fun (f + g) (integrable.add hf hg) = of_fun f hf + of_fun g hg :=
  rfl

theorem of_fun_neg {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : α → β) (hf : integrable f) : of_fun (-f) (integrable.neg hf) = -of_fun f hf :=
  rfl

theorem of_fun_sub {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : α → β) (g : α → β) (hf : integrable f) (hg : integrable g) : of_fun (f - g) (integrable.sub hf hg) = of_fun f hf - of_fun g hg := sorry

theorem norm_of_fun {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : α → β) (hf : integrable f) : norm (of_fun f hf) = ennreal.to_real (lintegral μ fun (a : α) => edist (f a) 0) :=
  rfl

theorem norm_of_fun_eq_lintegral_norm {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : α → β) (hf : integrable f) : norm (of_fun f hf) = ennreal.to_real (lintegral μ fun (a : α) => ennreal.of_real (norm (f a))) := sorry

theorem of_fun_smul {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] {𝕜 : Type u_5} [normed_field 𝕜] [normed_space 𝕜 β] (f : α → β) (hf : integrable f) (k : 𝕜) : of_fun (fun (a : α) => k • f a) (integrable.smul k hf) = k • of_fun f hf :=
  rfl

protected theorem measurable {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) : measurable ⇑f :=
  ae_eq_fun.measurable (subtype.val f)

protected theorem ae_measurable {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) : ae_measurable ⇑f :=
  ae_eq_fun.ae_measurable (subtype.val f)

theorem measurable_norm {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) : measurable fun (a : α) => norm (coe_fn f a) :=
  measurable.norm (l1.measurable f)

protected theorem integrable {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) : integrable ⇑f :=
  iff.mpr ae_eq_fun.integrable_coe_fn (subtype.property f)

protected theorem has_finite_integral {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) : has_finite_integral ⇑f :=
  integrable.has_finite_integral (l1.integrable f)

theorem integrable_norm {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) : integrable fun (a : α) => norm (coe_fn f a) :=
  iff.mpr (integrable_norm_iff (l1.ae_measurable f)) (l1.integrable f)

theorem of_fun_to_fun {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) : of_fun (⇑f) (l1.integrable f) = f :=
  subtype.ext (ae_eq_fun.mk_coe_fn ↑f)

theorem mk_to_fun {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) : ae_eq_fun.mk (⇑f) (l1.ae_measurable f) = ↑f := sorry

theorem to_fun_of_fun {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : α → β) (hf : integrable f) : filter.eventually_eq (measure.ae μ) (⇑(of_fun f hf)) f :=
  ae_eq_fun.coe_fn_mk f (integrable.ae_measurable hf)

theorem zero_to_fun (α : Type u_1) (β : Type u_2) [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] : filter.eventually_eq (measure.ae μ) (⇑0) 0 :=
  ae_eq_fun.coe_fn_zero

theorem add_to_fun {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) (g : l1 α β μ) : filter.eventually_eq (measure.ae μ) (⇑(f + g)) (⇑f + ⇑g) :=
  ae_eq_fun.coe_fn_add ↑f ↑g

theorem neg_to_fun {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) : filter.eventually_eq (measure.ae μ) (⇑(-f)) (-⇑f) :=
  ae_eq_fun.coe_fn_neg ↑f

theorem sub_to_fun {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) (g : l1 α β μ) : filter.eventually_eq (measure.ae μ) (⇑(f - g)) (⇑f - ⇑g) :=
  ae_eq_fun.coe_fn_sub ↑f ↑g

theorem dist_to_fun {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) (g : l1 α β μ) : dist f g = ennreal.to_real (lintegral μ fun (x : α) => edist (coe_fn f x) (coe_fn g x)) := sorry

theorem norm_eq_nnnorm_to_fun {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) : norm f = ennreal.to_real (lintegral μ fun (a : α) => ↑(nnnorm (coe_fn f a))) := sorry

theorem norm_eq_norm_to_fun {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) : norm f = ennreal.to_real (lintegral μ fun (a : α) => ennreal.of_real (norm (coe_fn f a))) := sorry

theorem lintegral_edist_to_fun_lt_top {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) (g : l1 α β μ) : (lintegral μ fun (a : α) => edist (coe_fn f a) (coe_fn g a)) < ⊤ :=
  lintegral_edist_lt_top (l1.integrable f) (l1.integrable g)

theorem smul_to_fun {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] {𝕜 : Type u_5} [normed_field 𝕜] [normed_space 𝕜 β] (c : 𝕜) (f : l1 α β μ) : filter.eventually_eq (measure.ae μ) (⇑(c • f)) (c • ⇑f) :=
  ae_eq_fun.coe_fn_smul c ↑f

theorem norm_eq_lintegral {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) : norm f = ennreal.to_real (lintegral μ fun (x : α) => ↑(nnnorm (coe_fn f x))) := sorry

/-- Computing the norm of a difference between two L¹-functions. Note that this is not a
  special case of `norm_eq_lintegral` since `(f - g) x` and `f x - g x` are not equal
  (but only a.e.-equal). -/
theorem norm_sub_eq_lintegral {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) (g : l1 α β μ) : norm (f - g) = ennreal.to_real (lintegral μ fun (x : α) => ↑(nnnorm (coe_fn f x - coe_fn g x))) := sorry

theorem of_real_norm_eq_lintegral {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) : ennreal.of_real (norm f) = lintegral μ fun (x : α) => ↑(nnnorm (coe_fn f x)) := sorry

/-- Computing the norm of a difference between two L¹-functions. Note that this is not a
  special case of `of_real_norm_eq_lintegral` since `(f - g) x` and `f x - g x` are not equal
  (but only a.e.-equal). -/
theorem of_real_norm_sub_eq_lintegral {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] (f : l1 α β μ) (g : l1 α β μ) : ennreal.of_real (norm (f - g)) = lintegral μ fun (x : α) => ↑(nnnorm (coe_fn f x - coe_fn g x)) := sorry

/-- Positive part of a function in `L¹` space. -/
def pos_part {α : Type u_1} [measurable_space α] {μ : measure α} (f : l1 α ℝ μ) : l1 α ℝ μ :=
  { val := ae_eq_fun.pos_part ↑f, property := sorry }

/-- Negative part of a function in `L¹` space. -/
def neg_part {α : Type u_1} [measurable_space α] {μ : measure α} (f : l1 α ℝ μ) : l1 α ℝ μ :=
  pos_part (-f)

theorem coe_pos_part {α : Type u_1} [measurable_space α] {μ : measure α} (f : l1 α ℝ μ) : ↑(pos_part f) = ae_eq_fun.pos_part ↑f :=
  rfl

theorem pos_part_to_fun {α : Type u_1} [measurable_space α] {μ : measure α} (f : l1 α ℝ μ) : filter.eventually_eq (measure.ae μ) ⇑(pos_part f) fun (a : α) => max (coe_fn f a) 0 :=
  ae_eq_fun.coe_fn_pos_part ↑f

theorem neg_part_to_fun_eq_max {α : Type u_1} [measurable_space α] {μ : measure α} (f : l1 α ℝ μ) : filter.eventually (fun (a : α) => coe_fn (neg_part f) a = max (-coe_fn f a) 0) (measure.ae μ) := sorry

theorem neg_part_to_fun_eq_min {α : Type u_1} [measurable_space α] {μ : measure α} (f : l1 α ℝ μ) : filter.eventually (fun (a : α) => coe_fn (neg_part f) a = -min (coe_fn f a) 0) (measure.ae μ) := sorry

theorem norm_le_norm_of_ae_le {α : Type u_1} {β : Type u_2} [measurable_space α] {μ : measure α} [normed_group β] [measurable_space β] [topological_space.second_countable_topology β] [borel_space β] {f : l1 α β μ} {g : l1 α β μ} (h : filter.eventually (fun (a : α) => norm (coe_fn f a) ≤ norm (coe_fn g a)) (measure.ae μ)) : norm f ≤ norm g := sorry

theorem continuous_pos_part {α : Type u_1} [measurable_space α] {μ : measure α} : continuous fun (f : l1 α ℝ μ) => pos_part f := sorry

theorem continuous_neg_part {α : Type u_1} [measurable_space α] {μ : measure α} : continuous fun (f : l1 α ℝ μ) => neg_part f := sorry

/- TODO: l1 is a complete space -/

end l1

end measure_theory

theorem integrable_zero_measure {α : Type u_1} {β : Type u_2} [measurable_space α] [normed_group β] [measurable_space β] {f : α → β} : measure_theory.integrable f :=
  measure_theory.integrable.congr (measure_theory.integrable_zero α β 0)
    (id (Eq.refl (coe_fn 0 (set_of fun (x : α) => 0 ≠ f x))))


import tactic

variables (α : Type) (x y z : α)

--set_option pp.notation false
example : x = x :=
begin
  refl,
end

example : x = y → y = x :=
begin
  intro h,
  induction h,
  refl,
end

example : x = y → y = z → x = z :=
begin
  intro hxy,
  intro hyz,
  induction hxy,
  assumption,
end