/-
Copyright (c) 2020 Zhouhang Zhou. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Zhouhang Zhou, Yury Kudryashov
-/
import measure_theory.integral.integrable_on
import measure_theory.integral.bochner
import measure_theory.function.locally_integrable
import order.filter.indicator_function
import topology.metric_space.thickened_indicator
import topology.continuous_function.compact

/-!
# Set integral

In this file we prove some properties of `∫ x in s, f x ∂μ`. Recall that this notation
is defined as `∫ x, f x ∂(μ.restrict s)`. In `integral_indicator` we prove that for a measurable
function `f` and a measurable set `s` this definition coincides with another natural definition:
`∫ x, indicator s f x ∂μ = ∫ x in s, f x ∂μ`, where `indicator s f x` is equal to `f x` for `x ∈ s`
and is zero otherwise.

Since `∫ x in s, f x ∂μ` is a notation, one can rewrite or apply any theorem about `∫ x, f x ∂μ`
directly. In this file we prove some theorems about dependence of `∫ x in s, f x ∂μ` on `s`, e.g.
`integral_union`, `integral_empty`, `integral_univ`.

We use the property `integrable_on f s μ := integrable f (μ.restrict s)`, defined in
`measure_theory.integrable_on`. We also defined in that same file a predicate
`integrable_at_filter (f : α → E) (l : filter α) (μ : measure α)` saying that `f` is integrable at
some set `s ∈ l`.

Finally, we prove a version of the
[Fundamental theorem of calculus](https://en.wikipedia.org/wiki/Fundamental_theorem_of_calculus)
for set integral, see `filter.tendsto.integral_sub_linear_is_o_ae` and its corollaries.
Namely, consider a measurably generated filter `l`, a measure `μ` finite at this filter, and
a function `f` that has a finite limit `c` at `l ⊓ μ.ae`. Then `∫ x in s, f x ∂μ = μ s • c + o(μ s)`
as `s` tends to `l.small_sets`, i.e. for any `ε>0` there exists `t ∈ l` such that
`‖∫ x in s, f x ∂μ - μ s • c‖ ≤ ε * μ s` whenever `s ⊆ t`. We also formulate a version of this
theorem for a locally finite measure `μ` and a function `f` continuous at a point `a`.

## Notation

We provide the following notations for expressing the integral of a function on a set :
* `∫ a in s, f a ∂μ` is `measure_theory.integral (μ.restrict s) f`
* `∫ a in s, f a` is `∫ a in s, f a ∂volume`

Note that the set notations are defined in the file `measure_theory/integral/bochner`,
but we reference them here because all theorems about set integrals are in this file.

-/

noncomputable theory
open set filter topological_space measure_theory function
open_locale classical topology interval big_operators filter ennreal nnreal measure_theory

variables {α β E F : Type*} [measurable_space α]

namespace measure_theory

section normed_add_comm_group

variables [normed_add_comm_group E]  {f g : α → E} {s t : set α} {μ ν : measure α}
  {l l' : filter α}

variables [complete_space E] [normed_space ℝ E]

lemma set_integral_congr_ae₀ (hs : null_measurable_set s μ) (h : ∀ᵐ x ∂μ, x ∈ s → f x = g x) :
  ∫ x in s, f x ∂μ = ∫ x in s, g x ∂μ :=
integral_congr_ae ((ae_restrict_iff'₀ hs).2 h)

lemma set_integral_congr_ae (hs : measurable_set s) (h : ∀ᵐ x ∂μ, x ∈ s → f x = g x) :
  ∫ x in s, f x ∂μ = ∫ x in s, g x ∂μ :=
integral_congr_ae ((ae_restrict_iff' hs).2 h)

lemma set_integral_congr₀ (hs : null_measurable_set s μ) (h : eq_on f g s) :
  ∫ x in s, f x ∂μ = ∫ x in s, g x ∂μ :=
set_integral_congr_ae₀ hs $ eventually_of_forall h

lemma set_integral_congr (hs : measurable_set s) (h : eq_on f g s) :
  ∫ x in s, f x ∂μ = ∫ x in s, g x ∂μ :=
set_integral_congr_ae hs $ eventually_of_forall h

lemma set_integral_congr_set_ae (hst : s =ᵐ[μ] t) :
  ∫ x in s, f x ∂μ = ∫ x in t, f x ∂μ :=
by rw measure.restrict_congr_set hst

lemma integral_union_ae (hst : ae_disjoint μ s t) (ht : null_measurable_set t μ)
  (hfs : integrable_on f s μ) (hft : integrable_on f t μ) :
  ∫ x in s ∪ t, f x ∂μ = ∫ x in s, f x ∂μ + ∫ x in t, f x ∂μ :=
by simp only [integrable_on, measure.restrict_union₀ hst ht, integral_add_measure hfs hft]

lemma integral_diff (ht : measurable_set t) (hfs : integrable_on f s μ) (hts : t ⊆ s) :
  ∫ x in s \ t, f x ∂μ = ∫ x in s, f x ∂μ - ∫ x in t, f x ∂μ :=
begin
  rw [eq_sub_iff_add_eq, ← integral_union, diff_union_of_subset hts],
  exacts [disjoint_sdiff_self_left, ht, hfs.mono_set (diff_subset _ _), hfs.mono_set hts]
end

lemma integral_inter_add_diff₀ (ht : null_measurable_set t μ) (hfs : integrable_on f s μ) :
  ∫ x in s ∩ t, f x ∂μ + ∫ x in s \ t, f x ∂μ = ∫ x in s, f x ∂μ :=
begin
  rw [← measure.restrict_inter_add_diff₀ s ht, integral_add_measure],
  { exact integrable.mono_measure hfs (measure.restrict_mono (inter_subset_left _ _) le_rfl) },
  { exact integrable.mono_measure hfs (measure.restrict_mono (diff_subset _ _) le_rfl) }
end

lemma integral_inter_add_diff (ht : measurable_set t) (hfs : integrable_on f s μ) :
  ∫ x in s ∩ t, f x ∂μ + ∫ x in s \ t, f x ∂μ = ∫ x in s, f x ∂μ :=
integral_inter_add_diff₀ ht.null_measurable_set hfs

lemma integral_finset_bUnion {ι : Type*} (t : finset ι) {s : ι → set α}
  (hs : ∀ i ∈ t, measurable_set (s i)) (h's : set.pairwise ↑t (disjoint on s))
  (hf : ∀ i ∈ t, integrable_on f (s i) μ) :
  ∫ x in (⋃ i ∈ t, s i), f x ∂ μ = ∑ i in t, ∫ x in s i, f x ∂ μ :=
begin
  induction t using finset.induction_on with a t hat IH hs h's,
  { simp },
  { simp only [finset.coe_insert, finset.forall_mem_insert, set.pairwise_insert,
      finset.set_bUnion_insert] at hs hf h's ⊢,
    rw [integral_union _ _ hf.1 (integrable_on_finset_Union.2 hf.2)],
    { rw [finset.sum_insert hat, IH hs.2 h's.1 hf.2] },
    { simp only [disjoint_Union_right],
      exact (λ i hi, (h's.2 i hi (ne_of_mem_of_not_mem hi hat).symm).1) },
    { exact finset.measurable_set_bUnion _ hs.2 } }
end

lemma integral_fintype_Union {ι : Type*} [fintype ι] {s : ι → set α}
  (hs : ∀ i, measurable_set (s i)) (h's : pairwise (disjoint on s))
  (hf : ∀ i, integrable_on f (s i) μ) :
  ∫ x in (⋃ i, s i), f x ∂ μ = ∑ i, ∫ x in s i, f x ∂ μ :=
begin
  convert integral_finset_bUnion finset.univ (λ i hi, hs i) _ (λ i _, hf i),
  { simp },
  { simp [pairwise_univ, h's] }
end

lemma integral_empty : ∫ x in ∅, f x ∂μ = 0 := by rw [measure.restrict_empty, integral_zero_measure]

lemma integral_univ : ∫ x in univ, f x ∂μ = ∫ x, f x ∂μ := by rw [measure.restrict_univ]

lemma integral_add_compl₀ (hs : null_measurable_set s μ) (hfi : integrable f μ) :
  ∫ x in s, f x ∂μ + ∫ x in sᶜ, f x ∂μ = ∫ x, f x ∂μ :=
by rw [← integral_union_ae (@disjoint_compl_right (set α) _ _).ae_disjoint hs.compl
    hfi.integrable_on hfi.integrable_on, union_compl_self, integral_univ]

lemma integral_add_compl (hs : measurable_set s) (hfi : integrable f μ) :
  ∫ x in s, f x ∂μ + ∫ x in sᶜ, f x ∂μ = ∫ x, f x ∂μ :=
integral_add_compl₀ hs.null_measurable_set hfi

/-- For a function `f` and a measurable set `s`, the integral of `indicator s f`
over the whole space is equal to `∫ x in s, f x ∂μ` defined as `∫ x, f x ∂(μ.restrict s)`. -/
lemma integral_indicator (hs : measurable_set s) :
  ∫ x, indicator s f x ∂μ = ∫ x in s, f x ∂μ :=
begin
  by_cases hfi : integrable_on f s μ, swap,
  { rwa [integral_undef, integral_undef],
    rwa integrable_indicator_iff hs },
  calc ∫ x, indicator s f x ∂μ = ∫ x in s, indicator s f x ∂μ + ∫ x in sᶜ, indicator s f x ∂μ :
    (integral_add_compl hs (hfi.integrable_indicator hs)).symm
  ... = ∫ x in s, f x ∂μ + ∫ x in sᶜ, 0 ∂μ :
    congr_arg2 (+) (integral_congr_ae (indicator_ae_eq_restrict hs))
      (integral_congr_ae (indicator_ae_eq_restrict_compl hs))
  ... = ∫ x in s, f x ∂μ : by simp
end

lemma set_integral_indicator (ht : measurable_set t) :
  ∫ x in s, t.indicator f x ∂μ = ∫ x in s ∩ t, f x ∂μ :=
by rw [integral_indicator ht, measure.restrict_restrict ht, set.inter_comm]

lemma of_real_set_integral_one_of_measure_ne_top {α : Type*} {m : measurable_space α}
  {μ : measure α} {s : set α} (hs : μ s ≠ ∞) :
  ennreal.of_real (∫ x in s, (1 : ℝ) ∂μ) = μ s :=
calc
ennreal.of_real (∫ x in s, (1 : ℝ) ∂μ)
    = ennreal.of_real (∫ x in s, ‖(1 : ℝ)‖ ∂μ) : by simp only [norm_one]
... = ∫⁻ x in s, 1 ∂μ :
begin
  rw of_real_integral_norm_eq_lintegral_nnnorm (integrable_on_const.2 (or.inr hs.lt_top)),
  simp only [nnnorm_one, ennreal.coe_one],
end
... = μ s : set_lintegral_one _

lemma of_real_set_integral_one {α : Type*} {m : measurable_space α} (μ : measure α)
  [is_finite_measure μ] (s : set α) :
  ennreal.of_real (∫ x in s, (1 : ℝ) ∂μ) = μ s :=
of_real_set_integral_one_of_measure_ne_top (measure_ne_top μ s)

lemma integral_piecewise [decidable_pred (∈ s)] (hs : measurable_set s)
  (hf : integrable_on f s μ) (hg : integrable_on g sᶜ μ) :
  ∫ x, s.piecewise f g x ∂μ = ∫ x in s, f x ∂μ + ∫ x in sᶜ, g x ∂μ :=
by rw [← set.indicator_add_compl_eq_piecewise,
  integral_add' (hf.integrable_indicator hs) (hg.integrable_indicator hs.compl),
  integral_indicator hs, integral_indicator hs.compl]

lemma tendsto_set_integral_of_monotone {ι : Type*} [countable ι] [semilattice_sup ι]
  {s : ι → set α} (hsm : ∀ i, measurable_set (s i))
  (h_mono : monotone s) (hfi : integrable_on f (⋃ n, s n) μ) :
  tendsto (λ i, ∫ a in s i, f a ∂μ) at_top (𝓝 (∫ a in (⋃ n, s n), f a ∂μ)) :=
begin
  have hfi' : ∫⁻ x in ⋃ n, s n, ‖f x‖₊ ∂μ < ∞ := hfi.2,
  set S := ⋃ i, s i,
  have hSm : measurable_set S := measurable_set.Union hsm,
  have hsub : ∀ {i}, s i ⊆ S, from subset_Union s,
  rw [← with_density_apply _ hSm] at hfi',
  set ν := μ.with_density (λ x, ‖f x‖₊) with hν,
  refine metric.nhds_basis_closed_ball.tendsto_right_iff.2 (λ ε ε0, _),
  lift ε to ℝ≥0 using ε0.le,
  have : ∀ᶠ i in at_top, ν (s i) ∈ Icc (ν S - ε) (ν S + ε),
    from tendsto_measure_Union h_mono (ennreal.Icc_mem_nhds hfi'.ne (ennreal.coe_pos.2 ε0).ne'),
  refine this.mono (λ i hi, _),
  rw [mem_closed_ball_iff_norm', ← integral_diff (hsm i) hfi hsub,
    ← coe_nnnorm, nnreal.coe_le_coe, ← ennreal.coe_le_coe],
  refine (ennnorm_integral_le_lintegral_ennnorm _).trans _,
  rw [← with_density_apply _ (hSm.diff (hsm _)), ← hν, measure_diff hsub (hsm _)],
  exacts [tsub_le_iff_tsub_le.mp hi.1,
    (hi.2.trans_lt $ ennreal.add_lt_top.2 ⟨hfi', ennreal.coe_lt_top⟩).ne]
end

lemma has_sum_integral_Union_ae {ι : Type*} [countable ι] {s : ι → set α}
  (hm : ∀ i, null_measurable_set (s i) μ) (hd : pairwise (ae_disjoint μ on s))
  (hfi : integrable_on f (⋃ i, s i) μ) :
  has_sum (λ n, ∫ a in s n, f a ∂ μ) (∫ a in ⋃ n, s n, f a ∂μ) :=
begin
  simp only [integrable_on, measure.restrict_Union_ae hd hm] at hfi ⊢,
  exact has_sum_integral_measure hfi
end

lemma has_sum_integral_Union {ι : Type*} [countable ι] {s : ι → set α}
  (hm : ∀ i, measurable_set (s i)) (hd : pairwise (disjoint on s))
  (hfi : integrable_on f (⋃ i, s i) μ) :
  has_sum (λ n, ∫ a in s n, f a ∂ μ) (∫ a in ⋃ n, s n, f a ∂μ) :=
has_sum_integral_Union_ae (λ i, (hm i).null_measurable_set) (hd.mono (λ i j h, h.ae_disjoint)) hfi

lemma integral_Union {ι : Type*} [countable ι] {s : ι → set α}
  (hm : ∀ i, measurable_set (s i)) (hd : pairwise (disjoint on s))
  (hfi : integrable_on f (⋃ i, s i) μ) :
  (∫ a in (⋃ n, s n), f a ∂μ) = ∑' n, ∫ a in s n, f a ∂ μ :=
(has_sum.tsum_eq (has_sum_integral_Union hm hd hfi)).symm

lemma integral_Union_ae {ι : Type*} [countable ι] {s : ι → set α}
  (hm : ∀ i, null_measurable_set (s i) μ) (hd : pairwise (ae_disjoint μ on s))
  (hfi : integrable_on f (⋃ i, s i) μ) :
  (∫ a in (⋃ n, s n), f a ∂μ) = ∑' n, ∫ a in s n, f a ∂ μ :=
(has_sum.tsum_eq (has_sum_integral_Union_ae hm hd hfi)).symm

lemma set_integral_eq_zero_of_ae_eq_zero (ht_eq : ∀ᵐ x ∂μ, x ∈ t → f x = 0) :
  ∫ x in t, f x ∂μ = 0 :=
begin
  by_cases hf : ae_strongly_measurable f (μ.restrict t), swap,
  { rw integral_undef,
    contrapose! hf,
    exact hf.1 },
  have : ∫ x in t, hf.mk f x ∂μ = 0,
  { refine integral_eq_zero_of_ae _,
    rw [eventually_eq, ae_restrict_iff
      (hf.strongly_measurable_mk.measurable_set_eq_fun strongly_measurable_zero)],
    filter_upwards [ae_imp_of_ae_restrict hf.ae_eq_mk, ht_eq] with x hx h'x h''x,
    rw ← hx h''x,
    exact h'x h''x },
  rw ← this,
  exact integral_congr_ae hf.ae_eq_mk,
end

lemma set_integral_eq_zero_of_forall_eq_zero (ht_eq : ∀ x ∈ t, f x = 0) :
  ∫ x in t, f x ∂μ = 0 :=
set_integral_eq_zero_of_ae_eq_zero (eventually_of_forall ht_eq)

lemma integral_union_eq_left_of_ae_aux (ht_eq : ∀ᵐ x ∂(μ.restrict t), f x = 0)
  (haux : strongly_measurable f) (H : integrable_on f (s ∪ t) μ) :
  ∫ x in (s ∪ t), f x ∂μ = ∫ x in s, f x ∂μ :=
begin
  let k := f ⁻¹' {0},
  have hk : measurable_set k,
  { borelize E, exact haux.measurable (measurable_set_singleton _) },
  have h's : integrable_on f s μ := H.mono (subset_union_left _ _) le_rfl,
  have A : ∀ (u : set α), ∫ x in u ∩ k, f x ∂μ = 0 :=
    λ u, set_integral_eq_zero_of_forall_eq_zero (λ x hx, hx.2),
  rw [← integral_inter_add_diff hk h's, ← integral_inter_add_diff hk H, A, A, zero_add, zero_add,
    union_diff_distrib, union_comm],
  apply set_integral_congr_set_ae,
  rw union_ae_eq_right,
  apply measure_mono_null (diff_subset _ _),
  rw measure_zero_iff_ae_nmem,
  filter_upwards [ae_imp_of_ae_restrict ht_eq] with x hx h'x using h'x.2 (hx h'x.1),
end

lemma integral_union_eq_left_of_ae (ht_eq : ∀ᵐ x ∂(μ.restrict t), f x = 0) :
  ∫ x in (s ∪ t), f x ∂μ = ∫ x in s, f x ∂μ :=
begin
  have ht : integrable_on f t μ,
  { apply integrable_on.congr_fun' integrable_on_zero, symmetry, exact ht_eq },
  by_cases H : integrable_on f (s ∪ t) μ, swap,
  { rw [integral_undef H, integral_undef], simpa [integrable_on_union, ht] using H },
  let f' := H.1.mk f,
  calc ∫ (x : α) in s ∪ t, f x ∂μ
      = ∫ (x : α) in s ∪ t, f' x ∂μ : integral_congr_ae H.1.ae_eq_mk
  ... = ∫ x in s, f' x ∂μ :
    begin
      apply integral_union_eq_left_of_ae_aux _ H.1.strongly_measurable_mk
        (H.congr_fun' H.1.ae_eq_mk),
      filter_upwards [ht_eq, ae_mono (measure.restrict_mono (subset_union_right s t) le_rfl)
        H.1.ae_eq_mk] with x hx h'x,
      rw [← h'x, hx]
    end
  ... = ∫ x in s, f x ∂μ : integral_congr_ae
    (ae_mono (measure.restrict_mono (subset_union_left s t) le_rfl) H.1.ae_eq_mk.symm)
end

lemma integral_union_eq_left_of_forall₀ {f : α → E}
  (ht : null_measurable_set t μ) (ht_eq : ∀ x ∈ t, f x = 0) :
  ∫ x in (s ∪ t), f x ∂μ = ∫ x in s, f x ∂μ :=
integral_union_eq_left_of_ae ((ae_restrict_iff'₀ ht).2 (eventually_of_forall ht_eq))

lemma integral_union_eq_left_of_forall {f : α → E}
  (ht : measurable_set t) (ht_eq : ∀ x ∈ t, f x = 0) :
  ∫ x in (s ∪ t), f x ∂μ = ∫ x in s, f x ∂μ :=
integral_union_eq_left_of_forall₀ ht.null_measurable_set ht_eq

lemma set_integral_eq_of_subset_of_ae_diff_eq_zero_aux
  (hts : s ⊆ t) (h't : ∀ᵐ x ∂μ, x ∈ t \ s → f x = 0)
  (haux : strongly_measurable f) (h'aux : integrable_on f t μ) :
  ∫ x in t, f x ∂μ = ∫ x in s, f x ∂μ :=
begin
  let k := f ⁻¹' {0},
  have hk : measurable_set k,
  { borelize E, exact haux.measurable (measurable_set_singleton _) },
  calc
  ∫ x in t, f x ∂μ
      = ∫ x in t ∩ k, f x ∂μ + ∫ x in t \ k, f x ∂μ :
    by rw integral_inter_add_diff hk h'aux
  ... = ∫ x in t \ k, f x ∂μ :
    by { rw [set_integral_eq_zero_of_forall_eq_zero (λ x hx, _), zero_add], exact hx.2 }
  ... = ∫ x in s \ k, f x ∂μ :
    begin
      apply set_integral_congr_set_ae,
      filter_upwards [h't] with x hx,
      change (x ∈ t \ k) = (x ∈ s \ k),
      simp only [mem_preimage, mem_singleton_iff, eq_iff_iff, and.congr_left_iff, mem_diff],
      assume h'x,
      by_cases xs : x ∈ s,
      { simp only [xs, hts xs] },
      { simp only [xs, iff_false],
        assume xt,
        exact h'x (hx ⟨xt, xs⟩) }
    end
  ... = ∫ x in s ∩ k, f x ∂μ + ∫ x in s \ k, f x ∂μ :
    begin
      have : ∀ x ∈ s ∩ k, f x = 0 := λ x hx, hx.2,
      rw [set_integral_eq_zero_of_forall_eq_zero this, zero_add],
    end
  ... = ∫ x in s, f x ∂μ : by rw integral_inter_add_diff hk (h'aux.mono hts le_rfl)
end

/-- If a function vanishes almost everywhere on `t \ s` with `s ⊆ t`, then its integrals on `s`
and `t` coincide if `t` is null-measurable. -/
lemma set_integral_eq_of_subset_of_ae_diff_eq_zero
  (ht : null_measurable_set t μ) (hts : s ⊆ t) (h't : ∀ᵐ x ∂μ, x ∈ t \ s → f x = 0) :
  ∫ x in t, f x ∂μ = ∫ x in s, f x ∂μ :=
begin
  by_cases h : integrable_on f t μ, swap,
  { have : ¬(integrable_on f s μ) := λ H, h (H.of_ae_diff_eq_zero ht h't),
    rw [integral_undef h, integral_undef this] },
  let f' := h.1.mk f,
  calc ∫ x in t, f x ∂μ
      = ∫ x in t, f' x ∂μ : integral_congr_ae h.1.ae_eq_mk
  ... = ∫ x in s, f' x ∂μ :
    begin
      apply set_integral_eq_of_subset_of_ae_diff_eq_zero_aux hts _ h.1.strongly_measurable_mk
        (h.congr h.1.ae_eq_mk),
      filter_upwards [h't, ae_imp_of_ae_restrict h.1.ae_eq_mk] with x hx h'x h''x,
      rw [← h'x h''x.1, hx h''x]
    end
  ... = ∫ x in s, f x ∂μ :
    begin
      apply integral_congr_ae,
      apply ae_restrict_of_ae_restrict_of_subset hts,
      exact h.1.ae_eq_mk.symm
    end
end

/-- If a function vanishes on `t \ s` with `s ⊆ t`, then its integrals on `s`
and `t` coincide if `t` is measurable. -/
lemma set_integral_eq_of_subset_of_forall_diff_eq_zero
  (ht : measurable_set t) (hts : s ⊆ t) (h't : ∀ x ∈ t \ s, f x = 0) :
  ∫ x in t, f x ∂μ = ∫ x in s, f x ∂μ :=
set_integral_eq_of_subset_of_ae_diff_eq_zero ht.null_measurable_set hts
  (eventually_of_forall (λ x hx, h't x hx))

/-- If a function vanishes almost everywhere on `sᶜ`, then its integral on `s`
coincides with its integral on the whole space. -/
lemma set_integral_eq_integral_of_ae_compl_eq_zero
  (h : ∀ᵐ x ∂μ, x ∉ s → f x = 0) : ∫ x in s, f x ∂μ = ∫ x, f x ∂μ :=
begin
  conv_rhs { rw ← integral_univ },
  symmetry,
  apply set_integral_eq_of_subset_of_ae_diff_eq_zero null_measurable_set_univ (subset_univ _),
  filter_upwards [h] with x hx h'x using hx h'x.2,
end

/-- If a function vanishes on `sᶜ`, then its integral on `s` coincides with its integral on the
whole space. -/
lemma set_integral_eq_integral_of_forall_compl_eq_zero
  (h : ∀ x, x ∉ s → f x = 0) : ∫ x in s, f x ∂μ = ∫ x, f x ∂μ :=
set_integral_eq_integral_of_ae_compl_eq_zero (eventually_of_forall h)

lemma set_integral_neg_eq_set_integral_nonpos [linear_order E]
  {f : α → E} (hf : ae_strongly_measurable f μ) :
  ∫ x in {x | f x < 0}, f x ∂μ = ∫ x in {x | f x ≤ 0}, f x ∂μ :=
begin
  have h_union : {x | f x ≤ 0} = {x | f x < 0} ∪ {x | f x = 0},
    by { ext, simp_rw [set.mem_union, set.mem_set_of_eq], exact le_iff_lt_or_eq, },
  rw h_union,
  have B : null_measurable_set {x | f x = 0} μ,
    from hf.null_measurable_set_eq_fun ae_strongly_measurable_zero,
  symmetry,
  refine integral_union_eq_left_of_ae _,
  filter_upwards [ae_restrict_mem₀ B] with x hx using hx,
end

lemma integral_norm_eq_pos_sub_neg {f : α → ℝ} (hfi : integrable f μ) :
  ∫ x, ‖f x‖ ∂μ = ∫ x in {x | 0 ≤ f x}, f x ∂μ - ∫ x in {x | f x ≤ 0}, f x ∂μ :=
have h_meas : null_measurable_set {x | 0 ≤ f x} μ,
  from ae_strongly_measurable_const.null_measurable_set_le hfi.1,
calc ∫ x, ‖f x‖ ∂μ = ∫ x in {x | 0 ≤ f x}, ‖f x‖ ∂μ + ∫ x in {x | 0 ≤ f x}ᶜ, ‖f x‖ ∂μ :
  by rw ← integral_add_compl₀ h_meas hfi.norm
... = ∫ x in {x | 0 ≤ f x}, f x ∂μ + ∫ x in {x | 0 ≤ f x}ᶜ, ‖f x‖ ∂μ :
begin
  congr' 1,
  refine set_integral_congr₀ h_meas (λ x hx, _),
  dsimp only,
  rw [real.norm_eq_abs, abs_eq_self.mpr _],
  exact hx,
end
... = ∫ x in {x | 0 ≤ f x}, f x ∂μ - ∫ x in {x | 0 ≤ f x}ᶜ, f x ∂μ :
begin
  congr' 1,
  rw ← integral_neg,
  refine set_integral_congr₀ h_meas.compl (λ x hx, _),
  dsimp only,
  rw [real.norm_eq_abs, abs_eq_neg_self.mpr _],
  rw [set.mem_compl_iff, set.nmem_set_of_iff] at hx,
  linarith,
end
... = ∫ x in {x | 0 ≤ f x}, f x ∂μ - ∫ x in {x | f x ≤ 0}, f x ∂μ :
by { rw ← set_integral_neg_eq_set_integral_nonpos hfi.1, congr, ext1 x, simp, }

lemma set_integral_const (c : E) : ∫ x in s, c ∂μ = (μ s).to_real • c :=
by rw [integral_const, measure.restrict_apply_univ]

@[simp]
lemma integral_indicator_const (e : E) ⦃s : set α⦄ (s_meas : measurable_set s) :
  ∫ (a : α), s.indicator (λ (x : α), e) a ∂μ = (μ s).to_real • e :=
by rw [integral_indicator s_meas, ← set_integral_const]

@[simp]
lemma integral_indicator_one ⦃s : set α⦄ (hs : measurable_set s) :
  ∫ a, s.indicator 1 a ∂μ = (μ s).to_real :=
(integral_indicator_const 1 hs).trans ((smul_eq_mul _).trans (mul_one _))

lemma set_integral_indicator_const_Lp {p : ℝ≥0∞} (hs : measurable_set s) (ht : measurable_set t)
  (hμt : μ t ≠ ∞) (x : E) :
  ∫ a in s, indicator_const_Lp p ht hμt x a ∂μ = (μ (t ∩ s)).to_real • x :=
calc ∫ a in s, indicator_const_Lp p ht hμt x a ∂μ
    = (∫ a in s, t.indicator (λ _, x) a ∂μ) :
  by rw set_integral_congr_ae hs (indicator_const_Lp_coe_fn.mono (λ x hx hxs, hx))
... = (μ (t ∩ s)).to_real • x : by rw [integral_indicator_const _ ht, measure.restrict_apply ht]

lemma integral_indicator_const_Lp {p : ℝ≥0∞} (ht : measurable_set t) (hμt : μ t ≠ ∞) (x : E) :
  ∫ a, indicator_const_Lp p ht hμt x a ∂μ = (μ t).to_real • x :=
calc ∫ a, indicator_const_Lp p ht hμt x a ∂μ
    = ∫ a in univ, indicator_const_Lp p ht hμt x a ∂μ : by rw integral_univ
... = (μ (t ∩ univ)).to_real • x : set_integral_indicator_const_Lp measurable_set.univ ht hμt x
... = (μ t).to_real • x : by rw inter_univ

lemma set_integral_map {β} [measurable_space β] {g : α → β} {f : β → E} {s : set β}
  (hs : measurable_set s)
  (hf : ae_strongly_measurable f (measure.map g μ)) (hg : ae_measurable g μ) :
  ∫ y in s, f y ∂(measure.map g μ) = ∫ x in g ⁻¹' s, f (g x) ∂μ :=
begin
  rw [measure.restrict_map_of_ae_measurable hg hs,
      integral_map (hg.mono_measure measure.restrict_le_self) (hf.mono_measure _)],
  exact measure.map_mono_of_ae_measurable measure.restrict_le_self hg
end

lemma _root_.measurable_embedding.set_integral_map {β} {_ : measurable_space β} {f : α → β}
  (hf : measurable_embedding f) (g : β → E) (s : set β) :
  ∫ y in s, g y ∂(measure.map f μ) = ∫ x in f ⁻¹' s, g (f x) ∂μ :=
by rw [hf.restrict_map, hf.integral_map]

lemma _root_.closed_embedding.set_integral_map [topological_space α] [borel_space α]
  {β} [measurable_space β] [topological_space β] [borel_space β]
  {g : α → β} {f : β → E} (s : set β) (hg : closed_embedding g) :
  ∫ y in s, f y ∂(measure.map g μ) = ∫ x in g ⁻¹' s, f (g x) ∂μ :=
hg.measurable_embedding.set_integral_map _ _

lemma measure_preserving.set_integral_preimage_emb {β} {_ : measurable_space β} {f : α → β} {ν}
  (h₁ : measure_preserving f μ ν) (h₂ : measurable_embedding f) (g : β → E) (s : set β) :
  ∫ x in f ⁻¹' s, g (f x) ∂μ = ∫ y in s, g y ∂ν :=
(h₁.restrict_preimage_emb h₂ s).integral_comp h₂ _

lemma measure_preserving.set_integral_image_emb {β} {_ : measurable_space β} {f : α → β} {ν}
  (h₁ : measure_preserving f μ ν) (h₂ : measurable_embedding f) (g : β → E) (s : set α) :
  ∫ y in f '' s, g y ∂ν = ∫ x in s, g (f x) ∂μ :=
eq.symm $ (h₁.restrict_image_emb h₂ s).integral_comp h₂ _

lemma set_integral_map_equiv {β} [measurable_space β] (e : α ≃ᵐ β) (f : β → E) (s : set β) :
  ∫ y in s, f y ∂(measure.map e μ) = ∫ x in e ⁻¹' s, f (e x) ∂μ :=
e.measurable_embedding.set_integral_map f s

lemma norm_set_integral_le_of_norm_le_const_ae {C : ℝ} (hs : μ s < ∞)
  (hC : ∀ᵐ x ∂μ.restrict s, ‖f x‖ ≤ C) :
  ‖∫ x in s, f x ∂μ‖ ≤ C * (μ s).to_real :=
begin
  rw ← measure.restrict_apply_univ at *,
  haveI : is_finite_measure (μ.restrict s) := ⟨‹_›⟩,
  exact norm_integral_le_of_norm_le_const hC
end

lemma norm_set_integral_le_of_norm_le_const_ae' {C : ℝ} (hs : μ s < ∞)
  (hC : ∀ᵐ x ∂μ, x ∈ s → ‖f x‖ ≤ C) (hfm : ae_strongly_measurable f (μ.restrict s)) :
  ‖∫ x in s, f x ∂μ‖ ≤ C * (μ s).to_real :=
begin
  apply norm_set_integral_le_of_norm_le_const_ae hs,
  have A : ∀ᵐ (x : α) ∂μ, x ∈ s → ‖ae_strongly_measurable.mk f hfm x‖ ≤ C,
  { filter_upwards [hC, hfm.ae_mem_imp_eq_mk] with _ h1 h2 h3,
    rw [← h2 h3],
    exact h1 h3 },
  have B : measurable_set {x | ‖(hfm.mk f) x‖ ≤ C} :=
    hfm.strongly_measurable_mk.norm.measurable measurable_set_Iic,
  filter_upwards [hfm.ae_eq_mk, (ae_restrict_iff B).2 A] with _ h1 _,
  rwa h1,
end

lemma norm_set_integral_le_of_norm_le_const_ae'' {C : ℝ} (hs : μ s < ∞) (hsm : measurable_set s)
  (hC : ∀ᵐ x ∂μ, x ∈ s → ‖f x‖ ≤ C) :
  ‖∫ x in s, f x ∂μ‖ ≤ C * (μ s).to_real :=
norm_set_integral_le_of_norm_le_const_ae hs $ by rwa [ae_restrict_eq hsm, eventually_inf_principal]

lemma norm_set_integral_le_of_norm_le_const {C : ℝ} (hs : μ s < ∞)
  (hC : ∀ x ∈ s, ‖f x‖ ≤ C) (hfm : ae_strongly_measurable f (μ.restrict s)) :
  ‖∫ x in s, f x ∂μ‖ ≤ C * (μ s).to_real :=
norm_set_integral_le_of_norm_le_const_ae' hs (eventually_of_forall hC) hfm

lemma norm_set_integral_le_of_norm_le_const' {C : ℝ} (hs : μ s < ∞) (hsm : measurable_set s)
  (hC : ∀ x ∈ s, ‖f x‖ ≤ C) :
  ‖∫ x in s, f x ∂μ‖ ≤ C * (μ s).to_real :=
norm_set_integral_le_of_norm_le_const_ae'' hs hsm $ eventually_of_forall hC

lemma set_integral_eq_zero_iff_of_nonneg_ae {f : α → ℝ} (hf : 0 ≤ᵐ[μ.restrict s] f)
  (hfi : integrable_on f s μ) :
  ∫ x in s, f x ∂μ = 0 ↔ f =ᵐ[μ.restrict s] 0 :=
integral_eq_zero_iff_of_nonneg_ae hf hfi

lemma set_integral_pos_iff_support_of_nonneg_ae {f : α → ℝ} (hf : 0 ≤ᵐ[μ.restrict s] f)
  (hfi : integrable_on f s μ) :
  0 < ∫ x in s, f x ∂μ ↔ 0 < μ (support f ∩ s) :=
begin
  rw [integral_pos_iff_support_of_nonneg_ae hf hfi, measure.restrict_apply₀],
  rw support_eq_preimage,
  exact hfi.ae_strongly_measurable.ae_measurable.null_measurable (measurable_set_singleton 0).compl
end

lemma set_integral_gt_gt {R : ℝ} {f : α → ℝ} (hR : 0 ≤ R) (hfm : measurable f)
  (hfint : integrable_on f {x | ↑R < f x} μ) (hμ : μ {x | ↑R < f x} ≠ 0):
  (μ {x | ↑R < f x}).to_real * R < ∫ x in {x | ↑R < f x}, f x ∂μ :=
begin
  have : integrable_on (λ x, R) {x | ↑R < f x} μ,
  { refine ⟨ae_strongly_measurable_const, lt_of_le_of_lt _ hfint.2⟩,
    refine set_lintegral_mono (measurable.nnnorm _).coe_nnreal_ennreal
      hfm.nnnorm.coe_nnreal_ennreal (λ x hx, _),
    { exact measurable_const },
    { simp only [ennreal.coe_le_coe, real.nnnorm_of_nonneg hR,
        real.nnnorm_of_nonneg (hR.trans $ le_of_lt hx), subtype.mk_le_mk],
      exact le_of_lt hx } },
  rw [← sub_pos, ← smul_eq_mul, ← set_integral_const, ← integral_sub hfint this,
    set_integral_pos_iff_support_of_nonneg_ae],
  { rw ← zero_lt_iff at hμ,
    rwa set.inter_eq_self_of_subset_right,
    exact λ x hx, ne.symm (ne_of_lt $ sub_pos.2 hx) },
  { change ∀ᵐ x ∂(μ.restrict _), _,
    rw ae_restrict_iff,
    { exact eventually_of_forall (λ x hx, sub_nonneg.2 $ le_of_lt hx) },
    { exact measurable_set_le measurable_zero (hfm.sub measurable_const) } },
  { exact integrable.sub hfint this },
end

lemma set_integral_trim {α} {m m0 : measurable_space α} {μ : measure α} (hm : m ≤ m0) {f : α → E}
  (hf_meas : strongly_measurable[m] f) {s : set α} (hs : measurable_set[m] s) :
  ∫ x in s, f x ∂μ = ∫ x in s, f x ∂(μ.trim hm) :=
by rwa [integral_trim hm hf_meas, restrict_trim hm μ]

lemma integral_Icc_eq_integral_Ioc' [partial_order α] {f : α → E} {a b : α} (ha : μ {a} = 0) :
  ∫ t in Icc a b, f t ∂μ = ∫ t in Ioc a b, f t ∂μ :=
set_integral_congr_set_ae (Ioc_ae_eq_Icc' ha).symm

lemma integral_Ioc_eq_integral_Ioo' [partial_order α] {f : α → E} {a b : α} (hb : μ {b} = 0) :
  ∫ t in Ioc a b, f t ∂μ = ∫ t in Ioo a b, f t ∂μ :=
set_integral_congr_set_ae (Ioo_ae_eq_Ioc' hb).symm

lemma integral_Icc_eq_integral_Ioc [partial_order α] {f : α → E} {a b : α} [has_no_atoms μ] :
  ∫ t in Icc a b, f t ∂μ = ∫ t in Ioc a b, f t ∂μ :=
integral_Icc_eq_integral_Ioc' $ measure_singleton a

lemma integral_Ioc_eq_integral_Ioo [partial_order α] {f : α → E} {a b : α} [has_no_atoms μ] :
  ∫ t in Ioc a b, f t ∂μ = ∫ t in Ioo a b, f t ∂μ :=
integral_Ioc_eq_integral_Ioo' $ measure_singleton b

end normed_add_comm_group

section mono

variables {μ : measure α} {f g : α → ℝ} {s t : set α}
  (hf : integrable_on f s μ) (hg : integrable_on g s μ)

lemma set_integral_mono_ae_restrict (h : f ≤ᵐ[μ.restrict s] g) :
  ∫ a in s, f a ∂μ ≤ ∫ a in s, g a ∂μ :=
integral_mono_ae hf hg h

lemma set_integral_mono_ae (h : f ≤ᵐ[μ] g) :
  ∫ a in s, f a ∂μ ≤ ∫ a in s, g a ∂μ :=
set_integral_mono_ae_restrict hf hg (ae_restrict_of_ae h)

lemma set_integral_mono_on (hs : measurable_set s) (h : ∀ x ∈ s, f x ≤ g x) :
  ∫ a in s, f a ∂μ ≤ ∫ a in s, g a ∂μ :=
set_integral_mono_ae_restrict hf hg
  (by simp [hs, eventually_le, eventually_inf_principal, ae_of_all _ h])

include hf hg  -- why do I need this include, but we don't need it in other lemmas?
lemma set_integral_mono_on_ae (hs : measurable_set s) (h : ∀ᵐ x ∂μ, x ∈ s → f x ≤ g x) :
  ∫ a in s, f a ∂μ ≤ ∫ a in s, g a ∂μ :=
by { refine set_integral_mono_ae_restrict hf hg _, rwa [eventually_le, ae_restrict_iff' hs], }
omit hf hg

lemma set_integral_mono (h : f ≤ g) :
  ∫ a in s, f a ∂μ ≤ ∫ a in s, g a ∂μ :=
integral_mono hf hg h

lemma set_integral_mono_set (hfi : integrable_on f t μ) (hf : 0 ≤ᵐ[μ.restrict t] f)
  (hst : s ≤ᵐ[μ] t) :
  ∫ x in s, f x ∂μ ≤ ∫ x in t, f x ∂μ :=
integral_mono_measure (measure.restrict_mono_ae hst) hf hfi

lemma set_integral_ge_of_const_le {c : ℝ} (hs : measurable_set s) (hμs : μ s ≠ ∞)
  (hf : ∀ x ∈ s, c ≤ f x) (hfint : integrable_on (λ (x : α), f x) s μ) :
  c * (μ s).to_real ≤ ∫ x in s, f x ∂μ :=
begin
  rw [mul_comm, ← smul_eq_mul, ← set_integral_const c],
  exact set_integral_mono_on (integrable_on_const.2 (or.inr hμs.lt_top)) hfint hs hf,
end

end mono

section nonneg

variables {μ : measure α} {f : α → ℝ} {s : set α}

lemma set_integral_nonneg_of_ae_restrict (hf : 0 ≤ᵐ[μ.restrict s] f) :
  0 ≤ ∫ a in s, f a ∂μ :=
integral_nonneg_of_ae hf

lemma set_integral_nonneg_of_ae (hf : 0 ≤ᵐ[μ] f) : 0 ≤ ∫ a in s, f a ∂μ :=
set_integral_nonneg_of_ae_restrict (ae_restrict_of_ae hf)

lemma set_integral_nonneg (hs : measurable_set s) (hf : ∀ a, a ∈ s → 0 ≤ f a) :
  0 ≤ ∫ a in s, f a ∂μ :=
set_integral_nonneg_of_ae_restrict ((ae_restrict_iff' hs).mpr (ae_of_all μ hf))

lemma set_integral_nonneg_ae (hs : measurable_set s) (hf : ∀ᵐ a ∂μ, a ∈ s → 0 ≤ f a) :
  0 ≤ ∫ a in s, f a ∂μ :=
set_integral_nonneg_of_ae_restrict $ by rwa [eventually_le, ae_restrict_iff' hs]

lemma set_integral_le_nonneg {s : set α} (hs : measurable_set s) (hf : strongly_measurable f)
  (hfi : integrable f μ) :
  ∫ x in s, f x ∂μ ≤ ∫ x in {y | 0 ≤ f y}, f x ∂μ :=
begin
  rw [← integral_indicator hs,
      ← integral_indicator (strongly_measurable_const.measurable_set_le hf)],
  exact integral_mono (hfi.indicator hs)
    (hfi.indicator (strongly_measurable_const.measurable_set_le hf))
    (indicator_le_indicator_nonneg s f),
end

lemma set_integral_nonpos_of_ae_restrict (hf : f ≤ᵐ[μ.restrict s] 0) :
  ∫ a in s, f a ∂μ ≤ 0 :=
integral_nonpos_of_ae hf

lemma set_integral_nonpos_of_ae (hf : f ≤ᵐ[μ] 0) : ∫ a in s, f a ∂μ ≤ 0 :=
set_integral_nonpos_of_ae_restrict (ae_restrict_of_ae hf)

lemma set_integral_nonpos (hs : measurable_set s) (hf : ∀ a, a ∈ s → f a ≤ 0) :
  ∫ a in s, f a ∂μ ≤ 0 :=
set_integral_nonpos_of_ae_restrict ((ae_restrict_iff' hs).mpr (ae_of_all μ hf))

lemma set_integral_nonpos_ae (hs : measurable_set s) (hf : ∀ᵐ a ∂μ, a ∈ s → f a ≤ 0) :
  ∫ a in s, f a ∂μ ≤ 0 :=
set_integral_nonpos_of_ae_restrict $ by rwa [eventually_le, ae_restrict_iff' hs]

lemma set_integral_nonpos_le {s : set α} (hs : measurable_set s) (hf : strongly_measurable f)
  (hfi : integrable f μ) :
  ∫ x in {y | f y ≤ 0}, f x ∂μ ≤ ∫ x in s, f x ∂μ :=
begin
  rw [← integral_indicator hs,
      ← integral_indicator (hf.measurable_set_le strongly_measurable_const)],
  exact integral_mono (hfi.indicator (hf.measurable_set_le strongly_measurable_const))
    (hfi.indicator hs) (indicator_nonpos_le_indicator s f),
end

end nonneg

section integrable_Union

variables {μ : measure α} [normed_add_comm_group E] [countable β]

lemma integrable_on_Union_of_summable_integral_norm {f : α → E} {s : β → set α}
  (hs : ∀ (b : β), measurable_set (s b)) (hi : ∀ (b : β), integrable_on f (s b) μ)
  (h : summable (λ (b : β), ∫ (a : α) in s b, ‖f a‖ ∂μ)) :
  integrable_on f (Union s) μ :=
begin
  refine ⟨ae_strongly_measurable.Union (λ i, (hi i).1), (lintegral_Union_le _ _).trans_lt _⟩,
  have B := λ (b : β), lintegral_coe_eq_integral (λ (a : α), ‖f a‖₊) (hi b).norm,
  rw tsum_congr B,
  have S' : summable (λ (b : β), (⟨∫ (a : α) in s b, ‖f a‖₊ ∂μ,
    set_integral_nonneg (hs b) (λ a ha, nnreal.coe_nonneg _)⟩ : nnreal)),
  { rw ←nnreal.summable_coe, exact h },
  have S'' := ennreal.tsum_coe_eq S'.has_sum,
  simp_rw [ennreal.coe_nnreal_eq, nnreal.coe_mk, coe_nnnorm] at S'',
  convert ennreal.of_real_lt_top,
end

variables [topological_space α] [borel_space α] [metrizable_space α] [is_locally_finite_measure μ]

/-- If `s` is a countable family of compact sets, `f` is a continuous function, and the sequence
`‖f.restrict (s i)‖ * μ (s i)` is summable, then `f` is integrable on the union of the `s i`. -/
lemma integrable_on_Union_of_summable_norm_restrict {f : C(α, E)} {s : β → compacts α}
  (hf : summable (λ i : β, ‖f.restrict (s i)‖ * ennreal.to_real (μ $ s i))) :
  integrable_on f (⋃ i : β, s i) μ :=
begin
  refine integrable_on_Union_of_summable_integral_norm
    (λ i, (s i).is_compact.is_closed.measurable_set)
    (λ i, (map_continuous f).continuous_on.integrable_on_compact (s i).is_compact)
    (summable_of_nonneg_of_le (λ ι, integral_nonneg (λ x, norm_nonneg _)) (λ i, _) hf),
  rw ←(real.norm_of_nonneg (integral_nonneg (λ a, norm_nonneg _)) : ‖_‖ = ∫ x in s i, ‖f x‖ ∂μ),
  exact norm_set_integral_le_of_norm_le_const' (s i).is_compact.measure_lt_top
    (s i).is_compact.is_closed.measurable_set
    (λ x hx, (norm_norm (f x)).symm ▸ (f.restrict ↑(s i)).norm_coe_le_norm ⟨x, hx⟩)
end

/-- If `s` is a countable family of compact sets covering `α`, `f` is a continuous function, and
the sequence `‖f.restrict (s i)‖ * μ (s i)` is summable, then `f` is integrable. -/
lemma integrable_of_summable_norm_restrict {f : C(α, E)} {s : β → compacts α}
  (hf : summable (λ i : β, ‖f.restrict (s i)‖ * ennreal.to_real (μ $ s i)))
  (hs : (⋃ i : β, ↑(s i)) = (univ : set α)) :
  integrable f μ :=
by simpa only [hs, integrable_on_univ] using integrable_on_Union_of_summable_norm_restrict hf

end integrable_Union

section tendsto_mono

variables {μ : measure α} [normed_add_comm_group E] [complete_space E] [normed_space ℝ E]
  {s : ℕ → set α} {f : α → E}

lemma _root_.antitone.tendsto_set_integral (hsm : ∀ i, measurable_set (s i))
  (h_anti : antitone s) (hfi : integrable_on f (s 0) μ) :
  tendsto (λi, ∫ a in s i, f a ∂μ) at_top (𝓝 (∫ a in (⋂ n, s n), f a ∂μ)) :=
begin
  let bound : α → ℝ := indicator (s 0) (λ a, ‖f a‖),
  have h_int_eq : (λ i, ∫ a in s i, f a ∂μ) = (λ i, ∫ a, (s i).indicator f a ∂μ),
    from funext (λ i, (integral_indicator (hsm i)).symm),
  rw h_int_eq,
  rw ← integral_indicator (measurable_set.Inter hsm),
  refine tendsto_integral_of_dominated_convergence bound _ _ _ _,
  { intro n,
    rw ae_strongly_measurable_indicator_iff (hsm n),
    exact (integrable_on.mono_set hfi (h_anti (zero_le n))).1 },
  { rw integrable_indicator_iff (hsm 0),
    exact hfi.norm, },
  { simp_rw norm_indicator_eq_indicator_norm,
    refine λ n, eventually_of_forall (λ x, _),
    exact indicator_le_indicator_of_subset (h_anti (zero_le n)) (λ a, norm_nonneg _) _ },
  { filter_upwards with a using le_trans (h_anti.tendsto_indicator _ _ _) (pure_le_nhds _), },
end

end tendsto_mono

/-! ### Continuity of the set integral

We prove that for any set `s`, the function `λ f : α →₁[μ] E, ∫ x in s, f x ∂μ` is continuous. -/

section continuous_set_integral
variables [normed_add_comm_group E] {𝕜 : Type*} [normed_field 𝕜] [normed_add_comm_group F]
  [normed_space 𝕜 F] {p : ℝ≥0∞} {μ : measure α}

/-- For `f : Lp E p μ`, we can define an element of `Lp E p (μ.restrict s)` by
`(Lp.mem_ℒp f).restrict s).to_Lp f`. This map is additive. -/
lemma Lp_to_Lp_restrict_add (f g : Lp E p μ) (s : set α) :
  ((Lp.mem_ℒp (f + g)).restrict s).to_Lp ⇑(f + g)
    = ((Lp.mem_ℒp f).restrict s).to_Lp f + ((Lp.mem_ℒp g).restrict s).to_Lp g :=
begin
  ext1,
  refine (ae_restrict_of_ae (Lp.coe_fn_add f g)).mp _,
  refine (Lp.coe_fn_add (mem_ℒp.to_Lp f ((Lp.mem_ℒp f).restrict s))
    (mem_ℒp.to_Lp g ((Lp.mem_ℒp g).restrict s))).mp _,
  refine (mem_ℒp.coe_fn_to_Lp ((Lp.mem_ℒp f).restrict s)).mp _,
  refine (mem_ℒp.coe_fn_to_Lp ((Lp.mem_ℒp g).restrict s)).mp _,
  refine (mem_ℒp.coe_fn_to_Lp ((Lp.mem_ℒp (f+g)).restrict s)).mono (λ x hx1 hx2 hx3 hx4 hx5, _),
  rw [hx4, hx1, pi.add_apply, hx2, hx3, hx5, pi.add_apply],
end

/-- For `f : Lp E p μ`, we can define an element of `Lp E p (μ.restrict s)` by
`(Lp.mem_ℒp f).restrict s).to_Lp f`. This map commutes with scalar multiplication. -/
lemma Lp_to_Lp_restrict_smul (c : 𝕜) (f : Lp F p μ) (s : set α) :
  ((Lp.mem_ℒp (c • f)).restrict s).to_Lp ⇑(c • f) = c • (((Lp.mem_ℒp f).restrict s).to_Lp f) :=
begin
  ext1,
  refine (ae_restrict_of_ae (Lp.coe_fn_smul c f)).mp _,
  refine (mem_ℒp.coe_fn_to_Lp ((Lp.mem_ℒp f).restrict s)).mp _,
  refine (mem_ℒp.coe_fn_to_Lp ((Lp.mem_ℒp (c • f)).restrict s)).mp _,
  refine (Lp.coe_fn_smul c (mem_ℒp.to_Lp f ((Lp.mem_ℒp f).restrict s))).mono
    (λ x hx1 hx2 hx3 hx4, _),
  rw [hx2, hx1, pi.smul_apply, hx3, hx4, pi.smul_apply],
end

/-- For `f : Lp E p μ`, we can define an element of `Lp E p (μ.restrict s)` by
`(Lp.mem_ℒp f).restrict s).to_Lp f`. This map is non-expansive. -/
lemma norm_Lp_to_Lp_restrict_le (s : set α) (f : Lp E p μ) :
  ‖((Lp.mem_ℒp f).restrict s).to_Lp f‖ ≤ ‖f‖ :=
begin
  rw [Lp.norm_def, Lp.norm_def, ennreal.to_real_le_to_real (Lp.snorm_ne_top _) (Lp.snorm_ne_top _)],
  refine (le_of_eq _).trans (snorm_mono_measure _ measure.restrict_le_self),
  { exact s, },
  exact snorm_congr_ae (mem_ℒp.coe_fn_to_Lp _),
end

variables (α F 𝕜)
/-- Continuous linear map sending a function of `Lp F p μ` to the same function in
`Lp F p (μ.restrict s)`. -/
def Lp_to_Lp_restrict_clm (μ : measure α) (p : ℝ≥0∞) [hp : fact (1 ≤ p)] (s : set α) :
  Lp F p μ →L[𝕜] Lp F p (μ.restrict s) :=
@linear_map.mk_continuous 𝕜 𝕜 (Lp F p μ) (Lp F p (μ.restrict s)) _ _ _ _ _ _ (ring_hom.id 𝕜)
  ⟨λ f, mem_ℒp.to_Lp f ((Lp.mem_ℒp f).restrict s), λ f g, Lp_to_Lp_restrict_add f g s,
    λ c f, Lp_to_Lp_restrict_smul c f s⟩
  1 (by { intro f, rw one_mul, exact norm_Lp_to_Lp_restrict_le s f, })

variables {α F 𝕜}

variables (𝕜)
lemma Lp_to_Lp_restrict_clm_coe_fn [hp : fact (1 ≤ p)] (s : set α) (f : Lp F p μ) :
  Lp_to_Lp_restrict_clm α F 𝕜 μ p s f =ᵐ[μ.restrict s] f :=
mem_ℒp.coe_fn_to_Lp ((Lp.mem_ℒp f).restrict s)
variables {𝕜}

@[continuity]
lemma continuous_set_integral [normed_space ℝ E] [complete_space E] (s : set α) :
  continuous (λ f : α →₁[μ] E, ∫ x in s, f x ∂μ) :=
begin
  haveI : fact ((1 : ℝ≥0∞) ≤ 1) := ⟨le_rfl⟩,
  have h_comp : (λ f : α →₁[μ] E, ∫ x in s, f x ∂μ)
    = (integral (μ.restrict s)) ∘ (λ f, Lp_to_Lp_restrict_clm α E ℝ μ 1 s f),
  { ext1 f,
    rw [function.comp_apply, integral_congr_ae (Lp_to_Lp_restrict_clm_coe_fn ℝ s f)], },
  rw h_comp,
  exact continuous_integral.comp (Lp_to_Lp_restrict_clm α E ℝ μ 1 s).continuous,
end

end continuous_set_integral

end measure_theory

open measure_theory asymptotics metric

variables {ι : Type*} [normed_add_comm_group E]

/-- Fundamental theorem of calculus for set integrals: if `μ` is a measure that is finite at a
filter `l` and `f` is a measurable function that has a finite limit `b` at `l ⊓ μ.ae`, then `∫ x in
s i, f x ∂μ = μ (s i) • b + o(μ (s i))` at a filter `li` provided that `s i` tends to `l.small_sets`
along `li`. Since `μ (s i)` is an `ℝ≥0∞` number, we use `(μ (s i)).to_real` in the actual statement.

Often there is a good formula for `(μ (s i)).to_real`, so the formalization can take an optional
argument `m` with this formula and a proof `of `(λ i, (μ (s i)).to_real) =ᶠ[li] m`. Without these
arguments, `m i = (μ (s i)).to_real` is used in the output. -/
lemma filter.tendsto.integral_sub_linear_is_o_ae
  [normed_space ℝ E] [complete_space E]
  {μ : measure α} {l : filter α} [l.is_measurably_generated]
  {f : α → E} {b : E} (h : tendsto f (l ⊓ μ.ae) (𝓝 b))
  (hfm : strongly_measurable_at_filter f l μ) (hμ : μ.finite_at_filter l)
  {s : ι → set α} {li : filter ι} (hs : tendsto s li l.small_sets)
  (m : ι → ℝ := λ i, (μ (s i)).to_real)
  (hsμ : (λ i, (μ (s i)).to_real) =ᶠ[li] m . tactic.interactive.refl) :
  (λ i, ∫ x in s i, f x ∂μ - m i • b) =o[li] m :=
begin
  suffices : (λ s, ∫ x in s, f x ∂μ - (μ s).to_real • b) =o[l.small_sets] (λ s, (μ s).to_real),
    from (this.comp_tendsto hs).congr' (hsμ.mono $ λ a ha, ha ▸ rfl) hsμ,
  refine is_o_iff.2 (λ ε ε₀, _),
  have : ∀ᶠ s in l.small_sets, ∀ᶠ x in μ.ae, x ∈ s → f x ∈ closed_ball b ε :=
    eventually_small_sets_eventually.2 (h.eventually $ closed_ball_mem_nhds _ ε₀),
  filter_upwards [hμ.eventually, (hμ.integrable_at_filter_of_tendsto_ae hfm h).eventually,
    hfm.eventually, this],
  simp only [mem_closed_ball, dist_eq_norm],
  intros s hμs h_integrable hfm h_norm,
  rw [← set_integral_const, ← integral_sub h_integrable (integrable_on_const.2 $ or.inr hμs),
    real.norm_eq_abs, abs_of_nonneg ennreal.to_real_nonneg],
  exact norm_set_integral_le_of_norm_le_const_ae' hμs h_norm (hfm.sub ae_strongly_measurable_const)
end

/-- Fundamental theorem of calculus for set integrals, `nhds_within` version: if `μ` is a locally
finite measure and `f` is an almost everywhere measurable function that is continuous at a point `a`
within a measurable set `t`, then `∫ x in s i, f x ∂μ = μ (s i) • f a + o(μ (s i))` at a filter `li`
provided that `s i` tends to `(𝓝[t] a).small_sets` along `li`.  Since `μ (s i)` is an `ℝ≥0∞`
number, we use `(μ (s i)).to_real` in the actual statement.

Often there is a good formula for `(μ (s i)).to_real`, so the formalization can take an optional
argument `m` with this formula and a proof `of `(λ i, (μ (s i)).to_real) =ᶠ[li] m`. Without these
arguments, `m i = (μ (s i)).to_real` is used in the output. -/
lemma continuous_within_at.integral_sub_linear_is_o_ae
  [topological_space α] [opens_measurable_space α]
  [normed_space ℝ E] [complete_space E]
  {μ : measure α} [is_locally_finite_measure μ] {a : α} {t : set α}
  {f : α → E} (ha : continuous_within_at f t a) (ht : measurable_set t)
  (hfm : strongly_measurable_at_filter f (𝓝[t] a) μ)
  {s : ι → set α} {li : filter ι} (hs : tendsto s li (𝓝[t] a).small_sets)
  (m : ι → ℝ := λ i, (μ (s i)).to_real)
  (hsμ : (λ i, (μ (s i)).to_real) =ᶠ[li] m . tactic.interactive.refl) :
  (λ i, ∫ x in s i, f x ∂μ - m i • f a) =o[li] m :=
by haveI : (𝓝[t] a).is_measurably_generated := ht.nhds_within_is_measurably_generated _;
exact (ha.mono_left inf_le_left).integral_sub_linear_is_o_ae
  hfm (μ.finite_at_nhds_within a t) hs m hsμ

/-- Fundamental theorem of calculus for set integrals, `nhds` version: if `μ` is a locally finite
measure and `f` is an almost everywhere measurable function that is continuous at a point `a`, then
`∫ x in s i, f x ∂μ = μ (s i) • f a + o(μ (s i))` at `li` provided that `s` tends to
`(𝓝 a).small_sets` along `li.  Since `μ (s i)` is an `ℝ≥0∞` number, we use `(μ (s i)).to_real` in
the actual statement.

Often there is a good formula for `(μ (s i)).to_real`, so the formalization can take an optional
argument `m` with this formula and a proof `of `(λ i, (μ (s i)).to_real) =ᶠ[li] m`. Without these
arguments, `m i = (μ (s i)).to_real` is used in the output. -/
lemma continuous_at.integral_sub_linear_is_o_ae
  [topological_space α] [opens_measurable_space α]
  [normed_space ℝ E] [complete_space E]
  {μ : measure α} [is_locally_finite_measure μ] {a : α}
  {f : α → E} (ha : continuous_at f a) (hfm : strongly_measurable_at_filter f (𝓝 a) μ)
  {s : ι → set α} {li : filter ι} (hs : tendsto s li (𝓝 a).small_sets)
  (m : ι → ℝ := λ i, (μ (s i)).to_real)
  (hsμ : (λ i, (μ (s i)).to_real) =ᶠ[li] m . tactic.interactive.refl) :
  (λ i, ∫ x in s i, f x ∂μ - m i • f a) =o[li] m :=
(ha.mono_left inf_le_left).integral_sub_linear_is_o_ae hfm (μ.finite_at_nhds a) hs m hsμ

/-- Fundamental theorem of calculus for set integrals, `nhds_within` version: if `μ` is a locally
finite measure, `f` is continuous on a measurable set `t`, and `a ∈ t`, then `∫ x in (s i), f x ∂μ =
μ (s i) • f a + o(μ (s i))` at `li` provided that `s i` tends to `(𝓝[t] a).small_sets` along `li`.
Since `μ (s i)` is an `ℝ≥0∞` number, we use `(μ (s i)).to_real` in the actual statement.

Often there is a good formula for `(μ (s i)).to_real`, so the formalization can take an optional
argument `m` with this formula and a proof `of `(λ i, (μ (s i)).to_real) =ᶠ[li] m`. Without these
arguments, `m i = (μ (s i)).to_real` is used in the output. -/
lemma continuous_on.integral_sub_linear_is_o_ae
  [topological_space α] [opens_measurable_space α]
  [normed_space ℝ E] [complete_space E] [second_countable_topology_either α E]
  {μ : measure α} [is_locally_finite_measure μ] {a : α} {t : set α}
  {f : α → E} (hft : continuous_on f t) (ha : a ∈ t) (ht : measurable_set t)
  {s : ι → set α} {li : filter ι} (hs : tendsto s li (𝓝[t] a).small_sets)
  (m : ι → ℝ := λ i, (μ (s i)).to_real)
  (hsμ : (λ i, (μ (s i)).to_real) =ᶠ[li] m . tactic.interactive.refl) :
  (λ i, ∫ x in s i, f x ∂μ - m i • f a) =o[li] m :=
(hft a ha).integral_sub_linear_is_o_ae ht
  ⟨t, self_mem_nhds_within, hft.ae_strongly_measurable ht⟩ hs m hsμ

section
/-! ### Continuous linear maps composed with integration

The goal of this section is to prove that integration commutes with continuous linear maps.
This holds for simple functions. The general result follows from the continuity of all involved
operations on the space `L¹`. Note that composition by a continuous linear map on `L¹` is not just
the composition, as we are dealing with classes of functions, but it has already been defined
as `continuous_linear_map.comp_Lp`. We take advantage of this construction here.
-/

open_locale complex_conjugate

variables {μ : measure α} {𝕜 : Type*} [is_R_or_C 𝕜] [normed_space 𝕜 E]
  [normed_add_comm_group F] [normed_space 𝕜 F]
  {p : ennreal}

namespace continuous_linear_map

variables [complete_space F] [normed_space ℝ F]

lemma integral_comp_Lp (L : E →L[𝕜] F) (φ : Lp E p μ) :
  ∫ a, (L.comp_Lp φ) a ∂μ = ∫ a, L (φ a) ∂μ :=
integral_congr_ae $ coe_fn_comp_Lp _ _

lemma set_integral_comp_Lp (L : E →L[𝕜] F) (φ : Lp E p μ) {s : set α} (hs : measurable_set s) :
  ∫ a in s, (L.comp_Lp φ) a ∂μ = ∫ a in s, L (φ a) ∂μ :=
set_integral_congr_ae hs ((L.coe_fn_comp_Lp φ).mono (λ x hx hx2, hx))

lemma continuous_integral_comp_L1 (L : E →L[𝕜] F) :
  continuous (λ (φ : α →₁[μ] E), ∫ (a : α), L (φ a) ∂μ) :=
by { rw ← funext L.integral_comp_Lp, exact continuous_integral.comp (L.comp_LpL 1 μ).continuous, }

variables [complete_space E] [normed_space ℝ E]

lemma integral_comp_comm (L : E →L[𝕜] F) {φ : α → E} (φ_int : integrable φ μ) :
  ∫ a, L (φ a) ∂μ = L (∫ a, φ a ∂μ) :=
begin
  apply integrable.induction (λ φ, ∫ a, L (φ a) ∂μ = L (∫ a, φ a ∂μ)),
  { intros e s s_meas s_finite,
    rw [integral_indicator_const e s_meas, ← @smul_one_smul E ℝ 𝕜 _ _ _ _ _ (μ s).to_real e,
      continuous_linear_map.map_smul, @smul_one_smul F ℝ 𝕜 _ _ _ _ _ (μ s).to_real (L e),
      ← integral_indicator_const (L e) s_meas],
    congr' 1 with a,
    rw set.indicator_comp_of_zero L.map_zero },
  { intros f g H f_int g_int hf hg,
    simp [L.map_add, integral_add f_int g_int,
      integral_add (L.integrable_comp f_int) (L.integrable_comp g_int), hf, hg] },
  { exact is_closed_eq L.continuous_integral_comp_L1 (L.continuous.comp continuous_integral) },
  { intros f g hfg f_int hf,
    convert hf using 1 ; clear hf,
    { exact integral_congr_ae (hfg.fun_comp L).symm },
    { rw integral_congr_ae hfg.symm } },
  all_goals { assumption }
end

lemma integral_apply {H : Type*} [normed_add_comm_group H] [normed_space 𝕜 H]
  {φ : α → H →L[𝕜] E} (φ_int : integrable φ μ) (v : H) :
  (∫ a, φ a ∂μ) v = ∫ a, φ a v ∂μ :=
((continuous_linear_map.apply 𝕜 E v).integral_comp_comm φ_int).symm

lemma integral_comp_comm' (L : E →L[𝕜] F) {K} (hL : antilipschitz_with K L) (φ : α → E) :
  ∫ a, L (φ a) ∂μ = L (∫ a, φ a ∂μ) :=
begin
  by_cases h : integrable φ μ,
  { exact integral_comp_comm L h },
  have : ¬ (integrable (L ∘ φ) μ),
    by rwa lipschitz_with.integrable_comp_iff_of_antilipschitz L.lipschitz hL (L.map_zero),
  simp [integral_undef, h, this]
end

lemma integral_comp_L1_comm (L : E →L[𝕜] F) (φ : α →₁[μ] E) : ∫ a, L (φ a) ∂μ = L (∫ a, φ a ∂μ) :=
L.integral_comp_comm (L1.integrable_coe_fn φ)

end continuous_linear_map

namespace linear_isometry

variables [complete_space F] [normed_space ℝ F] [complete_space E] [normed_space ℝ E]

lemma integral_comp_comm (L : E →ₗᵢ[𝕜] F) (φ : α → E) : ∫ a, L (φ a) ∂μ = L (∫ a, φ a ∂μ) :=
L.to_continuous_linear_map.integral_comp_comm' L.antilipschitz _

end linear_isometry

namespace continuous_linear_equiv

variables [complete_space F] [normed_space ℝ F] [complete_space E] [normed_space ℝ E]

lemma integral_comp_comm (L : E ≃L[𝕜] F) (φ : α → E) : ∫ a, L (φ a) ∂μ = L (∫ a, φ a ∂μ) :=
L.to_continuous_linear_map.integral_comp_comm' L.antilipschitz _

end continuous_linear_equiv

variables [complete_space E] [normed_space ℝ E] [complete_space F] [normed_space ℝ F]

@[norm_cast] lemma integral_of_real {f : α → ℝ} : ∫ a, (f a : 𝕜) ∂μ = ↑∫ a, f a ∂μ :=
(@is_R_or_C.of_real_li 𝕜 _).integral_comp_comm f

lemma integral_re {f : α → 𝕜} (hf : integrable f μ) :
  ∫ a, is_R_or_C.re (f a) ∂μ = is_R_or_C.re ∫ a, f a ∂μ :=
(@is_R_or_C.re_clm 𝕜 _).integral_comp_comm hf

lemma integral_im {f : α → 𝕜} (hf : integrable f μ) :
  ∫ a, is_R_or_C.im (f a) ∂μ = is_R_or_C.im ∫ a, f a ∂μ :=
(@is_R_or_C.im_clm 𝕜 _).integral_comp_comm hf

lemma integral_conj {f : α → 𝕜} : ∫ a, conj (f a) ∂μ = conj ∫ a, f a ∂μ :=
(@is_R_or_C.conj_lie 𝕜 _).to_linear_isometry.integral_comp_comm f

lemma integral_coe_re_add_coe_im {f : α → 𝕜} (hf : integrable f μ) :
  ∫ x, (is_R_or_C.re (f x) : 𝕜) ∂μ + ∫ x, is_R_or_C.im (f x) ∂μ * is_R_or_C.I = ∫ x, f x ∂μ :=
begin
  rw [mul_comm, ← smul_eq_mul, ← integral_smul, ← integral_add],
  { congr,
    ext1 x,
    rw [smul_eq_mul, mul_comm, is_R_or_C.re_add_im] },
  { exact hf.re.of_real },
  { exact hf.im.of_real.smul is_R_or_C.I }
end

lemma integral_re_add_im {f : α → 𝕜} (hf : integrable f μ) :
  ((∫ x, is_R_or_C.re (f x) ∂μ : ℝ) : 𝕜) + (∫ x, is_R_or_C.im (f x) ∂μ : ℝ) * is_R_or_C.I =
  ∫ x, f x ∂μ :=
by { rw [← integral_of_real, ← integral_of_real, integral_coe_re_add_coe_im hf] }

lemma set_integral_re_add_im {f : α → 𝕜} {i : set α} (hf : integrable_on f i μ) :
  ((∫ x in i, is_R_or_C.re (f x) ∂μ : ℝ) : 𝕜) +
  (∫ x in i, is_R_or_C.im (f x) ∂μ : ℝ) * is_R_or_C.I = ∫ x in i, f x ∂μ :=
integral_re_add_im hf

lemma fst_integral {f : α → E × F} (hf : integrable f μ) :
  (∫ x, f x ∂μ).1 = ∫ x, (f x).1 ∂μ :=
((continuous_linear_map.fst ℝ E F).integral_comp_comm hf).symm

lemma snd_integral {f : α → E × F} (hf : integrable f μ) :
  (∫ x, f x ∂μ).2 = ∫ x, (f x).2 ∂μ :=
((continuous_linear_map.snd ℝ E F).integral_comp_comm hf).symm

lemma integral_pair {f : α → E} {g : α → F} (hf : integrable f μ) (hg : integrable g μ) :
  ∫ x, (f x, g x) ∂μ = (∫ x, f x ∂μ, ∫ x, g x ∂μ) :=
have _ := hf.prod_mk hg, prod.ext (fst_integral this) (snd_integral this)

lemma integral_smul_const {𝕜 : Type*} [is_R_or_C 𝕜] [normed_space 𝕜 E] (f : α → 𝕜) (c : E) :
  ∫ x, f x • c ∂μ = (∫ x, f x ∂μ) • c :=
begin
  by_cases hf : integrable f μ,
  { exact ((1 : 𝕜 →L[𝕜] 𝕜).smul_right c).integral_comp_comm hf },
  { by_cases hc : c = 0,
    { simp only [hc, integral_zero, smul_zero] },
    rw [integral_undef hf, integral_undef, zero_smul],
    simp_rw [integrable_smul_const hc, hf, not_false_iff] }
end

section inner

variables {E' : Type*}
variables [normed_add_comm_group E'] [inner_product_space 𝕜 E']
variables [complete_space E'] [normed_space ℝ E']

local notation `⟪`x`, `y`⟫` := @inner 𝕜 E' _ x y

lemma integral_inner {f : α → E'} (hf : integrable f μ) (c : E') :
  ∫ x, ⟪c, f x⟫ ∂μ = ⟪c, ∫ x, f x ∂μ⟫ :=
((innerSL 𝕜 c).restrict_scalars ℝ).integral_comp_comm hf

variables (𝕜)
-- variable binder update doesn't work for lemmas which refer to `𝕜` only via the notation
local notation (name := inner_with_explicit) `⟪`x`, `y`⟫` := @inner 𝕜 E' _ x y

lemma integral_eq_zero_of_forall_integral_inner_eq_zero (f : α → E') (hf : integrable f μ)
  (hf_int : ∀ (c : E'), ∫ x, ⟪c, f x⟫ ∂μ = 0) :
  ∫ x, f x ∂μ = 0 :=
by { specialize hf_int (∫ x, f x ∂μ), rwa [integral_inner hf, inner_self_eq_zero] at hf_int }

end inner

lemma integral_with_density_eq_integral_smul
  {f : α → ℝ≥0} (f_meas : measurable f) (g : α → E) :
  ∫ a, g a ∂(μ.with_density (λ x, f x)) = ∫ a, f a • g a ∂μ :=
begin
  by_cases hg : integrable g (μ.with_density (λ x, f x)), swap,
  { rw [integral_undef hg, integral_undef],
    rwa [← integrable_with_density_iff_integrable_smul f_meas];
    apply_instance },
  refine integrable.induction _ _ _ _ _ hg,
  { assume c s s_meas hs,
    rw integral_indicator s_meas,
    simp_rw [← indicator_smul_apply, integral_indicator s_meas],
    simp only [s_meas, integral_const, measure.restrict_apply', univ_inter, with_density_apply],
    rw [lintegral_coe_eq_integral, ennreal.to_real_of_real, ← integral_smul_const],
    { refl },
    { exact integral_nonneg (λ x, nnreal.coe_nonneg _) },
    { refine ⟨(f_meas.coe_nnreal_real).ae_measurable.ae_strongly_measurable, _⟩,
      rw with_density_apply _ s_meas at hs,
      rw has_finite_integral,
      convert hs,
      ext1 x,
      simp only [nnreal.nnnorm_eq] } },
  { assume u u' h_disj u_int u'_int h h',
    change ∫ (a : α), (u a + u' a) ∂μ.with_density (λ (x : α), ↑(f x)) =
      ∫ (a : α), f a • (u a + u' a) ∂μ,
    simp_rw [smul_add],
    rw [integral_add u_int u'_int, h, h', integral_add],
    { exact (integrable_with_density_iff_integrable_smul f_meas).1 u_int },
    { exact (integrable_with_density_iff_integrable_smul f_meas).1 u'_int } },
  { have C1 : continuous (λ (u : Lp E 1 (μ.with_density (λ x, f x))),
      ∫ x, u x ∂(μ.with_density (λ x, f x))) := continuous_integral,
    have C2 : continuous (λ (u : Lp E 1 (μ.with_density (λ x, f x))),
      ∫ x, f x • u x ∂μ),
    { have : continuous ((λ (u : Lp E 1 μ), ∫ x, u x ∂μ) ∘ (with_density_smul_li μ f_meas)) :=
        continuous_integral.comp (with_density_smul_li μ f_meas).continuous,
      convert this,
      ext1 u,
      simp only [function.comp_app, with_density_smul_li_apply],
      exact integral_congr_ae (mem_ℒ1_smul_of_L1_with_density f_meas u).coe_fn_to_Lp.symm },
    exact is_closed_eq C1 C2 },
  { assume u v huv u_int hu,
    rw [← integral_congr_ae huv, hu],
    apply integral_congr_ae,
    filter_upwards [(ae_with_density_iff f_meas.coe_nnreal_ennreal).1 huv] with x hx,
    rcases eq_or_ne (f x) 0 with h'x|h'x,
    { simp only [h'x, zero_smul]},
    { rw [hx _],
      simpa only [ne.def, ennreal.coe_eq_zero] using h'x } }
end

lemma integral_with_density_eq_integral_smul₀
  {f : α → ℝ≥0} (hf : ae_measurable f μ) (g : α → E) :
  ∫ a, g a ∂(μ.with_density (λ x, f x)) = ∫ a, f a • g a ∂μ :=
begin
  let f' := hf.mk _,
  calc ∫ a, g a ∂(μ.with_density (λ x, f x))
      = ∫ a, g a ∂(μ.with_density (λ x, f' x)) :
  begin
    congr' 1,
    apply with_density_congr_ae,
    filter_upwards [hf.ae_eq_mk] with x hx,
    rw hx,
  end
  ... = ∫ a, f' a • g a ∂μ : integral_with_density_eq_integral_smul hf.measurable_mk _
  ... = ∫ a, f a • g a ∂μ :
  begin
    apply integral_congr_ae,
    filter_upwards [hf.ae_eq_mk] with x hx,
    rw hx,
  end
end

lemma set_integral_with_density_eq_set_integral_smul
  {f : α → ℝ≥0} (f_meas : measurable f) (g : α → E) {s : set α} (hs : measurable_set s) :
  ∫ a in s, g a ∂(μ.with_density (λ x, f x)) = ∫ a in s, f a • g a ∂μ :=
by rw [restrict_with_density hs, integral_with_density_eq_integral_smul f_meas]

lemma set_integral_with_density_eq_set_integral_smul₀ {f : α → ℝ≥0} {s : set α}
  (hf : ae_measurable f (μ.restrict s)) (g : α → E) (hs : measurable_set s) :
  ∫ a in s, g a ∂(μ.with_density (λ x, f x)) = ∫ a in s, f a • g a ∂μ :=
by rw [restrict_with_density hs, integral_with_density_eq_integral_smul₀ hf]

end

section thickened_indicator

variables [pseudo_emetric_space α]

lemma measure_le_lintegral_thickened_indicator_aux
  (μ : measure α) {E : set α} (E_mble : measurable_set E) (δ : ℝ) :
  μ E ≤ ∫⁻ a, (thickened_indicator_aux δ E a : ℝ≥0∞) ∂μ :=
begin
  convert_to lintegral μ (E.indicator (λ _, (1 : ℝ≥0∞)))
              ≤ lintegral μ (thickened_indicator_aux δ E),
  { rw [lintegral_indicator _ E_mble],
    simp only [lintegral_one, measure.restrict_apply, measurable_set.univ, univ_inter], },
  { apply lintegral_mono,
    apply indicator_le_thickened_indicator_aux, },
end

lemma measure_le_lintegral_thickened_indicator
  (μ : measure α) {E : set α} (E_mble : measurable_set E) {δ : ℝ} (δ_pos : 0 < δ) :
  μ E ≤ ∫⁻ a, (thickened_indicator δ_pos E a : ℝ≥0∞) ∂μ :=
begin
  convert measure_le_lintegral_thickened_indicator_aux μ E_mble δ,
  dsimp,
  simp only [thickened_indicator_aux_lt_top.ne, ennreal.coe_to_nnreal, ne.def, not_false_iff],
end

end thickened_indicator

section bilinear_map
namespace measure_theory

variables {f : β → ℝ} {m m0 : measurable_space β} {μ : measure β}

lemma integrable.simple_func_mul (g : simple_func β ℝ) (hf : integrable f μ) :
  integrable (g * f) μ :=
begin
  refine simple_func.induction (λ c s hs, _) (λ g₁ g₂ h_disj h_int₁ h_int₂,
    (h_int₁.add h_int₂).congr (by rw [simple_func.coe_add, add_mul])) g,
  simp only [simple_func.const_zero, simple_func.coe_piecewise, simple_func.coe_const,
    simple_func.coe_zero, set.piecewise_eq_indicator],
  have : set.indicator s (function.const β c) * f = s.indicator (c • f),
  { ext1 x,
    by_cases hx : x ∈ s,
    { simp only [hx, pi.mul_apply, set.indicator_of_mem, pi.smul_apply, algebra.id.smul_eq_mul] },
    { simp only [hx, pi.mul_apply, set.indicator_of_not_mem, not_false_iff, zero_mul], }, },
  rw [this, integrable_indicator_iff hs],
  exact (hf.smul c).integrable_on,
end

lemma integrable.simple_func_mul' (hm : m ≤ m0) (g : @simple_func β m ℝ) (hf : integrable f μ) :
  integrable (g * f) μ :=
by { rw ← simple_func.coe_to_larger_space_eq hm g, exact hf.simple_func_mul (g.to_larger_space hm) }

end measure_theory
end bilinear_map


/-
Copyright (c) 2020 Anatole Dedecker. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Anatole Dedecker

Basic topological facts (limits and continuity) about `floor`,
`ceil` and `fract` in a `floor_ring`.
-/
import topology.algebra.ordered
import algebra.floor

open set function filter
open_locale topological_space

variables {α : Type*} [linear_ordered_ring α] [floor_ring α]

lemma tendsto_floor_at_top : tendsto (floor : α → ℤ) at_top at_top :=
begin
  refine monotone.tendsto_at_top_at_top (λ a b hab, floor_mono hab) (λ b, _),
  use (b : α) + ((1 : ℤ) : α),
  rw [floor_add_int, floor_coe],
  exact (lt_add_one _).le
end

lemma tendsto_floor_at_bot : tendsto (floor : α → ℤ) at_bot at_bot :=
begin
  refine monotone.tendsto_at_bot_at_bot (λ a b hab, floor_mono hab) (λ b, ⟨b, _⟩),
  rw floor_coe
end

lemma tendsto_ceil_at_top : tendsto (ceil : α → ℤ) at_top at_top :=
tendsto_neg_at_bot_at_top.comp (tendsto_floor_at_bot.comp tendsto_neg_at_top_at_bot)

lemma tendsto_ceil_at_bot : tendsto (ceil : α → ℤ) at_bot at_bot :=
tendsto_neg_at_top_at_bot.comp (tendsto_floor_at_top.comp tendsto_neg_at_bot_at_top)

variables [topological_space α]

lemma continuous_on_floor (n : ℤ) : continuous_on (λ x, floor x : α → α) (Ico n (n+1) : set α) :=
(continuous_on_congr $ floor_eq_on_Ico' n).mpr continuous_on_const

lemma continuous_on_ceil (n : ℤ) : continuous_on (λ x, ceil x : α → α) (Ioc (n-1) n : set α) :=
(continuous_on_congr $ ceil_eq_on_Ioc' n).mpr continuous_on_const

lemma tendsto_floor_right' [order_closed_topology α] (n : ℤ) :
  tendsto (λ x, floor x : α → α) (𝓝[Ici n] n) (𝓝 n) :=
begin
  rw ← nhds_within_Ico_eq_nhds_within_Ici (lt_add_one (n : α)),
  simpa only [floor_coe] using
    (continuous_on_floor n _ (left_mem_Ico.mpr $ lt_add_one (_ : α))).tendsto
end

lemma tendsto_ceil_left' [order_closed_topology α] (n : ℤ) :
  tendsto (λ x, ceil x : α → α) (𝓝[Iic n] n) (𝓝 n) :=
begin
  rw ← nhds_within_Ioc_eq_nhds_within_Iic (sub_one_lt (n : α)),
  simpa only [ceil_coe] using
    (continuous_on_ceil _ _ (right_mem_Ioc.mpr $ sub_one_lt (_ : α))).tendsto
end

lemma tendsto_floor_right [order_closed_topology α] (n : ℤ) :
  tendsto (λ x, floor x : α → α) (𝓝[Ici n] n) (𝓝[Ici n] n) :=
tendsto_nhds_within_of_tendsto_nhds_of_eventually_within _ (tendsto_floor_right' _)
begin
  refine (eventually_nhds_with_of_forall $ λ x (hx : (n : α) ≤ x), _),
  change _ ≤ _,
  norm_cast,
  convert ← floor_mono hx,
  rw floor_eq_iff,
  exact ⟨le_refl _, lt_add_one _⟩
end

lemma tendsto_ceil_left [order_closed_topology α] (n : ℤ) :
  tendsto (λ x, ceil x : α → α) (𝓝[Iic n] n) (𝓝[Iic n] n) :=
tendsto_nhds_within_of_tendsto_nhds_of_eventually_within _ (tendsto_ceil_left' _)
begin
  refine (eventually_nhds_with_of_forall $ λ x (hx : x ≤ (n : α)), _),
  change _ ≤ _,
  norm_cast,
  convert ← ceil_mono hx,
  rw ceil_eq_iff,
  exact ⟨sub_one_lt _, le_refl _⟩
end

lemma tendsto_floor_left [order_closed_topology α] (n : ℤ) :
  tendsto (λ x, floor x : α → α) (𝓝[Iio n] n) (𝓝[Iic (n-1)] (n-1)) :=
begin
  rw ← nhds_within_Ico_eq_nhds_within_Iio (sub_one_lt (n : α)),
  convert (tendsto_nhds_within_congr $ (λ x hx, (floor_eq_on_Ico' (n-1) x hx).symm))
    (tendsto_nhds_within_of_tendsto_nhds_of_eventually_within _ tendsto_const_nhds
      (eventually_of_forall (λ _, mem_Iic.mpr $ le_refl _)));
  norm_cast <|> apply_instance,
  ring
end

lemma tendsto_ceil_right [order_closed_topology α] (n : ℤ) :
  tendsto (λ x, ceil x : α → α) (𝓝[Ioi n] n) (𝓝[Ici (n+1)] (n+1)) :=
begin
  rw ← nhds_within_Ioc_eq_nhds_within_Ioi (lt_add_one (n : α)),
  convert (tendsto_nhds_within_congr $ (λ x hx, (ceil_eq_on_Ioc' (n+1) x hx).symm))
    (tendsto_nhds_within_of_tendsto_nhds_of_eventually_within _ tendsto_const_nhds
      (eventually_of_forall (λ _, mem_Ici.mpr $ le_refl _)));
  norm_cast <|> apply_instance,
  ring
end

lemma tendsto_floor_left' [order_closed_topology α] (n : ℤ) :
  tendsto (λ x, floor x : α → α) (𝓝[Iio n] n) (𝓝 (n-1)) :=
begin
  rw ← nhds_within_univ,
  exact tendsto_nhds_within_mono_right (subset_univ _) (tendsto_floor_left n),
end

lemma tendsto_ceil_right' [order_closed_topology α] (n : ℤ) :
  tendsto (λ x, ceil x : α → α) (𝓝[Ioi n] n) (𝓝 (n+1)) :=
begin
  rw ← nhds_within_univ,
  exact tendsto_nhds_within_mono_right (subset_univ _) (tendsto_ceil_right n),
end

lemma continuous_on_fract [topological_add_group α] (n : ℤ) :
  continuous_on (fract : α → α) (Ico n (n+1) : set α) :=
continuous_on_id.sub (continuous_on_floor n)

lemma tendsto_fract_left' [order_closed_topology α] [topological_add_group α]
  (n : ℤ) : tendsto (fract : α → α) (𝓝[Iio n] n) (𝓝 1) :=
begin
  convert (tendsto_nhds_within_of_tendsto_nhds tendsto_id).sub (tendsto_floor_left' n);
  [{norm_cast, ring}, apply_instance, apply_instance]
end

lemma tendsto_fract_left [order_closed_topology α] [topological_add_group α]
  (n : ℤ) : tendsto (fract : α → α) (𝓝[Iio n] n) (𝓝[Iio 1] 1) :=
tendsto_nhds_within_of_tendsto_nhds_of_eventually_within _
  (tendsto_fract_left' _) (eventually_of_forall fract_lt_one)

lemma tendsto_fract_right' [order_closed_topology α] [topological_add_group α]
  (n : ℤ) : tendsto (fract : α → α) (𝓝[Ici n] n) (𝓝 0) :=
begin
  convert (tendsto_nhds_within_of_tendsto_nhds tendsto_id).sub (tendsto_floor_right' n);
  [exact (sub_self _).symm, apply_instance, apply_instance]
end

lemma tendsto_fract_right [order_closed_topology α] [topological_add_group α]
  (n : ℤ) : tendsto (fract : α → α) (𝓝[Ici n] n) (𝓝[Ici 0] 0) :=
tendsto_nhds_within_of_tendsto_nhds_of_eventually_within _
  (tendsto_fract_right' _) (eventually_of_forall fract_nonneg)

local notation `I` := (Icc 0 1 : set α)

lemma continuous_on.comp_fract' {β γ : Type*} [order_topology α]
  [topological_add_group α] [topological_space β] [topological_space γ] {f : β → α → γ}
  (h : continuous_on (uncurry f) $ (univ : set β).prod I) (hf : ∀ s, f s 0 = f s 1) :
  continuous (λ st : β × α, f st.1 $ fract st.2) :=
begin
  change continuous ((uncurry f) ∘ (prod.map id (fract))),
  rw continuous_iff_continuous_at,
  rintro ⟨s, t⟩,
  by_cases ht : t = floor t,
  { rw ht,
    rw ← continuous_within_at_univ,
    have : (univ : set (β × α)) ⊆ (set.prod univ (Iio $ floor t)) ∪ (set.prod univ (Ici $ floor t)),
    { rintros p -,
      rw ← prod_union,
      exact ⟨true.intro, lt_or_le _ _⟩ },
    refine continuous_within_at.mono _ this,
    refine continuous_within_at.union _ _,
    { simp only [continuous_within_at, fract_coe, nhds_within_prod_eq,
                  nhds_within_univ, id.def, comp_app, prod.map_mk],
      have : (uncurry f) (s, 0) = (uncurry f) (s, (1 : α)),
        by simp [uncurry, hf],
      rw this,
      refine (h _ ⟨true.intro, by exact_mod_cast right_mem_Icc.mpr zero_le_one⟩).tendsto.comp _,
      rw [nhds_within_prod_eq, nhds_within_univ],
      rw nhds_within_Icc_eq_nhds_within_Iic (@zero_lt_one α _ _),
      exact tendsto_id.prod_map
        (tendsto_nhds_within_mono_right Iio_subset_Iic_self $ tendsto_fract_left _) },
    { simp only [continuous_within_at, fract_coe, nhds_within_prod_eq,
                  nhds_within_univ, id.def, comp_app, prod.map_mk],
      refine (h _ ⟨true.intro, by exact_mod_cast left_mem_Icc.mpr zero_le_one⟩).tendsto.comp _,
      rw [nhds_within_prod_eq, nhds_within_univ,
        nhds_within_Icc_eq_nhds_within_Ici (@zero_lt_one α _ _)],
      exact tendsto_id.prod_map (tendsto_fract_right _) } },
  { have : t ∈ Ioo (floor t : α) ((floor t : α) + 1),
      from ⟨lt_of_le_of_ne (floor_le t) (ne.symm ht), lt_floor_add_one _⟩,
    apply (h ((prod.map _ fract) _) ⟨trivial, ⟨fract_nonneg _, (fract_lt_one _).le⟩⟩).tendsto.comp,
    simp only [nhds_prod_eq, nhds_within_prod_eq, nhds_within_univ, id.def, prod.map_mk],
    exact continuous_at_id.tendsto.prod_map
            (tendsto_nhds_within_of_tendsto_nhds_of_eventually_within _
              (((continuous_on_fract _ _ (Ioo_subset_Ico_self this)).mono
                  Ioo_subset_Ico_self).continuous_at (Ioo_mem_nhds this.1 this.2))
              (eventually_of_forall (λ x, ⟨fract_nonneg _, (fract_lt_one _).le⟩)) ) }
end

lemma continuous_on.comp_fract {β : Type*} [order_topology α]
  [topological_add_group α] [topological_space β] {f : α → β}
  (h : continuous_on f I) (hf : f 0 = f 1) : continuous (f ∘ fract) :=
begin
  let f' : unit → α → β := λ x y, f y,
  have : continuous_on (uncurry f') ((univ : set unit).prod I),
  { rintros ⟨s, t⟩ ⟨-, ht : t ∈ I⟩,
    simp only [continuous_within_at, uncurry, nhds_within_prod_eq, nhds_within_univ, f'],
    rw tendsto_prod_iff,
    intros W hW,
    specialize h t ht hW,
    rw mem_map_sets_iff at h,
    rcases h with ⟨V, hV, hVW⟩,
    rw image_subset_iff at hVW,
    use [univ, univ_mem_sets, V, hV],
    intros x y hx hy,
    exact hVW hy },
  have key : continuous (λ s, ⟨unit.star, s⟩ : α → unit × α) := by continuity,
  exact (this.comp_fract' (λ s, hf)).comp key
end


/-
Copyright (c) 2021 Eric Wieser. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Eric Wieser
-/
import ring_theory.subsemiring.basic
import algebra.group_ring_action
import algebra.pointwise

/-! # Pointwise instances on `subsemiring`s

This file provides the action `subsemiring.pointwise_mul_action` which matches the action of
`mul_action_set`.

This actions is available in the `pointwise` locale.

## Implementation notes

This file is almost identical to `group_theory/submonoid/pointwise.lean`. Where possible, try to
keep them in sync.
-/

variables {M R : Type*}

namespace subsemiring

section monoid
variables [monoid M] [semiring R] [mul_semiring_action M R]

/-- The action on a subsemiring corresponding to applying the action to every element.

This is available as an instance in the `pointwise` locale. -/
protected def pointwise_mul_action : mul_action M (subsemiring R) :=
{ smul := λ a S, S.map (mul_semiring_action.to_ring_hom _ _ a),
  one_smul := λ S,
    (congr_arg (λ f, S.map f) (ring_hom.ext $ by exact one_smul M)).trans S.map_id,
  mul_smul := λ a₁ a₂ S,
    (congr_arg (λ f, S.map f) (ring_hom.ext $ by exact mul_smul _ _)).trans (S.map_map _ _).symm }

localized "attribute [instance] subsemiring.pointwise_mul_action" in pointwise
open_locale pointwise

lemma pointwise_smul_def {a : M} (S : subsemiring R) :
  a • S = S.map (mul_semiring_action.to_ring_hom _ _ a) := rfl

@[simp] lemma coe_pointwise_smul (m : M) (S : subsemiring R) : ↑(m • S) = m • (S : set R) := rfl

@[simp] lemma pointwise_smul_to_add_submonoid (m : M) (S : subsemiring R) :
  (m • S).to_add_submonoid = m • S.to_add_submonoid := rfl

lemma mem_smul_pointwise_iff_exists (m : M) (r : R) (S : subsemiring R) :
  r ∈ m • S ↔ ∃ (s : R), s ∈ S ∧ m • s = r :=
(set.mem_smul_set : r ∈ m • (S : set R) ↔ _)

instance pointwise_central_scalar [mul_semiring_action Mᵐᵒᵖ R] [is_central_scalar M R] :
  is_central_scalar M (subsemiring R) :=
⟨λ a S, congr_arg (λ f, S.map f) $ ring_hom.ext $ by exact op_smul_eq_smul _⟩

end monoid

section group
variables [group M] [semiring R] [mul_semiring_action M R]

open_locale pointwise

@[simp] lemma smul_mem_pointwise_smul_iff {a : M} {S : subsemiring R} {x : R} :
  a • x ∈ a • S ↔ x ∈ S :=
smul_mem_smul_set_iff

lemma mem_pointwise_smul_iff_inv_smul_mem {a : M} {S : subsemiring R} {x : R} :
  x ∈ a • S ↔ a⁻¹ • x ∈ S :=
mem_smul_set_iff_inv_smul_mem

lemma mem_inv_pointwise_smul_iff {a : M} {S : subsemiring R} {x : R} : x ∈ a⁻¹ • S ↔ a • x ∈ S :=
mem_inv_smul_set_iff

@[simp] lemma pointwise_smul_le_pointwise_smul_iff {a : M} {S T : subsemiring R} :
  a • S ≤ a • T ↔ S ≤ T :=
set_smul_subset_set_smul_iff

lemma pointwise_smul_subset_iff {a : M} {S T : subsemiring R} : a • S ≤ T ↔ S ≤ a⁻¹ • T :=
set_smul_subset_iff

lemma subset_pointwise_smul_iff {a : M} {S T : subsemiring R} : S ≤ a • T ↔ a⁻¹ • S ≤ T :=
subset_set_smul_iff

/-! TODO: add `equiv_smul` like we have for subgroup. -/

end group

section group_with_zero
variables [group_with_zero M] [semiring R] [mul_semiring_action M R]

open_locale pointwise

@[simp] lemma smul_mem_pointwise_smul_iff₀ {a : M} (ha : a ≠ 0) (S : subsemiring R)
  (x : R) : a • x ∈ a • S ↔ x ∈ S :=
smul_mem_smul_set_iff₀ ha (S : set R) x

lemma mem_pointwise_smul_iff_inv_smul_mem₀ {a : M} (ha : a ≠ 0) (S : subsemiring R) (x : R) :
  x ∈ a • S ↔ a⁻¹ • x ∈ S :=
mem_smul_set_iff_inv_smul_mem₀ ha (S : set R) x

lemma mem_inv_pointwise_smul_iff₀ {a : M} (ha : a ≠ 0) (S : subsemiring R) (x : R) :
  x ∈ a⁻¹ • S ↔ a • x ∈ S :=
mem_inv_smul_set_iff₀ ha (S : set R) x

@[simp] lemma pointwise_smul_le_pointwise_smul_iff₀ {a : M} (ha : a ≠ 0) {S T : subsemiring R} :
  a • S ≤ a • T ↔ S ≤ T :=
set_smul_subset_set_smul_iff₀ ha

lemma pointwise_smul_le_iff₀ {a : M} (ha : a ≠ 0) {S T : subsemiring R} : a • S ≤ T ↔ S ≤ a⁻¹ • T :=
set_smul_subset_iff₀ ha

lemma le_pointwise_smul_iff₀ {a : M} (ha : a ≠ 0) {S T : subsemiring R} : S ≤ a • T ↔ a⁻¹ • S ≤ T :=
subset_set_smul_iff₀ ha

end group_with_zero

end subsemiring


-- Conmutatividad de la conjunción
-- ===============================

-- Demostrar que
--    P ∧ Q → Q ∧ P

import tactic

variables (P Q R : Prop)

-- 1ª demostración
-- ===============

example : P ∧ Q → Q ∧ P :=
begin
  intro h,
  cases h with hP hQ,
  split,
  { exact hQ },
  { exact hP },
end

-- 2ª demostración
-- ===============

example : P ∧ Q → Q ∧ P :=
begin
  rintro ⟨hP, hQ⟩,
  exact ⟨hQ, hP⟩,
end

-- 3ª demostración
-- ===============

example : P ∧ Q → Q ∧ P :=
λ ⟨hP, hQ⟩, ⟨hQ, hP⟩

-- 4ª demostración
-- ===============

example : P ∧ Q → Q ∧ P :=
and.comm.mp

-- 5ª demostración
-- ===============

example : P ∧ Q → Q ∧ P :=
begin
  assume h : P ∧ Q,
  have hP : P := h.left,
  have hQ : Q := h.right,
  show Q ∧ P, from ⟨hQ, hP⟩,
end

-- 6ª demostración
-- ===============

example : P ∧ Q → Q ∧ P :=
begin
  assume h : P ∧ Q,
  show Q ∧ P, from ⟨h.2, h.1⟩,
end

example : P ∧ Q → Q ∧ P :=
λ h, ⟨h.2, h.1⟩

-- 7ª demostración
-- ===============

example : P ∧ Q → Q ∧ P :=
by tauto

-- 8ª demostración
-- ===============

example : P ∧ Q → Q ∧ P :=
by finish


import number_theory.sum_two_squares
import number_theory.modular
import data.zmod.basic
/-
(pg 21) Lemma 2: No number n=4m+3 is a sum of 2 squares

The sum of any even number is (2k)^2= 4k^2 = 0 (mod 4)
while the squares of odd numbers yield (2k+1)^2=1 (mod 4)
Thus, any sum of squares is 0,1 or 2 (mod 4)
-/
lemma no_sum_of_sq_4m_3:  ∀ a b m,  a*a+b*b ≠ 4*m+3 := begin
  intro a,
  intro b,
  intro m,
  by_contradiction,
  by_cases ha : even a, -- split on whether even or odd
  by_cases hb : even b, -- split on whether even or odd
  {
    have x : (a: zmod 4)*a = 0 := begin
      norm_fin,
      sorry,
    end,
      have y : (b: zmod 4)*b = 0 := begin
      norm_fin,
      sorry,
    end,
    have z : (a: zmod 4)*a + (b: zmod 4)*b  = 0 := begin
      norm_fin,
      sorry,
    end,
    have fh: a * a + b * b =  3 := begin
      sorry,
    end,
    contradiction,
    sorry,
  },
  {

    sorry,
  },
  {

    sorry,
  },
  -- {

  --   -- sorry,
  -- },
end


/-
Copyright (c) 2020 Adam Topaz. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Adam Topaz
-/
import algebra.free_algebra
import algebra.ring_quot
import algebra.triv_sq_zero_ext
import algebra.algebra.operations
import linear_algebra.multilinear.basic

/-!
# Tensor Algebras

Given a commutative semiring `R`, and an `R`-module `M`, we construct the tensor algebra of `M`.
This is the free `R`-algebra generated (`R`-linearly) by the module `M`.

## Notation

1. `tensor_algebra R M` is the tensor algebra itself. It is endowed with an R-algebra structure.
2. `tensor_algebra.ι R` is the canonical R-linear map `M → tensor_algebra R M`.
3. Given a linear map `f : M → A` to an R-algebra `A`, `lift R f` is the lift of `f` to an
  `R`-algebra morphism `tensor_algebra R M → A`.

## Theorems

1. `ι_comp_lift` states that the composition `(lift R f) ∘ (ι R)` is identical to `f`.
2. `lift_unique` states that whenever an R-algebra morphism `g : tensor_algebra R M → A` is
  given whose composition with `ι R` is `f`, then one has `g = lift R f`.
3. `hom_ext` is a variant of `lift_unique` in the form of an extensionality theorem.
4. `lift_comp_ι` is a combination of `ι_comp_lift` and `lift_unique`. It states that the lift
  of the composition of an algebra morphism with `ι` is the algebra morphism itself.

## Implementation details

As noted above, the tensor algebra of `M` is constructed as the free `R`-algebra generated by `M`,
modulo the additional relations making the inclusion of `M` into an `R`-linear map.
-/

variables (R : Type*) [comm_semiring R]
variables (M : Type*) [add_comm_monoid M] [module R M]

namespace tensor_algebra

/--
An inductively defined relation on `pre R M` used to force the initial algebra structure on
the associated quotient.
-/
inductive rel : free_algebra R M → free_algebra R M → Prop
-- force `ι` to be linear
| add {a b : M} :
  rel (free_algebra.ι R (a+b)) (free_algebra.ι R a + free_algebra.ι R b)
| smul {r : R} {a : M} :
  rel (free_algebra.ι R (r • a)) (algebra_map R (free_algebra R M) r * free_algebra.ι R a)

end tensor_algebra

/--
The tensor algebra of the module `M` over the commutative semiring `R`.
-/
@[derive [inhabited, semiring, algebra R]]
def tensor_algebra := ring_quot (tensor_algebra.rel R M)

namespace tensor_algebra

instance {S : Type*} [comm_ring S] [module S M] : ring (tensor_algebra S M) :=
ring_quot.ring (rel S M)

variables {M}
/--
The canonical linear map `M →ₗ[R] tensor_algebra R M`.
-/
@[irreducible] def ι : M →ₗ[R] (tensor_algebra R M) :=
{ to_fun := λ m, (ring_quot.mk_alg_hom R _ (free_algebra.ι R m)),
  map_add' := λ x y, by { rw [←alg_hom.map_add], exact ring_quot.mk_alg_hom_rel R rel.add, },
  map_smul' := λ r x, by { rw [←alg_hom.map_smul], exact ring_quot.mk_alg_hom_rel R rel.smul, } }

lemma ring_quot_mk_alg_hom_free_algebra_ι_eq_ι (m : M) :
  ring_quot.mk_alg_hom R (rel R M) (free_algebra.ι R m) = ι R m :=
by { rw [ι], refl }

/--
Given a linear map `f : M → A` where `A` is an `R`-algebra, `lift R f` is the unique lift
of `f` to a morphism of `R`-algebras `tensor_algebra R M → A`.
-/
@[irreducible, simps symm_apply]
def lift {A : Type*} [semiring A] [algebra R A] : (M →ₗ[R] A) ≃ (tensor_algebra R M →ₐ[R] A) :=
{ to_fun := ring_quot.lift_alg_hom R ∘ λ f,
    ⟨free_algebra.lift R ⇑f, λ x y (h : rel R M x y), by induction h;
        simp only [algebra.smul_def, free_algebra.lift_ι_apply, linear_map.map_smulₛₗ,
          ring_hom.id_apply, map_mul, alg_hom.commutes, map_add]⟩,
  inv_fun := λ F, F.to_linear_map.comp (ι R),
  left_inv := λ f, begin
    rw [ι],
    ext1 x,
    exact (ring_quot.lift_alg_hom_mk_alg_hom_apply _ _ _ _).trans (free_algebra.lift_ι_apply f x),
  end,
  right_inv := λ F, ring_quot.ring_quot_ext' _ _ _ $ free_algebra.hom_ext $ funext $ λ x, begin
    rw [ι],
    exact (ring_quot.lift_alg_hom_mk_alg_hom_apply _ _ _ _).trans (free_algebra.lift_ι_apply _ _)
  end }

variables {R}

@[simp]
theorem ι_comp_lift {A : Type*} [semiring A] [algebra R A] (f : M →ₗ[R] A) :
  (lift R f).to_linear_map.comp (ι R) = f :=
by { convert (lift R).symm_apply_apply f, simp only [lift, equiv.coe_fn_symm_mk] }

@[simp]
theorem lift_ι_apply {A : Type*} [semiring A] [algebra R A] (f : M →ₗ[R] A) (x) :
  lift R f (ι R x) = f x :=
by { conv_rhs { rw ← ι_comp_lift f}, refl }

@[simp]
theorem lift_unique {A : Type*} [semiring A] [algebra R A] (f : M →ₗ[R] A)
  (g : tensor_algebra R M →ₐ[R] A) : g.to_linear_map.comp (ι R) = f ↔ g = lift R f :=
by { rw ← (lift R).symm_apply_eq, simp only [lift, equiv.coe_fn_symm_mk] }

-- Marking `tensor_algebra` irreducible makes `ring` instances inaccessible on quotients.
-- https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/algebra.2Esemiring_to_ring.20breaks.20semimodule.20typeclass.20lookup/near/212580241
-- For now, we avoid this by not marking it irreducible.

@[simp]
theorem lift_comp_ι {A : Type*} [semiring A] [algebra R A] (g : tensor_algebra R M →ₐ[R] A) :
  lift R (g.to_linear_map.comp (ι R)) = g :=
by { rw ←lift_symm_apply, exact (lift R).apply_symm_apply g }

/-- See note [partially-applied ext lemmas]. -/
@[ext]
theorem hom_ext {A : Type*} [semiring A] [algebra R A] {f g : tensor_algebra R M →ₐ[R] A}
  (w : f.to_linear_map.comp (ι R) = g.to_linear_map.comp (ι R)) : f = g :=
begin
  rw [←lift_symm_apply, ←lift_symm_apply] at w,
  exact (lift R).symm.injective w,
end

/-- If `C` holds for the `algebra_map` of `r : R` into `tensor_algebra R M`, the `ι` of `x : M`,
and is preserved under addition and muliplication, then it holds for all of `tensor_algebra R M`.
-/
-- This proof closely follows `free_algebra.induction`
@[elab_as_eliminator]
lemma induction {C : tensor_algebra R M → Prop}
  (h_grade0 : ∀ r, C (algebra_map R (tensor_algebra R M) r))
  (h_grade1 : ∀ x, C (ι R x))
  (h_mul : ∀ a b, C a → C b → C (a * b))
  (h_add : ∀ a b, C a → C b → C (a + b))
  (a : tensor_algebra R M) :
  C a :=
begin
  -- the arguments are enough to construct a subalgebra, and a mapping into it from M
  let s : subalgebra R (tensor_algebra R M) :=
  { carrier := C,
    mul_mem' := h_mul,
    add_mem' := h_add,
    algebra_map_mem' := h_grade0, },
  let of : M →ₗ[R] s := (ι R).cod_restrict s.to_submodule h_grade1,
  -- the mapping through the subalgebra is the identity
  have of_id : alg_hom.id R (tensor_algebra R M) = s.val.comp (lift R of),
  { ext,
    simp [of], },
  -- finding a proof is finding an element of the subalgebra
  convert subtype.prop (lift R of a),
  exact alg_hom.congr_fun of_id a,
end

/-- The left-inverse of `algebra_map`. -/
def algebra_map_inv : tensor_algebra R M →ₐ[R] R :=
lift R (0 : M →ₗ[R] R)

variables (M)

lemma algebra_map_left_inverse :
  function.left_inverse algebra_map_inv (algebra_map R $ tensor_algebra R M) :=
λ x, by simp [algebra_map_inv]

@[simp] lemma algebra_map_inj (x y : R) :
  algebra_map R (tensor_algebra R M) x = algebra_map R (tensor_algebra R M) y ↔ x = y :=
(algebra_map_left_inverse M).injective.eq_iff

@[simp] lemma algebra_map_eq_zero_iff (x : R) : algebra_map R (tensor_algebra R M) x = 0 ↔ x = 0 :=
map_eq_zero_iff (algebra_map _ _) (algebra_map_left_inverse _).injective

@[simp] lemma algebra_map_eq_one_iff (x : R) : algebra_map R (tensor_algebra R M) x = 1 ↔ x = 1 :=
map_eq_one_iff (algebra_map _ _) (algebra_map_left_inverse _).injective

variables {M}

/-- The canonical map from `tensor_algebra R M` into `triv_sq_zero_ext R M` that sends
`tensor_algebra.ι` to `triv_sq_zero_ext.inr`. -/
def to_triv_sq_zero_ext [module Rᵐᵒᵖ M] [is_central_scalar R M] :
  tensor_algebra R M →ₐ[R] triv_sq_zero_ext R M :=
lift R (triv_sq_zero_ext.inr_hom R M)

@[simp] lemma to_triv_sq_zero_ext_ι (x : M) [module Rᵐᵒᵖ M] [is_central_scalar R M] :
   to_triv_sq_zero_ext (ι R x) = triv_sq_zero_ext.inr x :=
lift_ι_apply _ _

/-- The left-inverse of `ι`.

As an implementation detail, we implement this using `triv_sq_zero_ext` which has a suitable
algebra structure. -/
def ι_inv : tensor_algebra R M →ₗ[R] M :=
begin
  letI : module Rᵐᵒᵖ M := module.comp_hom _ ((ring_hom.id R).from_opposite mul_comm),
  haveI : is_central_scalar R M := ⟨λ r m, rfl⟩,
  exact (triv_sq_zero_ext.snd_hom R M).comp to_triv_sq_zero_ext.to_linear_map
end

lemma ι_left_inverse : function.left_inverse ι_inv (ι R : M → tensor_algebra R M) :=
λ x, by simp [ι_inv]

variables (R)

@[simp] lemma ι_inj (x y : M) : ι R x = ι R y ↔ x = y :=
ι_left_inverse.injective.eq_iff

@[simp] lemma ι_eq_zero_iff (x : M) : ι R x = 0 ↔ x = 0 :=
by rw [←ι_inj R x 0, linear_map.map_zero]

variables {R}

@[simp] lemma ι_eq_algebra_map_iff (x : M) (r : R) : ι R x = algebra_map R _ r ↔ x = 0 ∧ r = 0 :=
begin
  refine ⟨λ h, _, _⟩,
  { letI : module Rᵐᵒᵖ M := module.comp_hom _ ((ring_hom.id R).from_opposite mul_comm),
    haveI : is_central_scalar R M := ⟨λ r m, rfl⟩,
    have hf0 : to_triv_sq_zero_ext (ι R x) = (0, x), from lift_ι_apply _ _,
    rw [h, alg_hom.commutes] at hf0,
    have : r = 0 ∧ 0 = x := prod.ext_iff.1 hf0,
    exact this.symm.imp_left eq.symm, },
  { rintro ⟨rfl, rfl⟩,
    rw [linear_map.map_zero, ring_hom.map_zero] }
end

@[simp] lemma ι_ne_one [nontrivial R] (x : M) : ι R x ≠ 1 :=
begin
  rw [←(algebra_map R (tensor_algebra R M)).map_one, ne.def, ι_eq_algebra_map_iff],
  exact one_ne_zero ∘ and.right,
end

/-- The generators of the tensor algebra are disjoint from its scalars. -/

variables (R M)

/-- Construct a product of `n` elements of the module within the tensor algebra.

See also `pi_tensor_product.tprod`. -/
def tprod (n : ℕ) : multilinear_map R (λ i : fin n, M) (tensor_algebra R M) :=
(multilinear_map.mk_pi_algebra_fin R n (tensor_algebra R M)).comp_linear_map $ λ _, ι R

@[simp] lemma tprod_apply {n : ℕ} (x : fin n → M) :
  tprod R M n x = (list.of_fn (λ i, ι R (x i))).prod := rfl

variables {R M}

end tensor_algebra

namespace free_algebra

variables {R M}

/-- The canonical image of the `free_algebra` in the `tensor_algebra`, which maps
`free_algebra.ι R x` to `tensor_algebra.ι R x`. -/
def to_tensor : free_algebra R M →ₐ[R] tensor_algebra R M :=
free_algebra.lift R (tensor_algebra.ι R)

@[simp] lemma to_tensor_ι (m : M) : (free_algebra.ι R m).to_tensor = tensor_algebra.ι R m :=
by simp [to_tensor]

end free_algebra


def x := 10

namespace Foo

def x := true

#check x
#check _root_.x

theorem ex1 : x = true := rfl
theorem ex2 : _root_.x = 10 := rfl

end Foo

theorem ex3 : x = 10 := rfl
theorem ex4 : _root_.x = 10 := rfl


namespace Abstract
/-
This is one attempt at writing down the implementation of a Matrix/Vector library for Poseidon.
I'm fairly certain this would be unwieldy to use in practice, so we prefer the implementation in
`Matrix.lean`.
WARNING: There's like a 50% chance I got the transposes wrong in these definitions, so the first
step is going to be to test if it's right
-/
def Vector (A : Type) (n : Nat) : Type := Fin n → A

def Matrix (A : Type) (r c : Nat) : Type := Fin c → Fin r → A

namespace Matrix

variable [Inhabited A] [Add A] [Mul A] [OfNat A (nat_lit 0)]

def last (f : Fin n.succ → A) : Fin n → A := f ∘ Fin.succ

open Nat in
theorem lt_succ (n : Nat) : n < n + 1 := by
  rw [add_one]
  apply lt_succ_of_le
  apply Nat.le_refl

def sum (f : Fin n → A) : A := match n with
  | 0 => 0
  | n + 1 => f ⟨n, lt_succ n⟩ + sum (last f)

def dotProduct (v w : Vector A c) : A := sum fun ⟨i, h⟩ => v ⟨i, h⟩ * w ⟨i, h⟩

infixl:50 "⬝" => dotProduct

def transpose (m : Matrix A r c) : Matrix A c r := fun ⟨i, hi⟩ ⟨j, hj⟩ => m ⟨j, hj⟩ ⟨i, hi⟩

postfix:max "ᵀ" => transpose

variable (m : Matrix A r c) (k : Fin r) (v : Vector A c)

def matrixVecAction (m : Matrix A r c) (v : Vector A c) : Vector A r :=
  fun ⟨i, h⟩ => mᵀ ⟨i, h⟩ ⬝ v

instance : HMul (Matrix A r c) (Vector A c) (Vector A r) := ⟨matrixVecAction⟩

def matrixMul (m : Matrix A r c) (m' : Matrix A c r') : Matrix A r r' :=
  fun ⟨i, hi⟩ ⟨j, hj⟩ => mᵀ ⟨j, hj⟩ ⬝ m' ⟨i, hi⟩

instance : HMul (Matrix A r c) (Matrix A c r') (Matrix A r r') := ⟨matrixMul⟩

def vectorSum (v₁ v₂ : Vector A c) : Vector A c :=
  fun i => v₁ i + v₂ i

instance : HAdd (Vector A c) (Vector A c) (Vector A c) := ⟨vectorSum⟩

end Matrix

end Abstract