CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

| Download

Try doing some basic maths questions in the Lean Theorem Prover. Functions, real numbers, equivalence relations and groups. Click on README.md and then on "Open in CoCalc with one click".

Project: Xena
Views: 18536
License: APACHE
/-
Copyright (c) 2019 Zhouhang Zhou. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Zhouhang Zhou
-/

import measure_theory.simple_func_dense
import analysis.normed_space.bounded_linear_maps

/-!
# Bochner integral

The Bochner integral extends the definition of the Lebesgue integral to functions that map from a
measure space into a Banach space (complete normed vector space). It is constructed here by
extending the integral on simple functions.

## Main definitions

The Bochner integral is defined following these steps:

1. Define the integral on simple functions of the type `simple_func α β` (notation : `α →ₛ β`)
  where `β` is a real normed space.

  (See `simple_func.bintegral` and section `bintegral` for details. Also see `simple_func.integral`
  for the integral on simple functions of the type `simple_func α ennreal`.)

2. Use `simple_func α β` to cut out the simple functions from L1 functions, and define integral
  on these. The type of simple functions in L1 space is written as `α →₁ₛ β`.

3. Show that the embedding of `α →₁ₛ β` into L1 is a dense and uniform one.

4. Show that the integral defined on `α →₁ₛ β` is a continuous linear map.

5. Define the Bochner integral on L1 functions by extending the integral on integrable simple
  functions `α →₁ₛ β` using `continuous_linear_map.extend`. Define the Bochner integral on functions
  as the Bochner integral of its equivalence class in L1 space.

## Main statements

1. Basic properties of the Bochner integral on functions of type `α → β`, where `α` is a measure
   space and `β` is a real normed space.

  * `integral_zero`                  : `∫ 0 = 0`
  * `integral_add`                   : `∫ f + g = ∫ f + ∫ g`
  * `integral_neg`                   : `∫ -f = - ∫ f`
  * `integral_sub`                   : `∫ f - g = ∫ f - ∫ g`
  * `integral_smul`                  : `∫ r • f = r • ∫ f`
  * `integral_congr_ae`              : `∀ₘ a, f a = g a → ∫ f = ∫ g`
  * `norm_integral_le_integral_norm` : `∥∫ f∥ ≤ ∫ ∥f∥`

2. Basic properties of the Bochner integral on functions of type `α → ℝ`, where `α` is a measure
  space.

  * `integral_nonneg_of_nonneg_ae`  : `∀ₘ a, 0 ≤ f a → 0 ≤ ∫ f`
  * `integral_nonpos_of_nonpos_ae`  : `∀ₘ a, f a ≤ 0 → ∫ f ≤ 0`
  * `integral_le_integral_of_le_ae` : `∀ₘ a, f a ≤ g a → ∫ f ≤ ∫ g`

3. Propositions connecting the Bochner integral with the integral on `ennreal`-valued functions,
   which is called `lintegral` and has the notation `∫⁻`.

  * `integral_eq_lintegral_max_sub_lintegral_min` : `∫ f = ∫⁻ f⁺ - ∫⁻ f⁻`, where `f⁺` is the positive
  part of `f` and `f⁻` is the negative part of `f`.
  * `integral_eq_lintegral_of_nonneg_ae`          : `∀ₘ a, 0 ≤ f a → ∫ f = ∫⁻ f`

4. `tendsto_integral_of_dominated_convergence` : the Lebesgue dominated convergence theorem

## Notes

Some tips on how to prove a proposition if the API for the Bochner integral is not enough so that
you need to unfold the definition of the Bochner integral and go back to simple functions.

See `integral_eq_lintegral_max_sub_lintegral_min` for a complicated example, which proves that
`∫ f = ∫⁻ f⁺ - ∫⁻ f⁻`, with the first integral sign being the Bochner integral of a real-valued
function f : α → ℝ, and second and third integral sign being the integral on ennreal-valued
functions (called `lintegral`). The proof of `integral_eq_lintegral_max_sub_lintegral_min` is
scattered in sections with the name `pos_part`.

Here are the usual steps of proving that a property `p`, say `∫ f = ∫⁻ f⁺ - ∫⁻ f⁻`, holds for all
functions :

1. First go to the `L¹` space.

   For example, if you see `ennreal.to_real (∫⁻ a, ennreal.of_real $ ∥f a∥)`, that is the norm of `f` in
`L¹` space. Rewrite using `l1.norm_of_fun_eq_lintegral_norm`.

2. Show that the set `{f ∈ L¹ | ∫ f = ∫⁻ f⁺ - ∫⁻ f⁻}` is closed in `L¹` using `is_closed_eq`.

3. Show that the property holds for all simple functions `s` in `L¹` space.

   Typically, you need to convert various notions to their `simple_func` counterpart, using lemmas like
`l1.integral_coe_eq_integral`.

4. Since simple functions are dense in `L¹`,
```
univ = closure {s simple}
     = closure {s simple | ∫ s = ∫⁻ s⁺ - ∫⁻ s⁻} : the property holds for all simple functions
     ⊆ closure {f | ∫ f = ∫⁻ f⁺ - ∫⁻ f⁻}
     = {f | ∫ f = ∫⁻ f⁺ - ∫⁻ f⁻} : closure of a closed set is itself
```
Use `is_closed_property` or `dense_range.induction_on` for this argument.

## Notations

* `α →ₛ β`  : simple functions (defined in `measure_theory/integration`)
* `α →₁ β`  : functions in L1 space, i.e., equivalence classes of integrable functions (defined in
             `measure_theory/l1_space`)
* `α →₁ₛ β` : simple functions in L1 space, i.e., equivalence classes of integrable simple functions

Note : `ₛ` is typed using `\_s`. Sometimes it shows as a box if font is missing.

## Tags

Bochner integral, simple function, function space, Lebesgue dominated convergence theorem

-/

noncomputable theory
open_locale classical topological_space

set_option class.instance_max_depth 100

-- Typeclass inference has difficulty finding `has_scalar ℝ β` where `β` is a `normed_space` on `ℝ`
local attribute [instance, priority 10000]
  mul_action.to_has_scalar distrib_mul_action.to_mul_action add_comm_group.to_add_comm_monoid
  normed_group.to_add_comm_group normed_space.to_module
  module.to_semimodule

namespace measure_theory

universes u v w
variables {α : Type u} [measurable_space α] {β : Type v} [decidable_linear_order β] [has_zero β]

local infixr ` →ₛ `:25 := simple_func

namespace simple_func

section pos_part

/-- Positive part of a simple function. -/
def pos_part (f : α →ₛ β) : α →ₛ β := f.map (λb, max b 0)

/-- Negative part of a simple function. -/
def neg_part [has_neg β] (f : α →ₛ β) : α →ₛ β := pos_part (-f)

lemma pos_part_map_norm (f : α →ₛ ℝ) : (pos_part f).map norm = pos_part f :=
begin
  ext,
  rw [map_apply, real.norm_eq_abs, abs_of_nonneg],
  rw [pos_part, map_apply],
  exact le_max_right _ _
end

lemma neg_part_map_norm (f : α →ₛ ℝ) : (neg_part f).map norm = neg_part f :=
by { rw neg_part, exact pos_part_map_norm _ }

lemma pos_part_sub_neg_part (f : α →ₛ ℝ) : f.pos_part - f.neg_part = f :=
begin
  simp only [pos_part, neg_part],
  ext,
  exact max_zero_sub_eq_self (f a)
end

end pos_part

end simple_func

end measure_theory

namespace measure_theory
open set lattice filter topological_space ennreal emetric

universes u v w
variables {α : Type u} [measure_space α] {β : Type v} {γ : Type w}

local infixr ` →ₛ `:25 := simple_func

namespace simple_func

section bintegral
/-!
### The Bochner integral of simple functions

Define the Bochner integral of simple functions of the type `α →ₛ β` where `β` is a normed group,
and prove basic property of this integral.
-/
open finset

variables [normed_group β] [normed_group γ]

lemma integrable_iff_integral_lt_top {f : α →ₛ β} :
  integrable f ↔ integral (f.map (coe ∘ nnnorm)) < ⊤ :=
by { rw [integrable, ← lintegral_eq_integral, lintegral_map] }

lemma fin_vol_supp_of_integrable {f : α →ₛ β} (hf : integrable f) : f.fin_vol_supp :=
begin
  rw [integrable_iff_integral_lt_top] at hf,
  have hf := fin_vol_supp_of_integral_lt_top hf,
  refine fin_vol_supp_of_fin_vol_supp_map f hf _,
  assume b, simp [nnnorm_eq_zero]
end

lemma integrable_of_fin_vol_supp {f : α →ₛ β} (h : f.fin_vol_supp) : integrable f :=
by { rw [integrable_iff_integral_lt_top], exact integral_map_coe_lt_top h nnnorm_zero }

/-- For simple functions with a `normed_group` as codomain, being integrable is the same as having
    finite volume support. -/
lemma integrable_iff_fin_vol_supp (f : α →ₛ β) : integrable f ↔ f.fin_vol_supp :=
iff.intro fin_vol_supp_of_integrable integrable_of_fin_vol_supp

lemma integrable_pair {f : α →ₛ β} {g : α →ₛ γ} (hf : integrable f) (hg : integrable g) :
  integrable (pair f g) :=
by { rw integrable_iff_fin_vol_supp at *, apply fin_vol_supp_pair; assumption }

variables [normed_space ℝ γ]

/-- Bochner integral of simple functions whose codomain is a real `normed_space`.
    The name `simple_func.integral` has been taken in the file `integration.lean`, which calculates
    the integral of a simple function with type `α → ennreal`.
    The name `bintegral` stands for Bochner integral. -/
def bintegral [normed_space ℝ β] (f : α →ₛ β) : β :=
f.range.sum (λ x, (ennreal.to_real (volume (f ⁻¹' {x}))) • x)

/-- Calculate the integral of `g ∘ f : α →ₛ γ`, where `f` is an integrable function from `α` to `β`
    and `g` is a function from `β` to `γ`. We require `g 0 = 0` so that `g ∘ f` is integrable. -/
lemma map_bintegral (f : α →ₛ β) (g : β → γ) (hf : integrable f) (hg : g 0 = 0) :
  (f.map g).bintegral = f.range.sum (λ x, (ennreal.to_real (volume (f ⁻¹' {x}))) • (g x)) :=
begin
  /- Just a complicated calculation with `finset.sum`. Real work is done by
     `map_preimage_singleton`, `simple_func.volume_bUnion_preimage` and `ennreal.to_real_sum`  -/
  rw integrable_iff_fin_vol_supp at hf,
  simp only [bintegral, range_map],
  refine finset.sum_image' _ (assume b hb, _),
  rcases mem_range.1 hb with ⟨a, rfl⟩,
  let s' := f.range.filter (λb, g b = g (f a)),
  calc (ennreal.to_real (volume ((f.map g) ⁻¹' {g (f a)}))) • (g (f a)) =
      (ennreal.to_real (volume (⋃b∈s', f ⁻¹' {b}))) • (g (f a)) : by rw map_preimage_singleton
  ... = (ennreal.to_real (s'.sum (λb, volume (f ⁻¹' {b})))) • (g (f a)) :
    by rw volume_bUnion_preimage
  ... = (s'.sum (λb, ennreal.to_real (volume (f ⁻¹' {b})))) • (g (f a)) :
  begin
    by_cases h : g (f a) = 0,
    { rw [h, smul_zero, smul_zero] },
    { rw ennreal.to_real_sum,
      simp only [mem_filter],
      rintros b ⟨_, hb⟩,
      have : b ≠ 0, { assume hb', rw [← hb, hb'] at h, contradiction },
      apply hf,
      assumption }
  end
  ... = s'.sum (λb, (ennreal.to_real (volume (f ⁻¹' {b}))) • (g (f a))) : finset.sum_smul
  ... = s'.sum (λb, (ennreal.to_real (volume (f ⁻¹' {b}))) • (g b)) :
    finset.sum_congr rfl $ by { assume x, simp only [mem_filter], rintro ⟨_, h⟩, rw h }
end

/-- `simple_func.bintegral` and `simple_func.integral` agree when the integrand has type
    `α →ₛ ennreal`. But since `ennreal` is not a `normed_space`, we need some form of coercion.
    See `bintegral_eq_integral'` for a simpler version. -/
lemma bintegral_eq_integral {f : α →ₛ β} {g : β → ennreal} (hf : integrable f) (hg0 : g 0 = 0)
  (hgt : ∀b, g b < ⊤):
  (f.map (ennreal.to_real ∘ g)).bintegral = ennreal.to_real (f.map g).integral :=
begin
  have hf' : f.fin_vol_supp, { rwa integrable_iff_fin_vol_supp at hf },
  rw [map_bintegral f _ hf, map_integral, ennreal.to_real_sum],
  { refine finset.sum_congr rfl (λb hb, _),
    rw [smul_eq_mul],
    rw [to_real_mul_to_real, mul_comm] },
  { assume a ha,
    by_cases a0 : a = 0,
    { rw [a0, hg0, zero_mul], exact with_top.zero_lt_top },
    apply mul_lt_top (hgt a) (hf' _ a0) },
  { simp [hg0] }
end

/-- `simple_func.bintegral` and `lintegral : (α → ennreal) → ennreal` are the same when the
    integrand has type `α →ₛ ennreal`. But since `ennreal` is not a `normed_space`, we need some
    form of coercion.
    See `bintegral_eq_lintegral'` for a simpler version. -/
lemma bintegral_eq_lintegral (f : α →ₛ β) (g : β → ennreal) (hf : integrable f) (hg0 : g 0 = 0)
  (hgt : ∀b, g b < ⊤):
  (f.map (ennreal.to_real ∘ g)).bintegral = ennreal.to_real (∫⁻ a, g (f a)) :=
by { rw [bintegral_eq_integral hf hg0 hgt, ← lintegral_eq_integral], refl }

variables [normed_space ℝ β]

lemma bintegral_congr {f g : α →ₛ β} (hf : integrable f) (hg : integrable g) (h : ∀ₘ a, f a = g a):
  bintegral f = bintegral g :=
show ((pair f g).map prod.fst).bintegral = ((pair f g).map prod.snd).bintegral, from
begin
  have inte := integrable_pair hf hg,
  rw [map_bintegral (pair f g) _ inte prod.fst_zero, map_bintegral (pair f g) _ inte prod.snd_zero],
  refine finset.sum_congr rfl (assume p hp, _),
  rcases mem_range.1 hp with ⟨a, rfl⟩,
  by_cases eq : f a = g a,
  { dsimp only [pair_apply], rw eq },
  { have : volume ((pair f g) ⁻¹' {(f a, g a)}) = 0,
    { refine volume_mono_null (assume a' ha', _) h,
      simp only [set.mem_preimage, mem_singleton_iff, pair_apply, prod.mk.inj_iff] at ha',
      show f a' ≠ g a',
      rwa [ha'.1, ha'.2] },
    simp only [this, pair_apply, zero_smul, ennreal.zero_to_real] },
end

/-- `simple_func.bintegral` and `simple_func.integral` agree when the integrand has type
    `α →ₛ ennreal`. But since `ennreal` is not a `normed_space`, we need some form of coercion. -/
lemma bintegral_eq_integral' {f : α →ₛ ℝ} (hf : integrable f) (h_pos : ∀ₘ a, 0 ≤ f a) :
  f.bintegral = ennreal.to_real (f.map ennreal.of_real).integral :=
begin
  have : ∀ₘ a, f a = (f.map (ennreal.to_real ∘ ennreal.of_real)) a,
  { filter_upwards [h_pos],
    assume a,
    simp only [mem_set_of_eq, map_apply, function.comp_apply],
    assume h,
    exact (ennreal.to_real_of_real h).symm },
  rw ← bintegral_eq_integral hf,
  { refine bintegral_congr hf _ this, exact integrable_of_ae_eq hf this },
  { exact ennreal.of_real_zero },
  { assume b, rw ennreal.lt_top_iff_ne_top, exact ennreal.of_real_ne_top  }
end

/-- `simple_func.bintegral` and `lintegral : (α → ennreal) → ennreal` agree when the integrand has
    type `α →ₛ ennreal`. But since `ennreal` is not a `normed_space`, we need some form of coercion. -/
lemma bintegral_eq_lintegral' {f : α →ₛ ℝ} (hf : integrable f) (h_pos : ∀ₘ a, 0 ≤ f a) :
  f.bintegral = ennreal.to_real (∫⁻ a, (f.map ennreal.of_real a)) :=
by rw [bintegral_eq_integral' hf h_pos, ← lintegral_eq_integral]

lemma bintegral_add {f g : α →ₛ β} (hf : integrable f) (hg : integrable g) :
  bintegral (f + g) = bintegral f + bintegral g :=
calc bintegral (f + g) = sum (pair f g).range
       (λx, ennreal.to_real (volume ((pair f g) ⁻¹' {x})) • (x.fst + x.snd)) :
begin
  rw [add_eq_map₂, map_bintegral (pair f g)],
  { exact integrable_pair hf hg },
  { simp only [add_zero, prod.fst_zero, prod.snd_zero] }
end
... = sum (pair f g).range
        (λx, ennreal.to_real (volume ((pair f g) ⁻¹' {x})) • x.fst +
             ennreal.to_real (volume ((pair f g) ⁻¹' {x})) • x.snd) :
  finset.sum_congr rfl $ assume a ha, smul_add _ _ _
... = sum (simple_func.range (pair f g))
        (λ (x : β × β), ennreal.to_real (volume ((pair f g) ⁻¹' {x})) • x.fst) +
      sum (simple_func.range (pair f g))
        (λ (x : β × β), ennreal.to_real (volume ((pair f g) ⁻¹' {x})) • x.snd) :
  by rw finset.sum_add_distrib
... = ((pair f g).map prod.fst).bintegral + ((pair f g).map prod.snd).bintegral :
begin
  rw [map_bintegral (pair f g), map_bintegral (pair f g)],
  { exact integrable_pair hf hg }, { refl },
  { exact integrable_pair hf hg }, { refl }
end
... = bintegral f + bintegral g : rfl

lemma bintegral_neg {f : α →ₛ β} (hf : integrable f) : bintegral (-f) = - bintegral f :=
calc bintegral (-f) = bintegral (f.map (has_neg.neg)) : rfl
  ... = - bintegral f :
  begin
    rw [map_bintegral f _ hf neg_zero, bintegral, ← sum_neg_distrib],
    refine finset.sum_congr rfl (λx h, smul_neg _ _),
  end

lemma bintegral_sub {f g : α →ₛ β} (hf : integrable f) (hg : integrable g) :
  bintegral (f - g) = bintegral f - bintegral g :=
begin
  have : f - g = f + (-g) := rfl,
  rw [this, bintegral_add hf _, bintegral_neg hg],
  { refl },
  exact hg.neg
end

lemma bintegral_smul (r : ℝ) {f : α →ₛ β} (hf : integrable f) :
  bintegral (r • f) = r • bintegral f :=
calc bintegral (r • f) = sum f.range (λx, ennreal.to_real (volume (f ⁻¹' {x})) • r • x) :
  by rw [smul_eq_map r f, map_bintegral f _ hf (smul_zero _)]
... = (f.range).sum (λ (x : β), ((ennreal.to_real (volume (f ⁻¹' {x}))) * r) • x) :
  finset.sum_congr rfl $ λb hb, by apply smul_smul
... = r • bintegral f :
begin
  rw [bintegral, smul_sum],
  refine finset.sum_congr rfl (λb hb, _),
  rw [smul_smul, mul_comm]
end

lemma norm_bintegral_le_bintegral_norm (f : α →ₛ β) (hf : integrable f) :
  ∥f.bintegral∥ ≤ (f.map norm).bintegral :=
begin
  rw map_bintegral f norm hf norm_zero,
  rw bintegral,
  calc ∥sum f.range (λx, ennreal.to_real (volume (f ⁻¹' {x})) • x)∥ ≤
       sum f.range (λx, ∥ennreal.to_real (volume (f ⁻¹' {x})) • x∥) :
    norm_sum_le _ _
    ... = sum f.range (λx, ennreal.to_real (volume (f ⁻¹' {x})) • ∥x∥) :
    begin
      refine finset.sum_congr rfl (λb hb, _),
      rw [norm_smul, smul_eq_mul, real.norm_eq_abs, abs_of_nonneg to_real_nonneg]
    end
end

end bintegral

end simple_func

namespace l1

open ae_eq_fun

variables [normed_group β] [second_countable_topology β]
          [normed_group γ] [second_countable_topology γ]

variables (α β)
/-- `l1.simple_func` is a subspace of L1 consisting of equivalence classes of an integrable simple
    function. -/
def simple_func : Type (max u v) :=
{ f : α →₁ β // ∃ (s : α →ₛ β),  integrable s ∧ ae_eq_fun.mk s s.measurable = f}

variables {α β}

infixr ` →₁ₛ `:25 := measure_theory.l1.simple_func

namespace simple_func

section instances
/-! Simple functions in L1 space form a `normed_space`. -/

instance : has_coe (α →₁ₛ β) (α →₁ β) := ⟨subtype.val⟩

protected lemma eq {f g : α →₁ₛ β} : (f : α →₁ β) = (g : α →₁ β) → f = g := subtype.eq
protected lemma eq' {f g : α →₁ₛ β} : (f : α →ₘ β) = (g : α →ₘ β) → f = g := subtype.eq ∘ subtype.eq

@[elim_cast] protected lemma eq_iff {f g : α →₁ₛ β} : (f : α →₁ β) = (g : α →₁ β) ↔ f = g :=
iff.intro (subtype.eq) (congr_arg coe)

@[elim_cast] protected lemma eq_iff' {f g : α →₁ₛ β} : (f : α →ₘ β) = (g : α →ₘ β) ↔ f = g :=
iff.intro (simple_func.eq') (congr_arg _)

/-- L1 simple functions forms a `emetric_space`, with the emetric being inherited from L1 space,
  i.e., `edist f g = ∫⁻ a, edist (f a) (g a)`.
  Not declared as an instance as `α →₁ₛ β` will only be useful in the construction of the bochner
  integral. -/
protected def emetric_space  : emetric_space (α →₁ₛ β) := subtype.emetric_space

/-- L1 simple functions forms a `metric_space`, with the metric being inherited from L1 space,
  i.e., `dist f g = ennreal.to_real (∫⁻ a, edist (f a) (g a)`).
  Not declared as an instance as `α →₁ₛ β` will only be useful in the construction of the bochner
  integral. -/
protected def metric_space : metric_space (α →₁ₛ β) := subtype.metric_space

local attribute [instance] protected lemma is_add_subgroup : is_add_subgroup
  (λf:α →₁ β, ∃ (s : α →ₛ β), integrable s ∧ ae_eq_fun.mk s s.measurable = f) :=
{ zero_mem := by { use 0, split, { apply integrable_zero }, { refl } },
  add_mem :=
  begin
    rintros f g ⟨s, hsi, hs⟩ ⟨t, hti, ht⟩,
    use s + t, split,
    { exact hsi.add s.measurable t.measurable hti },
    { rw [coe_add, ← hs, ← ht], refl }
  end,
  neg_mem :=
  begin
    rintros f ⟨s, hsi, hs⟩,
    use -s, split,
    { exact hsi.neg },
    { rw [coe_neg, ← hs], refl }
  end }

/-- Not declared as an instance as `α →₁ₛ β` will only be useful in the construction of the bochner
  integral. -/
protected def add_comm_group : add_comm_group (α →₁ₛ β) := subtype.add_comm_group

local attribute [instance] simple_func.add_comm_group simple_func.metric_space
  simple_func.emetric_space

instance : inhabited (α →₁ₛ β) := ⟨0⟩

@[simp, elim_cast] lemma coe_zero : ((0 : α →₁ₛ β) : α →₁ β) = 0 := rfl
@[simp, move_cast] lemma coe_add (f g : α →₁ₛ β) : ((f + g : α →₁ₛ β) : α →₁ β) = f + g := rfl
@[simp, move_cast] lemma coe_neg (f : α →₁ₛ β) : ((-f : α →₁ₛ β) : α →₁ β) = -f := rfl
@[simp, move_cast] lemma coe_sub (f g : α →₁ₛ β) : ((f - g : α →₁ₛ β) : α →₁ β) = f - g := rfl
@[simp] lemma edist_eq (f g : α →₁ₛ β) : edist f g = edist (f : α →₁ β) (g : α →₁ β) := rfl
@[simp] lemma dist_eq (f g : α →₁ₛ β) : dist f g = dist (f : α →₁ β) (g : α →₁ β) := rfl

/-- The norm on `α →₁ₛ β` is inherited from L1 space. That is, `∥f∥ = ∫⁻ a, edist (f a) 0`.
  Not declared as an instance as `α →₁ₛ β` will only be useful in the construction of the bochner
  integral. -/
protected def has_norm : has_norm (α →₁ₛ β) := ⟨λf, ∥(f : α →₁ β)∥⟩

local attribute [instance] simple_func.has_norm

lemma norm_eq (f : α →₁ₛ β) : ∥f∥ = ∥(f : α →₁ β)∥ := rfl
lemma norm_eq' (f : α →₁ₛ β) : ∥f∥ = ennreal.to_real (edist (f : α →ₘ β) 0) := rfl

/-- Not declared as an instance as `α →₁ₛ β` will only be useful in the construction of the bochner
  integral. -/
protected def normed_group : normed_group (α →₁ₛ β) :=
normed_group.of_add_dist (λ x, rfl) $ by
  { intros, simp only [dist_eq, coe_add, l1.dist_eq, l1.coe_add], rw edist_eq_add_add }

variables {𝕜 : Type*} [normed_field 𝕜] [normed_space 𝕜 β]

/-- Not declared as an instance as `α →₁ₛ β` will only be useful in the construction of the bochner
  integral. -/
protected def has_scalar : has_scalar 𝕜 (α →₁ₛ β) := ⟨λk f, ⟨k • f,
begin
  rcases f with ⟨f, ⟨s, hsi, hs⟩⟩,
  use k • s, split,
  { exact integrable.smul _ hsi },
  { rw [coe_smul, subtype.coe_mk, ← hs], refl }
end ⟩⟩

local attribute [instance, priority 10000] simple_func.has_scalar

@[simp, move_cast] lemma coe_smul (c : 𝕜) (f : α →₁ₛ β) :
  ((c • f : α →₁ₛ β) : α →₁ β) = c • (f : α →₁ β) := rfl

/-- Not declared as an instance as `α →₁ₛ β` will only be useful in the construction of the bochner
  integral. -/
protected def semimodule : semimodule 𝕜 (α →₁ₛ β) :=
{ one_smul  := λf, simple_func.eq (by { simp only [coe_smul], exact one_smul _ _ }),
  mul_smul  := λx y f, simple_func.eq (by { simp only [coe_smul], exact mul_smul _ _ _ }),
  smul_add  := λx f g, simple_func.eq (by { simp only [coe_smul, coe_add], exact smul_add _ _ _ }),
  smul_zero := λx, simple_func.eq (by { simp only [coe_zero, coe_smul], exact smul_zero _ }),
  add_smul  := λx y f, simple_func.eq (by { simp only [coe_smul], exact add_smul _ _ _ }),
  zero_smul := λf, simple_func.eq (by { simp only [coe_smul], exact zero_smul _ _ }) }

/-- Not declared as an instance as `α →₁ₛ β` will only be useful in the construction of the bochner
  integral. -/
protected def module : module 𝕜 (α →₁ₛ β) :=
{ .. simple_func.semimodule }

/-- Not declared as an instance as `α →₁ₛ β` will only be useful in the construction of the bochner
  integral. -/
protected def vector_space : vector_space 𝕜 (α →₁ₛ β) :=
{ .. simple_func.semimodule }

local attribute [instance] simple_func.vector_space simple_func.normed_group

/-- Not declared as an instance as `α →₁ₛ β` will only be useful in the construction of the bochner
  integral. -/
protected def normed_space : normed_space 𝕜 (α →₁ₛ β) :=
⟨ λc f, by { rw [norm_eq, norm_eq, coe_smul, norm_smul] } ⟩

end instances

local attribute [instance] simple_func.normed_group simple_func.normed_space

section of_simple_func

/-- Construct the equivalence class `[f]` of an integrable simple function `f`. -/
@[reducible] def of_simple_func (f : α →ₛ β) (hf : integrable f) : (α →₁ₛ β) :=
  ⟨l1.of_fun f f.measurable hf, ⟨f, ⟨hf, rfl⟩⟩⟩

lemma of_simple_func_eq_of_fun (f : α →ₛ β) (hf : integrable f) :
  (of_simple_func f hf : α →₁ β) = l1.of_fun f f.measurable hf := rfl

lemma of_simple_func_eq_mk (f : α →ₛ β) (hf : integrable f) :
  (of_simple_func f hf : α →ₘ β) = ae_eq_fun.mk f f.measurable := rfl

lemma of_simple_func_zero : of_simple_func (0 : α →ₛ β) (integrable_zero α β) = 0 := rfl

lemma of_simple_func_add (f g : α →ₛ β) (hf hg) :
  of_simple_func (f + g) (integrable.add f.measurable hf g.measurable hg) = of_simple_func f hf +
    of_simple_func g hg := rfl

lemma of_simple_func_neg (f : α →ₛ β) (hf) :
  of_simple_func (-f) (integrable.neg hf) = -of_simple_func f hf := rfl

lemma of_simple_func_sub (f g : α →ₛ β) (hf hg) :
  of_simple_func (f - g) (integrable.sub f.measurable hf g.measurable hg) = of_simple_func f hf -
    of_simple_func g hg := rfl

variables {𝕜 : Type*} [normed_field 𝕜] [normed_space 𝕜 β]

lemma of_simple_func_smul (f : α →ₛ β) (hf) (c : 𝕜) :
  of_simple_func (c • f) (integrable.smul _ hf) = c • of_simple_func f hf := rfl

lemma norm_of_simple_func (f : α →ₛ β) (hf) : ∥of_simple_func f hf∥ = ennreal.to_real (∫⁻ a, edist (f a) 0) :=
rfl

end of_simple_func

section to_simple_func

/-- Find a representative of a `l1.simple_func`. -/
def to_simple_func (f : α →₁ₛ β) : α →ₛ β := classical.some f.2

/-- `f.to_simple_func` is measurable. -/
protected lemma measurable (f : α →₁ₛ β) : measurable f.to_simple_func := f.to_simple_func.measurable

/-- `f.to_simple_func` is integrable. -/
protected lemma integrable (f : α →₁ₛ β) : integrable f.to_simple_func :=
let ⟨h, _⟩ := classical.some_spec f.2 in h

lemma of_simple_func_to_simple_func (f : α →₁ₛ β) :
  of_simple_func (f.to_simple_func) f.integrable = f :=
by { rw ← simple_func.eq_iff', exact (classical.some_spec f.2).2 }

lemma to_simple_func_of_simple_func (f : α →ₛ β) (hfi) :
  ∀ₘ a, (of_simple_func f hfi).to_simple_func a = f a :=
by { rw ← mk_eq_mk, exact (classical.some_spec (of_simple_func f hfi).2).2 }

lemma to_simple_func_eq_to_fun (f : α →₁ₛ β) : ∀ₘ a, (f.to_simple_func) a = (f : α →₁ β).to_fun a :=
begin
  rw [← of_fun_eq_of_fun (f.to_simple_func) (f : α →₁ β).to_fun f.measurable f.integrable
    (f:α→₁β).measurable (f:α→₁β).integrable, ← l1.eq_iff],
  simp only [of_fun_eq_mk],
  rcases classical.some_spec f.2 with ⟨_, h⟩, convert h, rw mk_to_fun, refl
end

variables (α β)
lemma zero_to_simple_func : ∀ₘ a, (0 : α →₁ₛ β).to_simple_func a = 0 :=
begin
  filter_upwards [to_simple_func_eq_to_fun (0 : α →₁ₛ β), l1.zero_to_fun α β],
  assume a,
  simp only [mem_set_of_eq],
  assume h,
  rw h,
  assume h,
  exact h
end
variables {α β}

lemma add_to_simple_func (f g : α →₁ₛ β) :
  ∀ₘ a, (f + g).to_simple_func a = f.to_simple_func a + g.to_simple_func a :=
begin
  filter_upwards [to_simple_func_eq_to_fun (f + g), to_simple_func_eq_to_fun f,
    to_simple_func_eq_to_fun g, l1.add_to_fun (f:α→₁β) g],
  assume a,
  simp only [mem_set_of_eq],
  repeat { assume h, rw h },
  assume h,
  rw ← h,
  refl
end

lemma neg_to_simple_func (f : α →₁ₛ β) : ∀ₘ a, (-f).to_simple_func a = - f.to_simple_func a :=
begin
  filter_upwards [to_simple_func_eq_to_fun (-f), to_simple_func_eq_to_fun f, l1.neg_to_fun (f:α→₁β)],
  assume a,
  simp only [mem_set_of_eq],
  repeat { assume h, rw h },
  assume h,
  rw ← h,
  refl
end

lemma sub_to_simple_func (f g : α →₁ₛ β) :
  ∀ₘ a, (f - g).to_simple_func a = f.to_simple_func a - g.to_simple_func a :=
begin
  filter_upwards [to_simple_func_eq_to_fun (f - g), to_simple_func_eq_to_fun f,
    to_simple_func_eq_to_fun g, l1.sub_to_fun (f:α→₁β) g],
  assume a,
  simp only [mem_set_of_eq],
  repeat { assume h, rw h },
  assume h,
  rw ← h,
  refl
end

variables {𝕜 : Type*} [normed_field 𝕜] [normed_space 𝕜 β]

lemma smul_to_simple_func (k : 𝕜) (f : α →₁ₛ β) :
  ∀ₘ a, (k • f).to_simple_func a = k • f.to_simple_func a :=
begin
  filter_upwards [to_simple_func_eq_to_fun (k • f), to_simple_func_eq_to_fun f,
    l1.smul_to_fun k (f:α→₁β)],
  assume a,
  simp only [mem_set_of_eq],
  repeat { assume h, rw h },
  assume h,
  rw ← h,
  refl
end

lemma lintegral_edist_to_simple_func_lt_top (f g : α →₁ₛ β) :
  (∫⁻ (x : α), edist ((to_simple_func f) x) ((to_simple_func g) x)) < ⊤ :=
begin
  rw lintegral_rw₂ (to_simple_func_eq_to_fun f) (to_simple_func_eq_to_fun g),
  exact lintegral_edist_to_fun_lt_top _ _
end

lemma dist_to_simple_func (f g : α →₁ₛ β) : dist f g =
  ennreal.to_real (∫⁻ x, edist (f.to_simple_func x) (g.to_simple_func x)) :=
begin
  rw [dist_eq, l1.dist_to_fun, ennreal.to_real_eq_to_real],
  { rw lintegral_rw₂, repeat { exact all_ae_eq_symm (to_simple_func_eq_to_fun _) } },
  { exact l1.lintegral_edist_to_fun_lt_top _ _ },
  { exact lintegral_edist_to_simple_func_lt_top _ _ }
end

lemma norm_to_simple_func (f : α →₁ₛ β) :
  ∥f∥ = ennreal.to_real (∫⁻ (a : α), nnnorm ((to_simple_func f) a)) :=
calc ∥f∥ = ennreal.to_real (∫⁻x, edist (f.to_simple_func x) ((0 : α →₁ₛ β).to_simple_func x)) :
begin
  rw [← dist_zero_right, dist_to_simple_func]
end
... = ennreal.to_real (∫⁻ (x : α), (coe ∘ nnnorm) (f.to_simple_func x)) :
begin
  rw lintegral_nnnorm_eq_lintegral_edist,
  have : (∫⁻ (x : α), edist ((to_simple_func f) x) ((to_simple_func (0:α→₁ₛβ)) x)) =
            ∫⁻ (x : α), edist ((to_simple_func f) x) 0,
  { apply lintegral_congr_ae, filter_upwards [zero_to_simple_func α β],
    assume a,
    simp only [mem_set_of_eq],
    assume h,
    rw h },
  rw [ennreal.to_real_eq_to_real],
  { exact this },
  { exact lintegral_edist_to_simple_func_lt_top _ _ },
  { rw ← this, exact lintegral_edist_to_simple_func_lt_top _ _ }
end

lemma norm_eq_bintegral (f : α →₁ₛ β) : ∥f∥ = (f.to_simple_func.map norm).bintegral :=
calc ∥f∥ = ennreal.to_real (∫⁻ (x : α), (coe ∘ nnnorm) (f.to_simple_func x)) :
  by { rw norm_to_simple_func }
... = (f.to_simple_func.map norm).bintegral :
begin
  rw ← f.to_simple_func.bintegral_eq_lintegral (coe ∘ nnnorm) f.integrable,
  { congr },
  { simp only [nnnorm_zero, function.comp_app, ennreal.coe_zero] },
  { assume b, exact coe_lt_top }
end

end to_simple_func

section coe_to_l1
/-! The embedding of integrable simple functions `α →₁ₛ β` into L1 is a uniform and dense embedding. -/

lemma exists_simple_func_near (f : α →₁ β) {ε : ℝ} (ε0 : 0 < ε) :
  ∃ s : α →₁ₛ β, dist f s < ε :=
begin
  rcases f with ⟨⟨f, hfm⟩, hfi⟩,
  simp only [integrable_mk, quot_mk_eq_mk] at hfi,
  rcases simple_func_sequence_tendsto' hfm hfi with ⟨F, ⟨h₁, h₂⟩⟩,
  rw ennreal.tendsto_at_top at h₂,
  rcases h₂ (ennreal.of_real (ε/2)) (of_real_pos.2 $ half_pos ε0) with ⟨N, hN⟩,
  have : (∫⁻ (x : α), nndist (F N x) (f x)) < ennreal.of_real ε :=
    calc (∫⁻ (x : α), nndist (F N x) (f x)) ≤ 0 + ennreal.of_real (ε/2) : (hN N (le_refl _)).2
    ... < ennreal.of_real ε :
      by { simp only [zero_add, of_real_lt_of_real_iff ε0], exact half_lt_self ε0 },
  { refine ⟨of_simple_func (F N) (h₁ N), _⟩, rw dist_comm,
    rw lt_of_real_iff_to_real_lt _ at this,
    { simpa [edist_mk_mk', of_simple_func, l1.of_fun, l1.dist_eq] },
    rw ← lt_top_iff_ne_top, exact lt_trans this (by simp [lt_top_iff_ne_top, of_real_ne_top]) },
  { exact zero_ne_top }
end

protected lemma uniform_continuous : uniform_continuous (coe : (α →₁ₛ β) → (α →₁ β)) :=
uniform_continuous_comap

protected lemma uniform_embedding : uniform_embedding (coe : (α →₁ₛ β) → (α →₁ β)) :=
uniform_embedding_comap subtype.val_injective

protected lemma uniform_inducing : uniform_inducing (coe : (α →₁ₛ β) → (α →₁ β)) :=
simple_func.uniform_embedding.to_uniform_inducing

protected lemma dense_embedding : dense_embedding (coe : (α →₁ₛ β) → (α →₁ β)) :=
simple_func.uniform_embedding.dense_embedding $
λ f, mem_closure_iff_nhds.2 $ λ t ht,
let ⟨ε,ε0, hε⟩ := metric.mem_nhds_iff.1 ht in
let ⟨s, h⟩ := exists_simple_func_near f ε0 in
⟨_, hε (metric.mem_ball'.2 h), s, rfl⟩

protected lemma dense_inducing : dense_inducing (coe : (α →₁ₛ β) → (α →₁ β)) :=
simple_func.dense_embedding.to_dense_inducing

protected lemma dense_range : dense_range (coe : (α →₁ₛ β) → (α →₁ β)) :=
simple_func.dense_inducing.dense

variables (𝕜 : Type*) [normed_field 𝕜] [normed_space 𝕜 β]

variables (α β)

/-- The uniform and dense embedding of L1 simple functions into L1 functions. -/
def coe_to_l1 : (α →₁ₛ β) →L[𝕜] (α →₁ β) :=
{ to_fun := (coe : (α →₁ₛ β) → (α →₁ β)),
  add := λf g, rfl,
  smul := λk f, rfl,
  cont := l1.simple_func.uniform_continuous.continuous, }

variables {α β 𝕜}

end coe_to_l1

section pos_part

/-- Positive part of a simple function in L1 space.  -/
def pos_part (f : α →₁ₛ ℝ) : α →₁ₛ ℝ := ⟨l1.pos_part (f : α →₁ ℝ),
begin
  rcases f with ⟨f, s, hsi, hsf⟩,
  use s.pos_part,
  split,
  { exact integrable.max_zero hsi },
  { simp only [subtype.coe_mk],
    rw [l1.coe_pos_part, ← hsf, ae_eq_fun.pos_part, ae_eq_fun.zero_def, comp₂_mk_mk, mk_eq_mk],
    filter_upwards [],
    simp only [mem_set_of_eq],
    assume a,
    refl }
end ⟩

/-- Negative part of a simple function in L1 space. -/
def neg_part (f : α →₁ₛ ℝ) : α →₁ₛ ℝ := pos_part (-f)

@[move_cast] lemma coe_pos_part (f : α →₁ₛ ℝ) : (f.pos_part : α →₁ ℝ) = (f : α →₁ ℝ).pos_part := rfl

@[move_cast] lemma coe_neg_part (f : α →₁ₛ ℝ) : (f.neg_part : α →₁ ℝ) = (f : α →₁ ℝ).neg_part := rfl

end pos_part

section simple_func_integral
/-! Define the Bochner integral on `α →₁ₛ β` and prove basic properties of this integral. -/

variables [normed_space ℝ β]

/-- The Bochner integral over simple functions in l1 space. -/
def integral (f : α →₁ₛ β) : β := (f.to_simple_func).bintegral

lemma integral_eq_bintegral (f : α →₁ₛ β) : integral f = (f.to_simple_func).bintegral := rfl

lemma integral_eq_lintegral {f : α →₁ₛ ℝ} (h_pos : ∀ₘ a, 0 ≤ f.to_simple_func a) :
  integral f = ennreal.to_real (∫⁻ a, ennreal.of_real (f.to_simple_func a)) :=
by { rw [integral, simple_func.bintegral_eq_lintegral' f.integrable h_pos], refl }

lemma integral_congr (f g : α →₁ₛ β) (h : ∀ₘ a, f.to_simple_func a = g.to_simple_func a) :
  integral f = integral g :=
by { simp only [integral], apply simple_func.bintegral_congr f.integrable g.integrable, exact h }

lemma integral_add (f g : α →₁ₛ β) : integral (f + g) = integral f + integral g :=
begin
  simp only [integral],
  rw ← simple_func.bintegral_add f.integrable g.integrable,
  apply simple_func.bintegral_congr (f + g).integrable,
    { exact f.integrable.add f.measurable g.measurable g.integrable },
    { apply add_to_simple_func },
end

lemma integral_smul (r : ℝ) (f : α →₁ₛ β) : integral (r • f) = r • integral f :=
begin
  simp only [integral],
  rw ← simple_func.bintegral_smul _ f.integrable,
  apply simple_func.bintegral_congr (r • f).integrable,
    { exact integrable.smul _ f.integrable },
    { apply smul_to_simple_func }
end

lemma norm_integral_le_norm (f : α →₁ₛ β) : ∥ integral f ∥ ≤ ∥f∥ :=
begin
  rw [integral, norm_eq_bintegral],
  exact f.to_simple_func.norm_bintegral_le_bintegral_norm f.integrable
end

/-- The Bochner integral over simple functions in l1 space as a continuous linear map. -/
def integral_clm : (α →₁ₛ β) →L[ℝ] β :=
linear_map.mk_continuous ⟨integral, integral_add, integral_smul⟩
  1 (λf, le_trans (norm_integral_le_norm _) $ by rw one_mul)

local notation `Integral` := @integral_clm α _ β _ _ _

open continuous_linear_map

lemma norm_Integral_le_one : ∥Integral∥ ≤ 1 :=
linear_map.mk_continuous_norm_le _ (zero_le_one) _

section pos_part

lemma pos_part_to_simple_func (f : α →₁ₛ ℝ) :
  ∀ₘ a, f.pos_part.to_simple_func a = f.to_simple_func.pos_part a :=
begin
  have eq : ∀ a, f.to_simple_func.pos_part a = max (f.to_simple_func a) 0 := λa, rfl,
  have ae_eq : ∀ₘ a, f.pos_part.to_simple_func a = max (f.to_simple_func a) 0,
  { filter_upwards [to_simple_func_eq_to_fun f.pos_part, pos_part_to_fun (f : α →₁ ℝ),
      to_simple_func_eq_to_fun f],
    simp only [mem_set_of_eq],
    assume a h₁ h₂ h₃,
    rw [h₁, coe_pos_part, h₂, ← h₃] },
  filter_upwards [ae_eq],
  simp only [mem_set_of_eq],
  assume a h,
  rw [h, eq]
end

lemma neg_part_to_simple_func (f : α →₁ₛ ℝ) :
  ∀ₘ a, f.neg_part.to_simple_func a = f.to_simple_func.neg_part a :=
begin
  rw [simple_func.neg_part, measure_theory.simple_func.neg_part],
  filter_upwards [pos_part_to_simple_func (-f), neg_to_simple_func f],
  simp only [mem_set_of_eq],
  assume a h₁ h₂,
  rw h₁,
  show max _ _ = max _ _,
  rw h₂,
  refl
end

lemma integral_eq_norm_pos_part_sub (f : α →₁ₛ ℝ) : f.integral = ∥f.pos_part∥ - ∥f.neg_part∥ :=
begin
  -- Convert things in `L¹` to their `simple_func` counterpart
  have ae_eq₁ : ∀ₘ a, f.to_simple_func.pos_part a = (f.pos_part).to_simple_func.map norm a,
  { filter_upwards [pos_part_to_simple_func f],
    simp only [mem_set_of_eq],
    assume a h,
    rw [simple_func.map_apply, h],
    conv_lhs { rw [← simple_func.pos_part_map_norm, simple_func.map_apply] } },
  -- Convert things in `L¹` to their `simple_func` counterpart
  have ae_eq₂ : ∀ₘ a, f.to_simple_func.neg_part a = (f.neg_part).to_simple_func.map norm a,
  { filter_upwards [neg_part_to_simple_func f],
    simp only [mem_set_of_eq],
    assume a h,
    rw [simple_func.map_apply, h],
    conv_lhs { rw [← simple_func.neg_part_map_norm, simple_func.map_apply] } },
  -- Convert things in `L¹` to their `simple_func` counterpart
  have ae_eq : ∀ₘ a, f.to_simple_func.pos_part a - f.to_simple_func.neg_part a =
    (f.pos_part).to_simple_func.map norm a - (f.neg_part).to_simple_func.map norm a,
  { filter_upwards [ae_eq₁, ae_eq₂],
    simp only [mem_set_of_eq],
    assume a h₁ h₂,
    rw [h₁, h₂] },
  rw [integral, norm_eq_bintegral, norm_eq_bintegral, ← simple_func.bintegral_sub],
  { show f.to_simple_func.bintegral =
      ((f.pos_part.to_simple_func).map norm - f.neg_part.to_simple_func.map norm).bintegral,
    apply simple_func.bintegral_congr f.integrable,
    { show integrable (f.pos_part.to_simple_func.map norm - f.neg_part.to_simple_func.map norm),
      refine integrable_of_ae_eq _ _,
      { exact (f.to_simple_func.pos_part - f.to_simple_func.neg_part) },
      { exact (integrable.max_zero f.integrable).sub f.to_simple_func.pos_part.measurable
        f.to_simple_func.neg_part.measurable (integrable.max_zero f.integrable.neg) },
      exact ae_eq },
    filter_upwards [ae_eq₁, ae_eq₂],
    simp only [mem_set_of_eq],
    assume a h₁ h₂, show _ = _ - _,
    rw [← h₁, ← h₂],
    have := f.to_simple_func.pos_part_sub_neg_part,
    conv_lhs {rw ← this},
    refl },
  { refine integrable_of_ae_eq (integrable.max_zero f.integrable) ae_eq₁ },
  { refine integrable_of_ae_eq (integrable.max_zero f.integrable.neg) ae_eq₂ }
end

end pos_part

end simple_func_integral

end simple_func

open simple_func

variables [normed_space ℝ β] [normed_space ℝ γ] [complete_space β]

section integration_in_l1

local notation `to_l1` := coe_to_l1 α β ℝ
local attribute [instance] simple_func.normed_group simple_func.normed_space

open continuous_linear_map

/-- The Bochner integral in l1 space as a continuous linear map. -/
def integral_clm : (α →₁ β) →L[ℝ] β :=
  integral_clm.extend to_l1 simple_func.dense_range simple_func.uniform_inducing

/-- The Bochner integral in l1 space -/
def integral (f : α →₁ β) : β := (integral_clm).to_fun f

lemma integral_eq (f : α →₁ β) : integral f = (integral_clm).to_fun f := rfl

@[elim_cast] lemma integral_coe_eq_integral (f : α →₁ₛ β) :
  integral (f : α →₁ β) = f.integral :=
by { refine uniformly_extend_of_ind _ _ _ _, exact simple_func.integral_clm.uniform_continuous }

variables (α β)
@[simp] lemma integral_zero : integral (0 : α →₁ β) = 0 :=
map_zero integral_clm
variables {α β}

lemma integral_add (f g : α →₁ β) : integral (f + g) = integral f + integral g :=
map_add integral_clm f g

lemma integral_neg (f : α →₁ β) : integral (-f) = - integral f :=
map_neg integral_clm f

lemma integral_sub (f g : α →₁ β) : integral (f - g) = integral f - integral g :=
map_sub integral_clm f g

lemma integral_smul (r : ℝ) (f : α →₁ β) : integral (r • f) = r • integral f :=
map_smul r integral_clm f

local notation `Integral` := @integral_clm α _ β _ _ _ _
local notation `sIntegral` := @simple_func.integral_clm α _ β _ _ _

lemma norm_Integral_le_one : ∥Integral∥ ≤ 1 :=
calc ∥Integral∥ ≤ 1 * ∥sIntegral∥ :
  op_norm_extend_le _ _ _ $ λs, by {rw one_mul, refl}
  ... = ∥sIntegral∥ : one_mul _
  ... ≤ 1 : norm_Integral_le_one

lemma norm_integral_le (f : α →₁ β) : ∥integral f∥ ≤ ∥f∥ :=
calc ∥integral f∥ = ∥Integral f∥ : rfl
  ... ≤ ∥Integral∥ * ∥f∥ : le_op_norm _ _
  ... ≤ 1 * ∥f∥ : mul_le_mul_of_nonneg_right norm_Integral_le_one $ norm_nonneg _
  ... = ∥f∥ : one_mul _

section pos_part

lemma integral_eq_norm_pos_part_sub (f : α →₁ ℝ) : integral f = ∥pos_part f∥ - ∥neg_part f∥ :=
begin
  -- Use `is_closed_property` and `is_closed_eq`
  refine @is_closed_property _ _ _ (coe : (α →₁ₛ ℝ) → (α →₁ ℝ))
    (λ f : α →₁ ℝ, integral f = ∥pos_part f∥ - ∥neg_part f∥)
    l1.simple_func.dense_range (is_closed_eq _ _) _ f,
  { exact cont _ },
  { refine continuous.sub (continuous_norm.comp l1.continuous_pos_part)
      (continuous_norm.comp l1.continuous_neg_part) },
  -- Show that the property holds for all simple functions in the `L¹` space.
  { assume s,
    norm_cast,
    rw [← simple_func.norm_eq, ← simple_func.norm_eq],
    exact simple_func.integral_eq_norm_pos_part_sub _}
end

end pos_part

end integration_in_l1

end l1

variables [normed_group β] [second_countable_topology β] [normed_space ℝ β] [complete_space β]
          [normed_group γ] [second_countable_topology γ] [normed_space ℝ γ] [complete_space γ]

/-- The Bochner integral -/
def integral (f : α → β) : β :=
if hf : measurable f ∧ integrable f
then (l1.of_fun f hf.1 hf.2).integral
else 0

notation `∫` binders `, ` r:(scoped f, integral f) := r

section properties

open continuous_linear_map measure_theory.simple_func

variables {f g : α → β}

lemma integral_eq (f : α → β) (h₁ : measurable f) (h₂ : integrable f) :
  (∫ a, f a) = (l1.of_fun f h₁ h₂).integral :=
dif_pos ⟨h₁, h₂⟩

lemma integral_undef (h : ¬ (measurable f ∧ integrable f)) : (∫ a, f a) = 0 :=
dif_neg h

lemma integral_non_integrable (h : ¬ integrable f) : (∫ a, f a) = 0 :=
integral_undef $ not_and_of_not_right _ h

lemma integral_non_measurable (h : ¬ measurable f) : (∫ a, f a) = 0 :=
integral_undef $ not_and_of_not_left _ h

variables (α β)
@[simp] lemma integral_zero : (∫ a:α, (0:β)) = 0 :=
by rw [integral_eq, l1.of_fun_zero, l1.integral_zero]

variables {α β}

lemma integral_add
  (hfm : measurable f) (hfi : integrable f) (hgm : measurable g) (hgi : integrable g) :
  (∫ a, f a + g a) = (∫ a, f a) + (∫ a, g a) :=
by rw [integral_eq, integral_eq f hfm hfi, integral_eq g hgm hgi, l1.of_fun_add, l1.integral_add]

lemma integral_neg (f : α → β) : (∫ a, -f a) = - (∫ a, f a) :=
begin
  by_cases hf : measurable f ∧ integrable f,
  { rw [integral_eq f hf.1 hf.2, integral_eq (λa, - f a) hf.1.neg hf.2.neg, l1.of_fun_neg,
    l1.integral_neg] },
  { have hf' : ¬(measurable (λa, -f a) ∧ integrable (λa, -f a)),
    { rwa [measurable_neg_iff, integrable_neg_iff] },
    rw [integral_undef hf, integral_undef hf', neg_zero] }
end

lemma integral_sub
  (hfm : measurable f) (hfi : integrable f) (hgm : measurable g) (hgi : integrable g) :
  (∫ a, f a - g a) = (∫ a, f a) - (∫ a, g a) :=
by simp only [sub_eq_add_neg, integral_neg, integral_add, measurable_neg_iff, integrable_neg_iff, *]

lemma integral_smul (r : ℝ) (f : α → β) : (∫ a, r • (f a)) = r • (∫ a, f a) :=
begin
  by_cases hf : measurable f ∧ integrable f,
  { rw [integral_eq f hf.1 hf.2, integral_eq (λa, r • (f a)), l1.of_fun_smul, l1.integral_smul] },
  { by_cases hr : r = 0,
    { simp only [hr, measure_theory.integral_zero, zero_smul] },
    have hf' : ¬(measurable (λa, r • f a) ∧ integrable (λa, r • f a)),
    { rwa [← measurable_smul_iff hr f, ← integrable_smul_iff hr f] at hf },
    rw [integral_undef hf, integral_undef hf', smul_zero] }
end

lemma integral_mul_left (r : ℝ) (f : α → ℝ) : (∫ a, r * (f a)) = r * (∫ a, f a) :=
integral_smul r f

lemma integral_mul_right (r : ℝ) (f : α → ℝ) : (∫ a, (f a) * r) = (∫ a, f a) * r :=
by { simp only [mul_comm], exact integral_mul_left r f }

lemma integral_div (r : ℝ) (f : α → ℝ) : (∫ a, (f a) / r) = (∫ a, f a) / r :=
integral_mul_right r⁻¹ f

lemma integral_congr_ae (hfm : measurable f) (hgm : measurable g) (h : ∀ₘ a, f a = g a) :
   (∫ a, f a) = (∫ a, g a) :=
begin
  by_cases hfi : integrable f,
  { have hgi : integrable g := integrable_of_ae_eq hfi h,
    rw [integral_eq f hfm hfi, integral_eq g hgm hgi, (l1.of_fun_eq_of_fun f g hfm hfi hgm hgi).2 h] },
  { have hgi : ¬ integrable g, { rw integrable_congr_ae h at hfi, exact hfi },
    rw [integral_non_integrable hfi, integral_non_integrable hgi] },
end

lemma norm_integral_le_lintegral_norm (f : α → β) :
  ∥(∫ a, f a)∥ ≤ ennreal.to_real (∫⁻ a, ennreal.of_real ∥f a∥) :=
begin
  by_cases hf : measurable f ∧ integrable f,
  { rw [integral_eq f hf.1 hf.2, ← l1.norm_of_fun_eq_lintegral_norm f hf.1 hf.2],
    exact l1.norm_integral_le _ },
  { rw [integral_undef hf, _root_.norm_zero],
    exact to_real_nonneg }
end

/-- Lebesgue dominated convergence theorem provides sufficient conditions under which almost
  everywhere convergence of a sequence of functions implies the convergence of their integrals. -/
theorem tendsto_integral_of_dominated_convergence {F : ℕ → α → β} {f : α → β} (bound : α → ℝ)
  (F_measurable : ∀ n, measurable (F n))
  (f_measurable : measurable f)
  (bound_integrable : integrable bound)
  (h_bound : ∀ n, ∀ₘ a, ∥F n a∥ ≤ bound a)
  (h_lim : ∀ₘ a, tendsto (λ n, F n a) at_top (𝓝 (f a))) :
  tendsto (λn, ∫ a, F n a) at_top (𝓝 $ (∫ a, f a)) :=
begin
  /- To show `(∫ a, F n a) --> (∫ f)`, suffices to show `∥∫ a, F n a - ∫ f∥ --> 0` -/
  rw tendsto_iff_norm_tendsto_zero,
  /- But `0 ≤ ∥∫ a, F n a - ∫ f∥ = ∥∫ a, (F n a - f a) ∥ ≤ ∫ a, ∥F n a - f a∥, and thus we apply the
    sandwich theorem and prove that `∫ a, ∥F n a - f a∥ --> 0` -/
  have zero_tendsto_zero : tendsto (λn:ℕ, (0 : ℝ)) at_top (𝓝 0) := tendsto_const_nhds,
  have lintegral_norm_tendsto_zero :
    tendsto (λn, ennreal.to_real $ ∫⁻ a, ennreal.of_real ∥F n a - f a∥) at_top (𝓝 0) :=
  tendsto.comp (tendsto_to_real (zero_ne_top))
    (tendsto_lintegral_norm_of_dominated_convergence
      F_measurable f_measurable bound_integrable h_bound h_lim),
  -- Use the sandwich theorem
  refine tendsto_of_tendsto_of_tendsto_of_le_of_le zero_tendsto_zero lintegral_norm_tendsto_zero _ _,
  -- Show `0 ≤ ∥∫ a, F n a - ∫ f∥` for all `n`
  { simp only [filter.eventually_at_top, norm_nonneg, forall_true_iff, exists_const] },
  -- Show `∥∫ a, F n a - ∫ f∥ ≤ ∫ a, ∥F n a - f a∥` for all `n`
  { simp only [filter.eventually_at_top],
    use 0,
    assume n hn,
    have h₁ : integrable (F n) := integrable_of_integrable_bound bound_integrable (h_bound _),
    have h₂ : integrable f := integrable_of_dominated_convergence bound_integrable h_bound h_lim,
    rw ← integral_sub (F_measurable _) h₁ f_measurable h₂,
    exact norm_integral_le_lintegral_norm _ }
end

/-- Lebesgue dominated convergence theorem for filters with a countable basis -/
lemma tendsto_integral_filter_of_dominated_convergence {ι} {l : filter ι}
  {F : ι → α → β} {f : α → β} (bound : α → ℝ)
  (hl_cb : l.has_countable_basis)
  (hF_meas : ∀ᶠ n in l, measurable (F n))
  (f_measurable : measurable f)
  (h_bound : ∀ᶠ n in l, ∀ₘ a, ∥F n a∥ ≤ bound a)
  (bound_integrable : integrable bound)
  (h_lim : ∀ₘ a, tendsto (λ n, F n a) l (𝓝 (f a))) :
  tendsto (λn, ∫ a, F n a) l (𝓝 $ (∫ a, f a)) :=
begin
  rw hl_cb.tendsto_iff_seq_tendsto,
  { intros x xl,
    have hxl, { rw tendsto_at_top' at xl, exact xl },
    have h := inter_mem_sets hF_meas h_bound,
    replace h := hxl _ h,
    rcases h with ⟨k, h⟩,
    rw ← tendsto_add_at_top_iff_nat k,
    refine tendsto_integral_of_dominated_convergence _ _ _ _ _ _,
    { exact bound },
    { intro, refine (h _ _).1, exact nat.le_add_left _ _ },
    { assumption },
    { assumption },
    { intro, refine (h _ _).2, exact nat.le_add_left _ _ },
    { filter_upwards [h_lim],
      simp only [mem_set_of_eq],
      assume a h_lim,
      apply @tendsto.comp _ _ _ (λn, x (n + k)) (λn, F n a),
      { assumption },
      rw tendsto_add_at_top_iff_nat,
      assumption } },
end

/-- The Bochner integral of a real-valued function `f : α → ℝ` is the difference between the
  integral of the positive part of `f` and the integral of the negative part of `f`.  -/
lemma integral_eq_lintegral_max_sub_lintegral_min {f : α → ℝ}
  (hfm : measurable f) (hfi : integrable f) : (∫ a, f a) =
  ennreal.to_real (∫⁻ a, ennreal.of_real $ max (f a) 0) -
  ennreal.to_real (∫⁻ a, ennreal.of_real $ - min (f a) 0) :=
let f₁ : α →₁ ℝ := l1.of_fun f hfm hfi in
-- Go to the `L¹` space
have eq₁ : ennreal.to_real (∫⁻ a, ennreal.of_real $ max (f a) 0) = ∥l1.pos_part f₁∥ :=
begin
  rw l1.norm_eq_norm_to_fun,
  congr' 1,
  apply lintegral_congr_ae,
  filter_upwards [l1.pos_part_to_fun f₁, l1.to_fun_of_fun f hfm hfi],
  simp only [mem_set_of_eq],
  assume a h₁ h₂,
  rw [h₁, h₂, real.norm_eq_abs, abs_of_nonneg],
  exact le_max_right _ _
end,
-- Go to the `L¹` space
have eq₂ : ennreal.to_real (∫⁻ a, ennreal.of_real $ -min (f a) 0) = ∥l1.neg_part f₁∥ :=
begin
  rw l1.norm_eq_norm_to_fun,
  congr' 1,
  apply lintegral_congr_ae,
  filter_upwards [l1.neg_part_to_fun_eq_min f₁, l1.to_fun_of_fun f hfm hfi],
  simp only [mem_set_of_eq],
  assume a h₁ h₂,
  rw [h₁, h₂, real.norm_eq_abs, abs_of_nonneg],
  rw [min_eq_neg_max_neg_neg, _root_.neg_neg, neg_zero],
  exact le_max_right _ _
end,
begin
  rw [eq₁, eq₂, integral, dif_pos],
  exact l1.integral_eq_norm_pos_part_sub _,
  { exact ⟨hfm, hfi⟩ }
end

lemma integral_eq_lintegral_of_nonneg_ae {f : α → ℝ} (hf : ∀ₘ a, 0 ≤ f a) (hfm : measurable f) :
  (∫ a, f a) = ennreal.to_real (∫⁻ a, ennreal.of_real $ f a) :=
begin
  by_cases hfi : integrable f,
  { rw integral_eq_lintegral_max_sub_lintegral_min hfm hfi,
    have h_min : (∫⁻ a, ennreal.of_real (-min (f a) 0)) = 0,
    { rw lintegral_eq_zero_iff,
      { filter_upwards [hf],
        simp only [mem_set_of_eq],
        assume a h,
        simp only [min_eq_right h, neg_zero, ennreal.of_real_zero] },
      { refine measurable_of_real.comp
          ((measurable.neg measurable_id).comp $ measurable.min hfm measurable_const) } },
    have h_max : (∫⁻ a, ennreal.of_real (max (f a) 0)) = (∫⁻ a, ennreal.of_real $ f a),
    { apply lintegral_congr_ae,
      filter_upwards [hf],
      simp only [mem_set_of_eq],
      assume a h,
      rw max_eq_left h },
    rw [h_min, h_max, zero_to_real, _root_.sub_zero] },
  { rw integral_non_integrable hfi,
    rw [integrable_iff_norm, lt_top_iff_ne_top, ne.def, not_not] at hfi,
    have : (∫⁻ (a : α), ennreal.of_real (f a)) = (∫⁻ a, ennreal.of_real ∥f a∥),
    { apply lintegral_congr_ae,
      filter_upwards [hf],
      simp only [mem_set_of_eq],
      assume a h,
      rw [real.norm_eq_abs, abs_of_nonneg h] },
    rw [this, hfi], refl }
end

lemma integral_nonneg_of_nonneg_ae {f : α → ℝ} (hf : ∀ₘ a, 0 ≤ f a) : 0 ≤ (∫ a, f a) :=
begin
  by_cases hfm : measurable f,
  { rw integral_eq_lintegral_of_nonneg_ae hf hfm, exact to_real_nonneg },
  { rw integral_non_measurable hfm }
end

lemma integral_nonpos_of_nonpos_ae {f : α → ℝ} (hf : ∀ₘ a, f a ≤ 0) : (∫ a, f a) ≤ 0 :=
begin
  have hf : ∀ₘ a, 0 ≤ (-f) a,
  { filter_upwards [hf], simp only [mem_set_of_eq], assume a h, rwa [pi.neg_apply, neg_nonneg] },
  have : 0 ≤ (∫ a, -f a) := integral_nonneg_of_nonneg_ae hf,
  rwa [integral_neg, neg_nonneg] at this,
end

lemma integral_le_integral_ae {f g : α → ℝ} (hfm : measurable f) (hfi : integrable f)
  (hgm : measurable g) (hgi : integrable g) (h : ∀ₘ a, f a ≤ g a) : (∫ a, f a) ≤ (∫ a, g a) :=
le_of_sub_nonneg
begin
  rw ← integral_sub hgm hgi hfm hfi,
  apply integral_nonneg_of_nonneg_ae,
  filter_upwards [h],
  simp only [mem_set_of_eq],
  assume a,
  exact sub_nonneg_of_le
end

lemma integral_le_integral {f g : α → ℝ} (hfm : measurable f) (hfi : integrable f)
  (hgm : measurable g) (hgi : integrable g) (h : ∀ a, f a ≤ g a) : (∫ a, f a) ≤ (∫ a, g a) :=
integral_le_integral_ae hfm hfi hgm hgi $ univ_mem_sets' h

lemma norm_integral_le_integral_norm (f : α → β) : ∥(∫ a, f a)∥ ≤ ∫ a, ∥f a∥ :=
have le_ae : ∀ₘ (a : α), 0 ≤ ∥f a∥ := by filter_upwards [] λa, norm_nonneg _,
classical.by_cases
( λh : measurable f,
  calc ∥(∫ a, f a)∥ ≤ ennreal.to_real (∫⁻ a, ennreal.of_real ∥f a∥) : norm_integral_le_lintegral_norm _
    ... = ∫ a, ∥f a∥ : (integral_eq_lintegral_of_nonneg_ae le_ae $ measurable.norm h).symm )
( λh : ¬measurable f,
  begin
    rw [integral_non_measurable h, _root_.norm_zero],
    exact integral_nonneg_of_nonneg_ae le_ae
  end )

lemma integral_finset_sum {ι} (s : finset ι) {f : ι → α → β}
  (hfm : ∀ i, measurable (f i)) (hfi : ∀ i, integrable (f i)) :
  (∫ a, s.sum (λ i, f i a)) = s.sum (λ i, ∫ a, f i a) :=
begin
  refine finset.induction_on s _ _,
  { simp only [integral_zero, finset.sum_empty] },
  { assume i s his ih,
    simp only [his, finset.sum_insert, not_false_iff],
    rw [integral_add (hfm _) (hfi _) (measurable_finset_sum s hfm)
        (integrable_finset_sum s hfm hfi), ih] }
end

end properties

mk_simp_attribute integral_simps "Simp set for integral rules."

attribute [integral_simps] integral_neg integral_smul l1.integral_add l1.integral_sub
  l1.integral_smul l1.integral_neg

attribute [irreducible] integral l1.integral

end measure_theory