/-
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.function.lp_order

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

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

Such a predicate is already available under the name `mem_ℒp 1`. We give a direct definition which
is easier to use, and show that it is equivalent to `mem_ℒp 1`

In the second part, we establish an API between `integrable` and the space `L¹` of equivalence
classes of integrable functions, already defined as a special case of `L^p` spaces for `p = 1`.

## Notation

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

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

## Main definitions

* Let `f : α → β` be a function, where `α` is a `measure_space` and `β` a `normed_add_comm_group`.
  Then `has_finite_integral f` means `(∫⁻ a, ‖f a‖₊) < ∞`.

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

## Implementation notes

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

## Tags

integrable, function space, l1

-/

noncomputable theory

open_locale classical topology big_operators ennreal measure_theory nnreal

open set filter topological_space ennreal emetric measure_theory

variables {α β γ δ : Type*} {m : measurable_space α} {μ ν : measure α} [measurable_space δ]
variables [normed_add_comm_group β]
variables [normed_add_comm_group γ]

namespace measure_theory

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

lemma lintegral_nnnorm_eq_lintegral_edist (f : α → β) :
  ∫⁻ a, ‖f a‖₊ ∂μ = ∫⁻ a, edist (f a) 0 ∂μ :=
by simp only [edist_eq_coe_nnnorm]

lemma lintegral_norm_eq_lintegral_edist (f : α → β) :
  ∫⁻ a, (ennreal.of_real ‖f a‖) ∂μ = ∫⁻ a, edist (f a) 0 ∂μ :=
by simp only [of_real_norm_eq_coe_nnnorm, edist_eq_coe_nnnorm]

lemma lintegral_edist_triangle {f g h : α → β}
  (hf : ae_strongly_measurable f μ) (hh : ae_strongly_measurable h μ) :
  ∫⁻ a, edist (f a) (g a) ∂μ ≤ ∫⁻ a, edist (f a) (h a) ∂μ + ∫⁻ a, edist (g a) (h a) ∂μ :=
begin
  rw ← lintegral_add_left' (hf.edist hh),
  refine lintegral_mono (λ a, _),
  apply edist_triangle_right
end

lemma lintegral_nnnorm_zero : ∫⁻ a : α, ‖(0 : β)‖₊ ∂μ = 0 := by simp

lemma lintegral_nnnorm_add_left
  {f : α → β} (hf : ae_strongly_measurable f μ) (g : α → γ) :
  ∫⁻ a, ‖f a‖₊ + ‖g a‖₊ ∂μ = ∫⁻ a, ‖f a‖₊ ∂μ + ∫⁻ a, ‖g a‖₊ ∂μ :=
lintegral_add_left' hf.ennnorm _

lemma lintegral_nnnorm_add_right
  (f : α → β) {g : α → γ} (hg : ae_strongly_measurable g μ) :
  ∫⁻ a, ‖f a‖₊ + ‖g a‖₊ ∂μ = ∫⁻ a, ‖f a‖₊ ∂μ + ∫⁻ a, ‖g a‖₊ ∂μ :=
lintegral_add_right' _ hg.ennnorm

lemma lintegral_nnnorm_neg {f : α → β} :
  ∫⁻ a, ‖(-f) a‖₊ ∂μ = ∫⁻ a, ‖f a‖₊ ∂μ :=
by simp only [pi.neg_apply, nnnorm_neg]

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

/-- `has_finite_integral f μ` means that the integral `∫⁻ a, ‖f a‖ ∂μ` is finite.
  `has_finite_integral f` means `has_finite_integral f volume`. -/
def has_finite_integral {m : measurable_space α} (f : α → β) (μ : measure α . volume_tac) : Prop :=
∫⁻ a, ‖f a‖₊ ∂μ < ∞

lemma has_finite_integral_iff_norm (f : α → β) :
  has_finite_integral f μ ↔ ∫⁻ a, (ennreal.of_real ‖f a‖) ∂μ < ∞ :=
by simp only [has_finite_integral, of_real_norm_eq_coe_nnnorm]

lemma has_finite_integral_iff_edist (f : α → β) :
  has_finite_integral f μ ↔ ∫⁻ a, edist (f a) 0 ∂μ < ∞ :=
by simp only [has_finite_integral_iff_norm, edist_dist, dist_zero_right]

lemma has_finite_integral_iff_of_real {f : α → ℝ} (h : 0 ≤ᵐ[μ] f) :
  has_finite_integral f μ ↔ ∫⁻ a, ennreal.of_real (f a) ∂μ < ∞ :=
by rw [has_finite_integral, lintegral_nnnorm_eq_of_ae_nonneg h]

lemma has_finite_integral_iff_of_nnreal {f : α → ℝ≥0} :
  has_finite_integral (λ x, (f x : ℝ)) μ ↔ ∫⁻ a, f a ∂μ < ∞ :=
by simp [has_finite_integral_iff_norm]

lemma has_finite_integral.mono {f : α → β} {g : α → γ} (hg : has_finite_integral g μ)
  (h : ∀ᵐ a ∂μ, ‖f a‖ ≤ ‖g a‖) : has_finite_integral f μ :=
begin
  simp only [has_finite_integral_iff_norm] at *,
  calc ∫⁻ a, (ennreal.of_real ‖f a‖) ∂μ ≤ ∫⁻ (a : α), (ennreal.of_real ‖g a‖) ∂μ :
    lintegral_mono_ae (h.mono $ assume a h, of_real_le_of_real h)
    ... < ∞ : hg
end

lemma has_finite_integral.mono' {f : α → β} {g : α → ℝ} (hg : has_finite_integral g μ)
  (h : ∀ᵐ a ∂μ, ‖f a‖ ≤ g a) : has_finite_integral f μ :=
hg.mono $ h.mono $ λ x hx, le_trans hx (le_abs_self _)

lemma has_finite_integral.congr' {f : α → β} {g : α → γ} (hf : has_finite_integral f μ)
  (h : ∀ᵐ a ∂μ, ‖f a‖ = ‖g a‖) :
  has_finite_integral g μ :=
hf.mono $ eventually_eq.le $ eventually_eq.symm h

lemma has_finite_integral_congr' {f : α → β} {g : α → γ} (h : ∀ᵐ a ∂μ, ‖f a‖ = ‖g a‖) :
  has_finite_integral f μ ↔ has_finite_integral g μ :=
⟨λ hf, hf.congr' h, λ hg, hg.congr' $ eventually_eq.symm h⟩

lemma has_finite_integral.congr {f g : α → β} (hf : has_finite_integral f μ) (h : f =ᵐ[μ] g) :
  has_finite_integral g μ :=
hf.congr' $ h.fun_comp norm

lemma has_finite_integral_congr {f g : α → β} (h : f =ᵐ[μ] g) :
  has_finite_integral f μ ↔ has_finite_integral g μ :=
has_finite_integral_congr' $ h.fun_comp norm

lemma has_finite_integral_const_iff {c : β} :
  has_finite_integral (λ x : α, c) μ ↔ c = 0 ∨ μ univ < ∞ :=
by simp [has_finite_integral, lintegral_const, lt_top_iff_ne_top, ennreal.mul_eq_top,
  or_iff_not_imp_left]

lemma has_finite_integral_const [is_finite_measure μ] (c : β) :
  has_finite_integral (λ x : α, c) μ :=
has_finite_integral_const_iff.2 (or.inr $ measure_lt_top _ _)

lemma has_finite_integral_of_bounded [is_finite_measure μ] {f : α → β} {C : ℝ}
  (hC : ∀ᵐ a ∂μ, ‖f a‖ ≤ C) : has_finite_integral f μ :=
(has_finite_integral_const C).mono' hC

lemma has_finite_integral.mono_measure {f : α → β} (h : has_finite_integral f ν) (hμ : μ ≤ ν) :
  has_finite_integral f μ :=
lt_of_le_of_lt (lintegral_mono' hμ le_rfl) h

lemma has_finite_integral.add_measure {f : α → β} (hμ : has_finite_integral f μ)
  (hν : has_finite_integral f ν) : has_finite_integral f (μ + ν) :=
begin
  simp only [has_finite_integral, lintegral_add_measure] at *,
  exact add_lt_top.2 ⟨hμ, hν⟩
end

lemma has_finite_integral.left_of_add_measure {f : α → β} (h : has_finite_integral f (μ + ν)) :
  has_finite_integral f μ :=
h.mono_measure $ measure.le_add_right $ le_rfl

lemma has_finite_integral.right_of_add_measure {f : α → β} (h : has_finite_integral f (μ + ν)) :
  has_finite_integral f ν :=
h.mono_measure $ measure.le_add_left $ le_rfl

@[simp] lemma has_finite_integral_add_measure {f : α → β} :
  has_finite_integral f (μ + ν) ↔ has_finite_integral f μ ∧ has_finite_integral f ν :=
⟨λ h, ⟨h.left_of_add_measure, h.right_of_add_measure⟩, λ h, h.1.add_measure h.2⟩

lemma has_finite_integral.smul_measure {f : α → β} (h : has_finite_integral f μ) {c : ℝ≥0∞}
  (hc : c ≠ ∞) : has_finite_integral f (c • μ) :=
begin
  simp only [has_finite_integral, lintegral_smul_measure] at *,
  exact mul_lt_top hc h.ne
end

@[simp] lemma has_finite_integral_zero_measure {m : measurable_space α} (f : α → β) :
  has_finite_integral f (0 : measure α) :=
by simp only [has_finite_integral, lintegral_zero_measure, with_top.zero_lt_top]

variables (α β μ)
@[simp] lemma has_finite_integral_zero : has_finite_integral (λa:α, (0:β)) μ :=
by simp [has_finite_integral]
variables {α β μ}

lemma has_finite_integral.neg {f : α → β} (hfi : has_finite_integral f μ) :
  has_finite_integral (-f) μ :=
by simpa [has_finite_integral] using hfi

@[simp] lemma has_finite_integral_neg_iff {f : α → β} :
  has_finite_integral (-f) μ ↔ has_finite_integral f μ :=
⟨λ h, neg_neg f ▸ h.neg, has_finite_integral.neg⟩

lemma has_finite_integral.norm {f : α → β} (hfi : has_finite_integral f μ) :
  has_finite_integral (λa, ‖f a‖) μ :=
have eq : (λa, (nnnorm ‖f a‖ : ℝ≥0∞)) = λa, (‖f a‖₊ : ℝ≥0∞),
  by { funext, rw nnnorm_norm },
by { rwa [has_finite_integral, eq] }

lemma has_finite_integral_norm_iff (f : α → β) :
  has_finite_integral (λa, ‖f a‖) μ ↔ has_finite_integral f μ :=
has_finite_integral_congr' $ eventually_of_forall $ λ x, norm_norm (f x)

lemma has_finite_integral_to_real_of_lintegral_ne_top
  {f : α → ℝ≥0∞} (hf : ∫⁻ x, f x ∂μ ≠ ∞) :
  has_finite_integral (λ x, (f x).to_real) μ :=
begin
  have : ∀ x, (‖(f x).to_real‖₊ : ℝ≥0∞) =
    @coe ℝ≥0 ℝ≥0∞ _ (⟨(f x).to_real, ennreal.to_real_nonneg⟩ : ℝ≥0),
  { intro x, rw real.nnnorm_of_nonneg },
  simp_rw [has_finite_integral, this],
  refine lt_of_le_of_lt (lintegral_mono (λ x, _)) (lt_top_iff_ne_top.2 hf),
  by_cases hfx : f x = ∞,
  { simp [hfx] },
  { lift f x to ℝ≥0 using hfx with fx,
    simp [← h] }
end

lemma is_finite_measure_with_density_of_real {f : α → ℝ} (hfi : has_finite_integral f μ) :
  is_finite_measure (μ.with_density (λ x, ennreal.of_real $ f x)) :=
begin
  refine is_finite_measure_with_density ((lintegral_mono $ λ x, _).trans_lt hfi).ne,
  exact real.of_real_le_ennnorm (f x)
end

section dominated_convergence

variables {F : ℕ → α → β} {f : α → β} {bound : α → ℝ}

lemma all_ae_of_real_F_le_bound (h : ∀ n, ∀ᵐ a ∂μ, ‖F n a‖ ≤ bound a) :
  ∀ n, ∀ᵐ a ∂μ, ennreal.of_real ‖F n a‖ ≤ ennreal.of_real (bound a) :=
λn, (h n).mono $ λ a h, ennreal.of_real_le_of_real h

lemma all_ae_tendsto_of_real_norm (h : ∀ᵐ a ∂μ, tendsto (λ n, F n a) at_top $ 𝓝 $ f a) :
  ∀ᵐ a ∂μ, tendsto (λn, ennreal.of_real ‖F n a‖) at_top $ 𝓝 $ ennreal.of_real ‖f a‖ :=
h.mono $
  λ a h, tendsto_of_real $ tendsto.comp (continuous.tendsto continuous_norm _) h

lemma all_ae_of_real_f_le_bound (h_bound : ∀ n, ∀ᵐ a ∂μ, ‖F n a‖ ≤ bound a)
  (h_lim : ∀ᵐ a ∂μ, tendsto (λ n, F n a) at_top (𝓝 (f a))) :
  ∀ᵐ a ∂μ, ennreal.of_real ‖f a‖ ≤ ennreal.of_real (bound a) :=
begin
  have F_le_bound := all_ae_of_real_F_le_bound h_bound,
  rw ← ae_all_iff at F_le_bound,
  apply F_le_bound.mp ((all_ae_tendsto_of_real_norm h_lim).mono _),
  assume a tendsto_norm F_le_bound,
  exact le_of_tendsto' tendsto_norm (F_le_bound)
end

lemma has_finite_integral_of_dominated_convergence {F : ℕ → α → β} {f : α → β} {bound : α → ℝ}
  (bound_has_finite_integral : has_finite_integral bound μ)
  (h_bound : ∀ n, ∀ᵐ a ∂μ, ‖F n a‖ ≤ bound a)
  (h_lim : ∀ᵐ a ∂μ, tendsto (λ n, F n a) at_top (𝓝 (f a))) :
  has_finite_integral f μ :=
/- `‖F n a‖ ≤ bound a` and `‖F n a‖ --> ‖f a‖` implies `‖f a‖ ≤ bound a`,
  and so `∫ ‖f‖ ≤ ∫ bound < ∞` since `bound` is has_finite_integral -/
begin
  rw has_finite_integral_iff_norm,
  calc ∫⁻ a, (ennreal.of_real ‖f a‖) ∂μ ≤ ∫⁻ a, ennreal.of_real (bound a) ∂μ :
    lintegral_mono_ae $ all_ae_of_real_f_le_bound h_bound h_lim
    ... < ∞ :
    begin
      rw ← has_finite_integral_iff_of_real,
      { exact bound_has_finite_integral },
      exact (h_bound 0).mono (λ a h, le_trans (norm_nonneg _) h)
    end
end

lemma tendsto_lintegral_norm_of_dominated_convergence
  {F : ℕ → α → β} {f : α → β} {bound : α → ℝ}
  (F_measurable : ∀ n, ae_strongly_measurable (F n) μ)
  (bound_has_finite_integral : has_finite_integral 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, (ennreal.of_real ‖F n a - f a‖) ∂μ) at_top (𝓝 0) :=
have f_measurable : ae_strongly_measurable f μ :=
  ae_strongly_measurable_of_tendsto_ae _ F_measurable h_lim,
let b := λ a, 2 * ennreal.of_real (bound a) in
/- `‖F n a‖ ≤ bound a` and `F n a --> f a` implies `‖f a‖ ≤ bound a`, and thus by the
  triangle inequality, have `‖F n a - f a‖ ≤ 2 * (bound a). -/
have hb : ∀ n, ∀ᵐ a ∂μ, ennreal.of_real ‖F n a - f a‖ ≤ b a,
begin
  assume n,
  filter_upwards [all_ae_of_real_F_le_bound h_bound n, all_ae_of_real_f_le_bound h_bound h_lim]
    with a h₁ h₂,
  calc ennreal.of_real ‖F n a - f a‖ ≤ (ennreal.of_real ‖F n a‖) + (ennreal.of_real ‖f a‖) :
  begin
    rw [← ennreal.of_real_add],
    apply of_real_le_of_real,
    { apply norm_sub_le }, { exact norm_nonneg _ }, { exact norm_nonneg _ }
  end
    ... ≤ (ennreal.of_real (bound a)) + (ennreal.of_real (bound a)) : add_le_add h₁ h₂
    ... = b a : by rw ← two_mul
end,
/- On the other hand, `F n a --> f a` implies that `‖F n a - f a‖ --> 0`  -/
have h : ∀ᵐ a ∂μ, tendsto (λ n, ennreal.of_real ‖F n a - f a‖) at_top (𝓝 0),
begin
  rw ← ennreal.of_real_zero,
  refine h_lim.mono (λ a h, (continuous_of_real.tendsto _).comp _),
  rwa ← tendsto_iff_norm_tendsto_zero
end,
/- Therefore, by the dominated convergence theorem for nonnegative integration, have
  ` ∫ ‖f a - F n a‖ --> 0 ` -/
begin
  suffices h : tendsto (λn, ∫⁻ a, (ennreal.of_real ‖F n a - f a‖) ∂μ) at_top (𝓝 (∫⁻ (a:α), 0 ∂μ)),
  { rwa lintegral_zero at h },
  -- Using the dominated convergence theorem.
  refine tendsto_lintegral_of_dominated_convergence' _ _ hb _ _,
  -- Show `λa, ‖f a - F n a‖` is almost everywhere measurable for all `n`
  { exact λ n,  measurable_of_real.comp_ae_measurable
      ((F_measurable n).sub f_measurable).norm.ae_measurable },
  -- Show `2 * bound` is has_finite_integral
  { rw has_finite_integral_iff_of_real at bound_has_finite_integral,
    { calc ∫⁻ a, b a ∂μ = 2 * ∫⁻ a, ennreal.of_real (bound a) ∂μ :
        by { rw lintegral_const_mul', exact coe_ne_top }
        ... ≠ ∞ : mul_ne_top coe_ne_top bound_has_finite_integral.ne },
    filter_upwards [h_bound 0] with _ h using le_trans (norm_nonneg _) h },
  -- Show `‖f a - F n a‖ --> 0`
  { exact h }
end

end dominated_convergence

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

lemma has_finite_integral.max_zero {f : α → ℝ} (hf : has_finite_integral f μ) :
  has_finite_integral (λa, max (f a) 0) μ :=
hf.mono $ eventually_of_forall $ λ x, by simp [abs_le, le_abs_self]

lemma has_finite_integral.min_zero {f : α → ℝ} (hf : has_finite_integral f μ) :
  has_finite_integral (λa, min (f a) 0) μ :=
hf.mono $ eventually_of_forall $ λ x,
  by simp [abs_le, neg_le, neg_le_abs_self, abs_eq_max_neg, le_total]

end pos_part

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

lemma has_finite_integral.smul (c : 𝕜) {f : α → β} : has_finite_integral f μ →
  has_finite_integral (c • f) μ :=
begin
  simp only [has_finite_integral], assume hfi,
  calc
    ∫⁻ (a : α), ‖c • f a‖₊ ∂μ = ∫⁻ (a : α), (‖c‖₊) * ‖f a‖₊ ∂μ :
      by simp only [nnnorm_smul, ennreal.coe_mul]
    ... < ∞ :
    begin
      rw lintegral_const_mul',
      exacts [mul_lt_top coe_ne_top hfi.ne, coe_ne_top]
    end
end

lemma has_finite_integral_smul_iff {c : 𝕜} (hc : c ≠ 0) (f : α → β) :
  has_finite_integral (c • f) μ ↔ has_finite_integral f μ :=
begin
  split,
  { assume h,
    simpa only [smul_smul, inv_mul_cancel hc, one_smul] using h.smul c⁻¹ },
  exact has_finite_integral.smul _
end

lemma has_finite_integral.const_mul {f : α → ℝ} (h : has_finite_integral f μ) (c : ℝ) :
  has_finite_integral (λ x, c * f x) μ :=
(has_finite_integral.smul c h : _)

lemma has_finite_integral.mul_const {f : α → ℝ} (h : has_finite_integral f μ) (c : ℝ) :
  has_finite_integral (λ x, f x * c) μ :=
by simp_rw [mul_comm, h.const_mul _]

end normed_space

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

-- variables [measurable_space β] [measurable_space γ] [measurable_space δ]

/-- `integrable f μ` means that `f` is measurable and that the integral `∫⁻ a, ‖f a‖ ∂μ` is finite.
  `integrable f` means `integrable f volume`. -/
def integrable {α} {m : measurable_space α} (f : α → β) (μ : measure α . volume_tac) : Prop :=
ae_strongly_measurable f μ ∧ has_finite_integral f μ

lemma mem_ℒp_one_iff_integrable {f : α → β} : mem_ℒp f 1 μ ↔ integrable f μ :=
by simp_rw [integrable, has_finite_integral, mem_ℒp, snorm_one_eq_lintegral_nnnorm]

lemma integrable.ae_strongly_measurable {f : α → β} (hf : integrable f μ) :
  ae_strongly_measurable f μ :=
hf.1

lemma integrable.ae_measurable [measurable_space β] [borel_space β]
  {f : α → β} (hf : integrable f μ) :
  ae_measurable f μ :=
hf.ae_strongly_measurable.ae_measurable

lemma integrable.has_finite_integral {f : α → β} (hf : integrable f μ) : has_finite_integral f μ :=
hf.2

lemma integrable.mono {f : α → β} {g : α → γ}
  (hg : integrable g μ) (hf : ae_strongly_measurable f μ) (h : ∀ᵐ a ∂μ, ‖f a‖ ≤ ‖g a‖) :
  integrable f μ :=
⟨hf, hg.has_finite_integral.mono h⟩

lemma integrable.mono' {f : α → β} {g : α → ℝ}
  (hg : integrable g μ) (hf : ae_strongly_measurable f μ) (h : ∀ᵐ a ∂μ, ‖f a‖ ≤ g a) :
  integrable f μ :=
⟨hf, hg.has_finite_integral.mono' h⟩

lemma integrable.congr' {f : α → β} {g : α → γ}
  (hf : integrable f μ) (hg : ae_strongly_measurable g μ) (h : ∀ᵐ a ∂μ, ‖f a‖ = ‖g a‖) :
  integrable g μ :=
⟨hg, hf.has_finite_integral.congr' h⟩

lemma integrable_congr' {f : α → β} {g : α → γ}
  (hf : ae_strongly_measurable f μ) (hg : ae_strongly_measurable g μ) (h : ∀ᵐ a ∂μ, ‖f a‖ = ‖g a‖) :
  integrable f μ ↔ integrable g μ :=
⟨λ h2f, h2f.congr' hg h, λ h2g, h2g.congr' hf $ eventually_eq.symm h⟩

lemma integrable.congr {f g : α → β} (hf : integrable f μ) (h : f =ᵐ[μ] g) :
  integrable g μ :=
⟨hf.1.congr h, hf.2.congr h⟩

lemma integrable_congr {f g : α → β} (h : f =ᵐ[μ] g) :
  integrable f μ ↔ integrable g μ :=
⟨λ hf, hf.congr h, λ hg, hg.congr h.symm⟩

lemma integrable_const_iff {c : β} : integrable (λ x : α, c) μ ↔ c = 0 ∨ μ univ < ∞ :=
begin
  have : ae_strongly_measurable (λ (x : α), c) μ := ae_strongly_measurable_const,
  rw [integrable, and_iff_right this, has_finite_integral_const_iff]
end

lemma integrable_const [is_finite_measure μ] (c : β) : integrable (λ x : α, c) μ :=
integrable_const_iff.2 $ or.inr $ measure_lt_top _ _

lemma mem_ℒp.integrable_norm_rpow {f : α → β} {p : ℝ≥0∞}
  (hf : mem_ℒp f p μ) (hp_ne_zero : p ≠ 0) (hp_ne_top : p ≠ ∞) :
  integrable (λ (x : α), ‖f x‖ ^ p.to_real) μ :=
begin
  rw ← mem_ℒp_one_iff_integrable,
  exact hf.norm_rpow hp_ne_zero hp_ne_top,
end

lemma mem_ℒp.integrable_norm_rpow' [is_finite_measure μ] {f : α → β} {p : ℝ≥0∞}
  (hf : mem_ℒp f p μ) :
  integrable (λ (x : α), ‖f x‖ ^ p.to_real) μ :=
begin
  by_cases h_zero : p = 0,
  { simp [h_zero, integrable_const] },
  by_cases h_top : p = ∞,
  { simp [h_top, integrable_const] },
  exact hf.integrable_norm_rpow h_zero h_top
end

lemma integrable.mono_measure {f : α → β} (h : integrable f ν) (hμ : μ ≤ ν) : integrable f μ :=
⟨h.ae_strongly_measurable.mono_measure hμ, h.has_finite_integral.mono_measure hμ⟩

lemma integrable.of_measure_le_smul {μ' : measure α} (c : ℝ≥0∞) (hc : c ≠ ∞)
  (hμ'_le : μ' ≤ c • μ) {f : α → β} (hf : integrable f μ) :
  integrable f μ' :=
by { rw ← mem_ℒp_one_iff_integrable at hf ⊢, exact hf.of_measure_le_smul c hc hμ'_le, }

lemma integrable.add_measure {f : α → β} (hμ : integrable f μ) (hν : integrable f ν) :
  integrable f (μ + ν) :=
begin
  simp_rw ← mem_ℒp_one_iff_integrable at hμ hν ⊢,
  refine ⟨hμ.ae_strongly_measurable.add_measure hν.ae_strongly_measurable, _⟩,
  rw [snorm_one_add_measure, ennreal.add_lt_top],
  exact ⟨hμ.snorm_lt_top, hν.snorm_lt_top⟩,
end

lemma integrable.left_of_add_measure {f : α → β} (h : integrable f (μ + ν)) : integrable f μ :=
by { rw ← mem_ℒp_one_iff_integrable at h ⊢, exact h.left_of_add_measure, }

lemma integrable.right_of_add_measure {f : α → β} (h : integrable f (μ + ν)) : integrable f ν :=
by { rw ← mem_ℒp_one_iff_integrable at h ⊢, exact h.right_of_add_measure, }

@[simp] lemma integrable_add_measure {f : α → β} :
  integrable f (μ + ν) ↔ integrable f μ ∧ integrable f ν :=
⟨λ h, ⟨h.left_of_add_measure, h.right_of_add_measure⟩, λ h, h.1.add_measure h.2⟩

@[simp] lemma integrable_zero_measure {m : measurable_space α} {f : α → β} :
  integrable f (0 : measure α) :=
⟨ae_strongly_measurable_zero_measure f, has_finite_integral_zero_measure f⟩

theorem integrable_finset_sum_measure {ι} {m : measurable_space α} {f : α → β}
  {μ : ι → measure α} {s : finset ι} :
  integrable f (∑ i in s, μ i) ↔ ∀ i ∈ s, integrable f (μ i) :=
by induction s using finset.induction_on; simp [*]

lemma integrable.smul_measure {f : α → β} (h : integrable f μ) {c : ℝ≥0∞} (hc : c ≠ ∞) :
  integrable f (c • μ) :=
by { rw ← mem_ℒp_one_iff_integrable at h ⊢, exact h.smul_measure hc, }

lemma integrable_smul_measure {f : α → β} {c : ℝ≥0∞} (h₁ : c ≠ 0) (h₂ : c ≠ ∞) :
  integrable f (c • μ) ↔ integrable f μ :=
⟨λ h, by simpa only [smul_smul, ennreal.inv_mul_cancel h₁ h₂, one_smul]
  using h.smul_measure (ennreal.inv_ne_top.2 h₁), λ h, h.smul_measure h₂⟩

lemma integrable_inv_smul_measure {f : α → β} {c : ℝ≥0∞} (h₁ : c ≠ 0) (h₂ : c ≠ ∞) :
  integrable f (c⁻¹ • μ) ↔ integrable f μ :=
integrable_smul_measure (by simpa using h₂) (by simpa using h₁)

lemma integrable.to_average {f : α → β} (h : integrable f μ) :
  integrable f ((μ univ)⁻¹ • μ) :=
begin
  rcases eq_or_ne μ 0 with rfl|hne,
  { rwa smul_zero },
  { apply h.smul_measure, simpa }
end

lemma integrable_average [is_finite_measure μ] {f : α → β} :
  integrable f ((μ univ)⁻¹ • μ) ↔ integrable f μ :=
(eq_or_ne μ 0).by_cases (λ h, by simp [h]) $ λ h,
  integrable_smul_measure (ennreal.inv_ne_zero.2 $ measure_ne_top _ _)
    (ennreal.inv_ne_top.2 $ mt measure.measure_univ_eq_zero.1 h)

lemma integrable_map_measure {f : α → δ} {g : δ → β}
  (hg : ae_strongly_measurable g (measure.map f μ)) (hf : ae_measurable f μ) :
  integrable g (measure.map f μ) ↔ integrable (g ∘ f) μ :=
by { simp_rw ← mem_ℒp_one_iff_integrable, exact mem_ℒp_map_measure_iff hg hf, }

lemma integrable.comp_ae_measurable {f : α → δ} {g : δ → β}
  (hg : integrable g (measure.map f μ)) (hf : ae_measurable f μ) : integrable (g ∘ f) μ :=
(integrable_map_measure hg.ae_strongly_measurable hf).mp hg

lemma integrable.comp_measurable {f : α → δ} {g : δ → β}
  (hg : integrable g (measure.map f μ)) (hf : measurable f) : integrable (g ∘ f) μ :=
hg.comp_ae_measurable hf.ae_measurable

lemma _root_.measurable_embedding.integrable_map_iff
  {f : α → δ} (hf : measurable_embedding f) {g : δ → β} :
  integrable g (measure.map f μ) ↔ integrable (g ∘ f) μ :=
by { simp_rw ← mem_ℒp_one_iff_integrable, exact hf.mem_ℒp_map_measure_iff, }

lemma integrable_map_equiv (f : α ≃ᵐ δ) (g : δ → β) :
  integrable g (measure.map f μ) ↔ integrable (g ∘ f) μ :=
by { simp_rw ← mem_ℒp_one_iff_integrable, exact f.mem_ℒp_map_measure_iff, }

lemma measure_preserving.integrable_comp {ν : measure δ} {g : δ → β}
  {f : α → δ} (hf : measure_preserving f μ ν) (hg : ae_strongly_measurable g ν) :
  integrable (g ∘ f) μ ↔ integrable g ν :=
by { rw ← hf.map_eq at hg ⊢, exact (integrable_map_measure hg hf.measurable.ae_measurable).symm }

lemma measure_preserving.integrable_comp_emb {f : α → δ} {ν} (h₁ : measure_preserving f μ ν)
  (h₂ : measurable_embedding f) {g : δ → β} :
  integrable (g ∘ f) μ ↔ integrable g ν :=
h₁.map_eq ▸ iff.symm h₂.integrable_map_iff

lemma lintegral_edist_lt_top {f g : α → β}
  (hf : integrable f μ) (hg : integrable g μ) :
  ∫⁻ a, edist (f a) (g a) ∂μ < ∞ :=
lt_of_le_of_lt
  (lintegral_edist_triangle hf.ae_strongly_measurable ae_strongly_measurable_zero)
  (ennreal.add_lt_top.2 $ by { simp_rw [pi.zero_apply, ← has_finite_integral_iff_edist],
                               exact ⟨hf.has_finite_integral, hg.has_finite_integral⟩ })

variables (α β μ)
@[simp] lemma integrable_zero : integrable (λ _, (0 : β)) μ :=
by simp [integrable, ae_strongly_measurable_const]
variables {α β μ}

lemma integrable.add' {f g : α → β} (hf : integrable f μ) (hg : integrable g μ) :
  has_finite_integral (f + g) μ :=
calc ∫⁻ a, ‖f a + g a‖₊ ∂μ ≤ ∫⁻ a, ‖f a‖₊ + ‖g a‖₊ ∂μ :
  lintegral_mono (λ a, by exact_mod_cast nnnorm_add_le _ _)
... = _ : lintegral_nnnorm_add_left hf.ae_strongly_measurable _
... < ∞ : add_lt_top.2 ⟨hf.has_finite_integral, hg.has_finite_integral⟩

lemma integrable.add
  {f g : α → β} (hf : integrable f μ) (hg : integrable g μ) : integrable (f + g) μ :=
⟨hf.ae_strongly_measurable.add hg.ae_strongly_measurable, hf.add' hg⟩

lemma integrable_finset_sum' {ι} (s : finset ι)
  {f : ι → α → β} (hf : ∀ i ∈ s, integrable (f i) μ) : integrable (∑ i in s, f i) μ :=
finset.sum_induction f (λ g, integrable g μ) (λ _ _, integrable.add)
  (integrable_zero _ _ _) hf

lemma integrable_finset_sum {ι} (s : finset ι)
  {f : ι → α → β} (hf : ∀ i ∈ s, integrable (f i) μ) : integrable (λ a, ∑ i in s, f i a) μ :=
by simpa only [← finset.sum_apply] using integrable_finset_sum' s hf

lemma integrable.neg {f : α → β} (hf : integrable f μ) : integrable (-f) μ :=
⟨hf.ae_strongly_measurable.neg, hf.has_finite_integral.neg⟩

@[simp] lemma integrable_neg_iff {f : α → β} :
  integrable (-f) μ ↔ integrable f μ :=
⟨λ h, neg_neg f ▸ h.neg, integrable.neg⟩

lemma integrable.sub {f g : α → β}
  (hf : integrable f μ) (hg : integrable g μ) : integrable (f - g) μ :=
by simpa only [sub_eq_add_neg] using hf.add hg.neg

lemma integrable.norm {f : α → β} (hf : integrable f μ) :
  integrable (λ a, ‖f a‖) μ :=
⟨hf.ae_strongly_measurable.norm, hf.has_finite_integral.norm⟩

lemma integrable.inf {β} [normed_lattice_add_comm_group β] {f g : α → β}
  (hf : integrable f μ) (hg : integrable g μ) :
  integrable (f ⊓ g) μ :=
by { rw ← mem_ℒp_one_iff_integrable at hf hg ⊢, exact hf.inf hg, }

lemma integrable.sup {β} [normed_lattice_add_comm_group β] {f g : α → β}
  (hf : integrable f μ) (hg : integrable g μ) :
  integrable (f ⊔ g) μ :=
by { rw ← mem_ℒp_one_iff_integrable at hf hg ⊢, exact hf.sup hg, }

lemma integrable.abs {β} [normed_lattice_add_comm_group β] {f : α → β} (hf : integrable f μ) :
  integrable (λ a, |f a|) μ :=
by { rw ← mem_ℒp_one_iff_integrable at hf ⊢, exact hf.abs, }

lemma integrable.bdd_mul {F : Type*} [normed_division_ring F]
  {f g : α → F} (hint : integrable g μ) (hm : ae_strongly_measurable f μ)
  (hfbdd : ∃ C, ∀ x, ‖f x‖ ≤ C) :
  integrable (λ x, f x * g x) μ :=
begin
  casesI is_empty_or_nonempty α with hα hα,
  { rw μ.eq_zero_of_is_empty,
    exact integrable_zero_measure },
  { refine ⟨hm.mul hint.1, _⟩,
    obtain ⟨C, hC⟩ := hfbdd,
    have hCnonneg : 0 ≤ C := le_trans (norm_nonneg _) (hC hα.some),
    have : (λ x, ‖f x * g x‖₊) ≤ λ x, ⟨C, hCnonneg⟩ * ‖g x‖₊,
    { intro x,
      simp only [nnnorm_mul],
      exact mul_le_mul_of_nonneg_right (hC x) (zero_le _) },
    refine lt_of_le_of_lt (lintegral_mono_nnreal this) _,
    simp only [ennreal.coe_mul],
    rw lintegral_const_mul' _ _ ennreal.coe_ne_top,
    exact ennreal.mul_lt_top ennreal.coe_ne_top (ne_of_lt hint.2) },
end

/-- Hölder's inequality for integrable functions: the scalar multiplication of an integrable
vector-valued function by a scalar function with finite essential supremum is integrable. -/
lemma integrable.ess_sup_smul {𝕜 : Type*} [normed_field 𝕜] [normed_space 𝕜 β] {f : α → β}
  (hf : integrable f μ) {g : α → 𝕜} (g_ae_strongly_measurable : ae_strongly_measurable g μ)
  (ess_sup_g : ess_sup (λ x, (‖g x‖₊ : ℝ≥0∞)) μ ≠ ∞) :
  integrable (λ (x : α), g x • f x) μ :=
begin
  rw ← mem_ℒp_one_iff_integrable at *,
  refine ⟨g_ae_strongly_measurable.smul hf.1, _⟩,
  have h : (1:ℝ≥0∞) / 1 = 1 / ∞ + 1 / 1 := by norm_num,
  have hg' : snorm g ∞ μ ≠ ∞ := by rwa snorm_exponent_top,
  calc snorm (λ (x : α), g x • f x) 1 μ
      ≤ _ : measure_theory.snorm_smul_le_mul_snorm hf.1 g_ae_strongly_measurable h
  ... < ∞ : ennreal.mul_lt_top hg' hf.2.ne,
end

/-- Hölder's inequality for integrable functions: the scalar multiplication of an integrable
scalar-valued function by a vector-value function with finite essential supremum is integrable. -/
lemma integrable.smul_ess_sup {𝕜 : Type*} [normed_field 𝕜] [normed_space 𝕜 β] {f : α → 𝕜}
  (hf : integrable f μ) {g : α → β} (g_ae_strongly_measurable : ae_strongly_measurable g μ)
  (ess_sup_g : ess_sup (λ x, (‖g x‖₊ : ℝ≥0∞)) μ ≠ ∞) :
  integrable (λ (x : α), f x • g x) μ :=
begin
  rw ← mem_ℒp_one_iff_integrable at *,
  refine ⟨hf.1.smul g_ae_strongly_measurable, _⟩,
  have h : (1:ℝ≥0∞) / 1 = 1 / 1 + 1 / ∞ := by norm_num,
  have hg' : snorm g ∞ μ ≠ ∞ := by rwa snorm_exponent_top,
  calc snorm (λ (x : α), f x • g x) 1 μ
      ≤ _ : measure_theory.snorm_smul_le_mul_snorm g_ae_strongly_measurable hf.1 h
  ... < ∞ : ennreal.mul_lt_top hf.2.ne hg',
end

lemma integrable_norm_iff {f : α → β} (hf : ae_strongly_measurable f μ) :
  integrable (λa, ‖f a‖) μ ↔ integrable f μ :=
by simp_rw [integrable, and_iff_right hf, and_iff_right hf.norm, has_finite_integral_norm_iff]

lemma integrable_of_norm_sub_le {f₀ f₁ : α → β} {g : α → ℝ}
  (hf₁_m : ae_strongly_measurable f₁ μ)
  (hf₀_i : integrable f₀ μ)
  (hg_i : integrable g μ)
  (h : ∀ᵐ a ∂μ, ‖f₀ a - f₁ a‖ ≤ g a) :
  integrable f₁ μ :=
begin
  have : ∀ᵐ a ∂μ, ‖f₁ a‖ ≤ ‖f₀ a‖ + g a,
  { apply h.mono,
    intros a ha,
    calc ‖f₁ a‖ ≤ ‖f₀ a‖ + ‖f₀ a - f₁ a‖ : norm_le_insert _ _
    ... ≤ ‖f₀ a‖ + g a : add_le_add_left ha _ },
  exact integrable.mono' (hf₀_i.norm.add hg_i) hf₁_m this
end

lemma integrable.prod_mk {f : α → β} {g : α → γ} (hf : integrable f μ) (hg : integrable g μ) :
  integrable (λ x, (f x, g x)) μ :=
⟨hf.ae_strongly_measurable.prod_mk hg.ae_strongly_measurable,
  (hf.norm.add' hg.norm).mono $ eventually_of_forall $ λ x,
  calc max ‖f x‖ ‖g x‖ ≤ ‖f x‖ + ‖g x‖   : max_le_add_of_nonneg (norm_nonneg _) (norm_nonneg _)
                 ... ≤ ‖(‖f x‖ + ‖g x‖)‖ : le_abs_self _⟩

lemma mem_ℒp.integrable {q : ℝ≥0∞} (hq1 : 1 ≤ q) {f : α → β} [is_finite_measure μ]
  (hfq : mem_ℒp f q μ) : integrable f μ :=
mem_ℒp_one_iff_integrable.mp (hfq.mem_ℒp_of_exponent_le hq1)

/-- A non-quantitative version of Markov inequality for integrable functions: the measure of points
where `‖f x‖ ≥ ε` is finite for all positive `ε`. -/
lemma integrable.measure_ge_lt_top {f : α → β} (hf : integrable f μ) {ε : ℝ} (hε : 0 < ε) :
  μ {x | ε ≤ ‖f x‖} < ∞ :=
begin
  rw show {x | ε ≤ ‖f x‖} = {x | ennreal.of_real ε ≤ ‖f x‖₊},
    by simp only [ennreal.of_real, real.to_nnreal_le_iff_le_coe, ennreal.coe_le_coe, coe_nnnorm],
  refine (meas_ge_le_mul_pow_snorm μ one_ne_zero ennreal.one_ne_top hf.1 _).trans_lt _,
  { simpa only [ne.def, ennreal.of_real_eq_zero, not_le] using hε },
  apply ennreal.mul_lt_top,
  { simpa only [ennreal.one_to_real, ennreal.rpow_one, ne.def, ennreal.inv_eq_top,
      ennreal.of_real_eq_zero, not_le] using hε },
  simpa only [ennreal.one_to_real, ennreal.rpow_one]
    using (mem_ℒp_one_iff_integrable.2 hf).snorm_ne_top,
end

lemma lipschitz_with.integrable_comp_iff_of_antilipschitz {K K'} {f : α → β} {g : β → γ}
  (hg : lipschitz_with K g) (hg' : antilipschitz_with K' g) (g0 : g 0 = 0) :
  integrable (g ∘ f) μ ↔ integrable f μ :=
by simp [← mem_ℒp_one_iff_integrable, hg.mem_ℒp_comp_iff_of_antilipschitz hg' g0]

lemma integrable.real_to_nnreal {f : α → ℝ} (hf : integrable f μ) :
  integrable (λ x, ((f x).to_nnreal : ℝ)) μ :=
begin
  refine ⟨hf.ae_strongly_measurable.ae_measurable
    .real_to_nnreal.coe_nnreal_real.ae_strongly_measurable, _⟩,
  rw has_finite_integral_iff_norm,
  refine lt_of_le_of_lt _ ((has_finite_integral_iff_norm _).1 hf.has_finite_integral),
  apply lintegral_mono,
  assume x,
  simp [ennreal.of_real_le_of_real, abs_le, le_abs_self],
end

lemma of_real_to_real_ae_eq {f : α → ℝ≥0∞} (hf : ∀ᵐ x ∂μ, f x < ∞) :
  (λ x, ennreal.of_real (f x).to_real) =ᵐ[μ] f :=
begin
  filter_upwards [hf],
  assume x hx,
  simp only [hx.ne, of_real_to_real, ne.def, not_false_iff],
end

lemma coe_to_nnreal_ae_eq {f : α → ℝ≥0∞} (hf : ∀ᵐ x ∂μ, f x < ∞) :
  (λ x, ((f x).to_nnreal : ℝ≥0∞)) =ᵐ[μ] f :=
begin
  filter_upwards [hf],
  assume x hx,
  simp only [hx.ne, ne.def, not_false_iff, coe_to_nnreal],
end

section
variables  {E : Type*} [normed_add_comm_group E] [normed_space ℝ E]

lemma integrable_with_density_iff_integrable_coe_smul
  {f : α → ℝ≥0} (hf : measurable f) {g : α → E} :
  integrable g (μ.with_density (λ x, f x)) ↔ integrable (λ x, (f x : ℝ) • g x) μ :=
begin
  by_cases H : ae_strongly_measurable (λ (x : α), (f x : ℝ) • g x) μ,
  { simp only [integrable, ae_strongly_measurable_with_density_iff hf, has_finite_integral, H,
      true_and],
    rw lintegral_with_density_eq_lintegral_mul₀' hf.coe_nnreal_ennreal.ae_measurable,
    { congr',
      ext1 x,
      simp only [nnnorm_smul, nnreal.nnnorm_eq, coe_mul, pi.mul_apply] },
    { rw ae_measurable_with_density_ennreal_iff hf,
      convert H.ennnorm,
      ext1 x,
      simp only [nnnorm_smul, nnreal.nnnorm_eq, coe_mul] } },
  { simp only [integrable, ae_strongly_measurable_with_density_iff hf, H, false_and] }
end

lemma integrable_with_density_iff_integrable_smul {f : α → ℝ≥0} (hf : measurable f) {g : α → E} :
  integrable g (μ.with_density (λ x, f x)) ↔ integrable (λ x, f x • g x) μ :=
integrable_with_density_iff_integrable_coe_smul hf

lemma integrable_with_density_iff_integrable_smul'
  {f : α → ℝ≥0∞} (hf : measurable f) (hflt : ∀ᵐ x ∂μ, f x < ∞) {g : α → E} :
  integrable g (μ.with_density f) ↔ integrable (λ x, (f x).to_real • g x) μ :=
begin
  rw [← with_density_congr_ae (coe_to_nnreal_ae_eq hflt),
      integrable_with_density_iff_integrable_smul],
  { refl },
  { exact hf.ennreal_to_nnreal },
end

lemma integrable_with_density_iff_integrable_coe_smul₀
  {f : α → ℝ≥0} (hf : ae_measurable f μ) {g : α → E} :
  integrable g (μ.with_density (λ x, f x)) ↔ integrable (λ x, (f x : ℝ) • g x) μ :=
calc
integrable g (μ.with_density (λ x, f x))
    ↔ integrable g (μ.with_density (λ x, hf.mk f x)) :
begin
  suffices : (λ x, (f x : ℝ≥0∞)) =ᵐ[μ] (λ x, hf.mk f x), by rw with_density_congr_ae this,
  filter_upwards [hf.ae_eq_mk] with x hx,
  simp [hx],
end
... ↔ integrable (λ x, (hf.mk f x : ℝ) • g x) μ :
  integrable_with_density_iff_integrable_coe_smul hf.measurable_mk
... ↔ integrable (λ x, (f x : ℝ) • g x) μ :
begin
  apply integrable_congr,
  filter_upwards [hf.ae_eq_mk] with x hx,
  simp [hx],
end

lemma integrable_with_density_iff_integrable_smul₀
  {f : α → ℝ≥0} (hf : ae_measurable f μ) {g : α → E} :
  integrable g (μ.with_density (λ x, f x)) ↔ integrable (λ x, f x • g x) μ :=
integrable_with_density_iff_integrable_coe_smul₀ hf

end

lemma integrable_with_density_iff {f : α → ℝ≥0∞} (hf : measurable f)
  (hflt : ∀ᵐ x ∂μ, f x < ∞) {g : α → ℝ} :
  integrable g (μ.with_density f) ↔ integrable (λ x, g x * (f x).to_real) μ :=
begin
  have : (λ x, g x * (f x).to_real) = (λ x, (f x).to_real • g x), by simp [mul_comm],
  rw this,
  exact integrable_with_density_iff_integrable_smul' hf hflt,
end

section
variables {E : Type*} [normed_add_comm_group E] [normed_space ℝ E]

lemma mem_ℒ1_smul_of_L1_with_density {f : α → ℝ≥0} (f_meas : measurable f)
  (u : Lp E 1 (μ.with_density (λ x, f x))) :
  mem_ℒp (λ x, f x • u x) 1 μ :=
mem_ℒp_one_iff_integrable.2 $ (integrable_with_density_iff_integrable_smul f_meas).1 $
mem_ℒp_one_iff_integrable.1 (Lp.mem_ℒp u)

variable (μ)
/-- The map `u ↦ f • u` is an isometry between the `L^1` spaces for `μ.with_density f` and `μ`. -/
noncomputable def with_density_smul_li {f : α → ℝ≥0} (f_meas : measurable f) :
  Lp E 1 (μ.with_density (λ x, f x)) →ₗᵢ[ℝ] Lp E 1 μ :=
{ to_fun := λ u, (mem_ℒ1_smul_of_L1_with_density f_meas u).to_Lp _,
  map_add' :=
  begin
    assume u v,
    ext1,
    filter_upwards [(mem_ℒ1_smul_of_L1_with_density f_meas u).coe_fn_to_Lp,
      (mem_ℒ1_smul_of_L1_with_density f_meas v).coe_fn_to_Lp,
      (mem_ℒ1_smul_of_L1_with_density f_meas (u + v)).coe_fn_to_Lp,
      Lp.coe_fn_add ((mem_ℒ1_smul_of_L1_with_density f_meas u).to_Lp _)
        ((mem_ℒ1_smul_of_L1_with_density f_meas v).to_Lp _),
      (ae_with_density_iff f_meas.coe_nnreal_ennreal).1 (Lp.coe_fn_add u v)],
    assume x hu hv huv h' h'',
    rw [huv, h', pi.add_apply, hu, hv],
    rcases eq_or_ne (f x) 0 with hx|hx,
    { simp only [hx, zero_smul, add_zero] },
    { rw [h'' _, pi.add_apply, smul_add],
      simpa only [ne.def, ennreal.coe_eq_zero] using hx }
  end,
  map_smul' :=
  begin
    assume r u,
    ext1,
    filter_upwards [(ae_with_density_iff f_meas.coe_nnreal_ennreal).1 (Lp.coe_fn_smul r u),
      (mem_ℒ1_smul_of_L1_with_density f_meas (r • u)).coe_fn_to_Lp,
      Lp.coe_fn_smul r ((mem_ℒ1_smul_of_L1_with_density f_meas u).to_Lp _),
      (mem_ℒ1_smul_of_L1_with_density f_meas u).coe_fn_to_Lp],
    assume x h h' h'' h''',
    rw [ring_hom.id_apply, h', h'', pi.smul_apply, h'''],
    rcases eq_or_ne (f x) 0 with hx|hx,
    { simp only [hx, zero_smul, smul_zero] },
    { rw [h _, smul_comm, pi.smul_apply],
      simpa only [ne.def, ennreal.coe_eq_zero] using hx }
  end,
  norm_map' :=
  begin
    assume u,
    simp only [snorm, linear_map.coe_mk, Lp.norm_to_Lp, one_ne_zero, ennreal.one_ne_top,
      ennreal.one_to_real, if_false, snorm', ennreal.rpow_one, _root_.div_one, Lp.norm_def],
    rw lintegral_with_density_eq_lintegral_mul_non_measurable _ f_meas.coe_nnreal_ennreal
      (filter.eventually_of_forall (λ x, ennreal.coe_lt_top)),
    congr' 1,
    apply lintegral_congr_ae,
    filter_upwards [(mem_ℒ1_smul_of_L1_with_density f_meas u).coe_fn_to_Lp] with x hx,
    rw [hx, pi.mul_apply],
    change ↑‖(f x : ℝ) • u x‖₊ = ↑(f x) * ↑‖u x‖₊,
    simp only [nnnorm_smul, nnreal.nnnorm_eq, ennreal.coe_mul],
  end }

@[simp] lemma with_density_smul_li_apply {f : α → ℝ≥0} (f_meas : measurable f)
  (u : Lp E 1 (μ.with_density (λ x, f x))) :
  with_density_smul_li μ f_meas u =
    (mem_ℒ1_smul_of_L1_with_density f_meas u).to_Lp (λ x, f x • u x) :=
rfl

end

lemma mem_ℒ1_to_real_of_lintegral_ne_top
  {f : α → ℝ≥0∞} (hfm : ae_measurable f μ) (hfi : ∫⁻ x, f x ∂μ ≠ ∞) :
  mem_ℒp (λ x, (f x).to_real) 1 μ :=
begin
  rw [mem_ℒp, snorm_one_eq_lintegral_nnnorm],
  exact ⟨(ae_measurable.ennreal_to_real hfm).ae_strongly_measurable,
          has_finite_integral_to_real_of_lintegral_ne_top hfi⟩
end

lemma integrable_to_real_of_lintegral_ne_top
  {f : α → ℝ≥0∞} (hfm : ae_measurable f μ) (hfi : ∫⁻ x, f x ∂μ ≠ ∞) :
  integrable (λ x, (f x).to_real) μ :=
mem_ℒp_one_iff_integrable.1 $ mem_ℒ1_to_real_of_lintegral_ne_top hfm hfi

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

lemma integrable.pos_part {f : α → ℝ} (hf : integrable f μ) : integrable (λ a, max (f a) 0) μ :=
⟨(hf.ae_strongly_measurable.ae_measurable.max ae_measurable_const).ae_strongly_measurable,
  hf.has_finite_integral.max_zero⟩

lemma integrable.neg_part {f : α → ℝ} (hf : integrable f μ) : integrable (λ a, max (-f a) 0) μ :=
hf.neg.pos_part

end pos_part

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

lemma integrable.smul (c : 𝕜) {f : α → β}
  (hf : integrable f μ) : integrable (c • f) μ :=
⟨hf.ae_strongly_measurable.const_smul c, hf.has_finite_integral.smul c⟩

lemma integrable_smul_iff {c : 𝕜} (hc : c ≠ 0) (f : α → β) :
  integrable (c • f) μ ↔ integrable f μ :=
and_congr (ae_strongly_measurable_const_smul_iff₀ hc) (has_finite_integral_smul_iff hc f)

lemma integrable.smul_of_top_right {f : α → β} {φ : α → 𝕜}
  (hf : integrable f μ) (hφ : mem_ℒp φ ∞ μ) :
  integrable (φ • f) μ :=
by { rw ← mem_ℒp_one_iff_integrable at hf ⊢, exact mem_ℒp.smul_of_top_right hf hφ }

lemma integrable.smul_of_top_left {f : α → β} {φ : α → 𝕜}
  (hφ : integrable φ μ) (hf : mem_ℒp f ∞ μ) :
  integrable (φ • f) μ :=
by { rw ← mem_ℒp_one_iff_integrable at hφ ⊢, exact mem_ℒp.smul_of_top_left hf hφ }

lemma integrable.smul_const {f : α → 𝕜} (hf : integrable f μ) (c : β) :
  integrable (λ x, f x • c) μ :=
hf.smul_of_top_left (mem_ℒp_top_const c)

end normed_space

section normed_space_over_complete_field
variables {𝕜 : Type*} [nontrivially_normed_field 𝕜] [complete_space 𝕜]
variables {E : Type*} [normed_add_comm_group E] [normed_space 𝕜 E]

lemma integrable_smul_const {f : α → 𝕜} {c : E} (hc : c ≠ 0) :
  integrable (λ x, f x • c) μ ↔ integrable f μ :=
begin
  simp_rw [integrable, ae_strongly_measurable_smul_const_iff hc, and.congr_right_iff,
    has_finite_integral, nnnorm_smul, ennreal.coe_mul],
  intro hf, rw [lintegral_mul_const' _ _ ennreal.coe_ne_top, ennreal.mul_lt_top_iff],
  have : ∀ x : ℝ≥0∞, x = 0 → x < ∞ := by simp,
  simp [hc, or_iff_left_of_imp (this _)]
end

end normed_space_over_complete_field

section is_R_or_C
variables {𝕜 : Type*} [is_R_or_C 𝕜] {f : α → 𝕜}

lemma integrable.const_mul {f : α → 𝕜} (h : integrable f μ) (c : 𝕜) :
  integrable (λ x, c * f x) μ :=
integrable.smul c h

lemma integrable.const_mul' {f : α → 𝕜} (h : integrable f μ) (c : 𝕜) :
  integrable ((λ (x : α), c) * f) μ :=
integrable.smul c h

lemma integrable.mul_const {f : α → 𝕜} (h : integrable f μ) (c : 𝕜) :
  integrable (λ x, f x * c) μ :=
by simp_rw [mul_comm, h.const_mul _]

lemma integrable.mul_const' {f : α → 𝕜} (h : integrable f μ) (c : 𝕜) :
  integrable (f * (λ (x : α), c)) μ :=
integrable.mul_const h c

lemma integrable.div_const {f : α → 𝕜} (h : integrable f μ) (c : 𝕜) :
  integrable (λ x, f x / c) μ :=
by simp_rw [div_eq_mul_inv, h.mul_const]

lemma integrable.bdd_mul' {f g : α → 𝕜} {c : ℝ} (hg : integrable g μ)
  (hf : ae_strongly_measurable f μ) (hf_bound : ∀ᵐ x ∂μ, ‖f x‖ ≤ c) :
  integrable (λ x, f x * g x) μ :=
begin
  refine integrable.mono' (hg.norm.smul c) (hf.mul hg.1) _,
  filter_upwards [hf_bound] with x hx,
  rw [pi.smul_apply, smul_eq_mul],
  exact (norm_mul_le _ _).trans (mul_le_mul_of_nonneg_right hx (norm_nonneg _)),
end

lemma integrable.re_im_iff :
  integrable (λ x, is_R_or_C.re (f x)) μ ∧ integrable (λ x, is_R_or_C.im (f x)) μ ↔
  integrable f μ :=
by { simp_rw ← mem_ℒp_one_iff_integrable, exact mem_ℒp_re_im_iff }

lemma integrable.re (hf : integrable f μ) : integrable (λ x, is_R_or_C.re (f x)) μ :=
by { rw ← mem_ℒp_one_iff_integrable at hf ⊢, exact hf.re, }

lemma integrable.im (hf : integrable f μ) : integrable (λ x, is_R_or_C.im (f x)) μ :=
by { rw ← mem_ℒp_one_iff_integrable at hf ⊢, exact hf.im, }

end is_R_or_C

section inner_product
variables {𝕜 E : Type*}
variables [is_R_or_C 𝕜] [normed_add_comm_group E] [inner_product_space 𝕜 E] {f : α → E}

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

lemma integrable.const_inner (c : E) (hf : integrable f μ) : integrable (λ x, ⟪c, f x⟫) μ :=
by { rw ← mem_ℒp_one_iff_integrable at hf ⊢, exact hf.const_inner c, }

lemma integrable.inner_const (hf : integrable f μ) (c : E) : integrable (λ x, ⟪f x, c⟫) μ :=
by { rw ← mem_ℒp_one_iff_integrable at hf ⊢, exact hf.inner_const c, }

end inner_product

section trim

variables {H : Type*} [normed_add_comm_group H] {m0 : measurable_space α} {μ' : measure α}
  {f : α → H}

lemma integrable.trim (hm : m ≤ m0) (hf_int : integrable f μ') (hf : strongly_measurable[m] f) :
  integrable f (μ'.trim hm) :=
begin
  refine ⟨hf.ae_strongly_measurable, _⟩,
  rw [has_finite_integral, lintegral_trim hm _],
  { exact hf_int.2, },
  { exact @strongly_measurable.ennnorm _ m _ _ f hf },
end

lemma integrable_of_integrable_trim (hm : m ≤ m0) (hf_int : integrable f (μ'.trim hm)) :
  integrable f μ' :=
begin
  obtain ⟨hf_meas_ae, hf⟩ := hf_int,
  refine ⟨ae_strongly_measurable_of_ae_strongly_measurable_trim hm hf_meas_ae, _⟩,
  rw has_finite_integral at hf ⊢,
  rwa lintegral_trim_ae hm _ at hf,
  exact ae_strongly_measurable.ennnorm hf_meas_ae
end

end trim

section sigma_finite

variables {E : Type*} {m0 : measurable_space α} [normed_add_comm_group E]

lemma integrable_of_forall_fin_meas_le' {μ : measure α} (hm : m ≤ m0) [sigma_finite (μ.trim hm)]
  (C : ℝ≥0∞) (hC : C < ∞) {f : α → E} (hf_meas : ae_strongly_measurable f μ)
  (hf : ∀ s, measurable_set[m] s → μ s ≠ ∞ → ∫⁻ x in s, ‖f x‖₊ ∂μ ≤ C) :
  integrable f μ :=
⟨hf_meas, (lintegral_le_of_forall_fin_meas_le' hm C hf_meas.ennnorm hf).trans_lt hC⟩

lemma integrable_of_forall_fin_meas_le [sigma_finite μ]
  (C : ℝ≥0∞) (hC : C < ∞) {f : α → E} (hf_meas : ae_strongly_measurable f μ)
  (hf : ∀ s : set α, measurable_set s → μ s ≠ ∞ → ∫⁻ x in s, ‖f x‖₊ ∂μ ≤ C) :
  integrable f μ :=
@integrable_of_forall_fin_meas_le' _ _ _ _ _ _ _ (by rwa trim_eq_self) C hC _ hf_meas hf

end sigma_finite

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

namespace ae_eq_fun

section

/-- A class of almost everywhere equal functions is `integrable` if its function representative
is integrable. -/
def integrable (f : α →ₘ[μ] β) : Prop := integrable f μ

lemma integrable_mk {f : α → β} (hf : ae_strongly_measurable f μ ) :
  (integrable (mk f hf : α →ₘ[μ] β)) ↔ measure_theory.integrable f μ :=
begin
  simp [integrable],
  apply integrable_congr,
  exact coe_fn_mk f hf
end

lemma integrable_coe_fn {f : α →ₘ[μ] β} : (measure_theory.integrable f μ) ↔ integrable f :=
by rw [← integrable_mk, mk_coe_fn]

lemma integrable_zero : integrable (0 : α →ₘ[μ] β) :=
(integrable_zero α β μ).congr (coe_fn_mk _ _).symm

end

section

lemma integrable.neg {f : α →ₘ[μ] β} : integrable f → integrable (-f) :=
induction_on f $ λ f hfm hfi, (integrable_mk _).2 ((integrable_mk hfm).1 hfi).neg

section

lemma integrable_iff_mem_L1 {f : α →ₘ[μ] β} : integrable f ↔ f ∈ (α →₁[μ] β) :=
by rw [← integrable_coe_fn, ← mem_ℒp_one_iff_integrable, Lp.mem_Lp_iff_mem_ℒp]

lemma integrable.add {f g : α →ₘ[μ] β} : integrable f → integrable g → integrable (f + g) :=
begin
  refine induction_on₂ f g (λ f hf g hg hfi hgi, _),
  simp only [integrable_mk, mk_add_mk] at hfi hgi ⊢,
  exact hfi.add hgi
end

lemma integrable.sub {f g : α →ₘ[μ] β} (hf : integrable f) (hg : integrable g) :
  integrable (f - g) :=
(sub_eq_add_neg f g).symm ▸ hf.add hg.neg

end

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

lemma integrable.smul {c : 𝕜} {f : α →ₘ[μ] β} : integrable f → integrable (c • f) :=
induction_on f $ λ f hfm hfi, (integrable_mk _).2 $ ((integrable_mk hfm).1 hfi).smul _

end normed_space

end

end ae_eq_fun

namespace L1

lemma integrable_coe_fn (f : α →₁[μ] β) :
  integrable f μ :=
by { rw ← mem_ℒp_one_iff_integrable, exact Lp.mem_ℒp f }

lemma has_finite_integral_coe_fn (f : α →₁[μ] β) :
  has_finite_integral f μ :=
(integrable_coe_fn f).has_finite_integral

lemma strongly_measurable_coe_fn (f : α →₁[μ] β) : strongly_measurable f :=
Lp.strongly_measurable f

lemma measurable_coe_fn [measurable_space β] [borel_space β] (f : α →₁[μ] β) :
  measurable f :=
(Lp.strongly_measurable f).measurable

lemma ae_strongly_measurable_coe_fn (f : α →₁[μ] β) : ae_strongly_measurable f μ :=
Lp.ae_strongly_measurable f

lemma ae_measurable_coe_fn [measurable_space β] [borel_space β] (f : α →₁[μ] β) :
  ae_measurable f μ :=
(Lp.strongly_measurable f).measurable.ae_measurable

lemma edist_def (f g : α →₁[μ] β) :
  edist f g = ∫⁻ a, edist (f a) (g a) ∂μ :=
by { simp [Lp.edist_def, snorm, snorm'], simp [edist_eq_coe_nnnorm_sub] }

lemma dist_def (f g : α →₁[μ] β) :
  dist f g = (∫⁻ a, edist (f a) (g a) ∂μ).to_real :=
by { simp [Lp.dist_def, snorm, snorm'], simp [edist_eq_coe_nnnorm_sub] }

lemma norm_def (f : α →₁[μ] β) :
  ‖f‖ = (∫⁻ a, ‖f a‖₊ ∂μ).to_real :=
by { simp [Lp.norm_def, snorm, snorm'] }

/-- Computing the norm of a difference between two L¹-functions. Note that this is not a
  special case of `norm_def` since `(f - g) x` and `f x - g x` are not equal
  (but only a.e.-equal). -/
lemma norm_sub_eq_lintegral (f g : α →₁[μ] β) :
  ‖f - g‖ = (∫⁻ x, (‖f x - g x‖₊ : ℝ≥0∞) ∂μ).to_real :=
begin
  rw [norm_def],
  congr' 1,
  rw lintegral_congr_ae,
  filter_upwards [Lp.coe_fn_sub f g] with _ ha,
  simp only [ha, pi.sub_apply],
end

lemma of_real_norm_eq_lintegral (f : α →₁[μ] β) :
  ennreal.of_real ‖f‖ = ∫⁻ x, (‖f x‖₊ : ℝ≥0∞) ∂μ :=
by { rw [norm_def, ennreal.of_real_to_real], exact ne_of_lt (has_finite_integral_coe_fn f) }

/-- Computing the norm of a difference between two L¹-functions. Note that this is not a
  special case of `of_real_norm_eq_lintegral` since `(f - g) x` and `f x - g x` are not equal
  (but only a.e.-equal). -/
lemma of_real_norm_sub_eq_lintegral (f g : α →₁[μ] β) :
  ennreal.of_real ‖f - g‖ = ∫⁻ x, (‖f x - g x‖₊ : ℝ≥0∞) ∂μ :=
begin
  simp_rw [of_real_norm_eq_lintegral, ← edist_eq_coe_nnnorm],
  apply lintegral_congr_ae,
  filter_upwards [Lp.coe_fn_sub f g] with _ ha,
  simp only [ha, pi.sub_apply],
end

end L1

namespace integrable

/-- Construct the equivalence class `[f]` of an integrable function `f`, as a member of the
space `L1 β 1 μ`. -/
def to_L1 (f : α → β) (hf : integrable f μ) : α →₁[μ] β :=
(mem_ℒp_one_iff_integrable.2 hf).to_Lp f

@[simp] lemma to_L1_coe_fn (f : α →₁[μ] β) (hf : integrable f μ) : hf.to_L1 f = f :=
by simp [integrable.to_L1]

lemma coe_fn_to_L1 {f : α → β} (hf : integrable f μ) : hf.to_L1 f =ᵐ[μ] f :=
ae_eq_fun.coe_fn_mk _ _

@[simp] lemma to_L1_zero (h : integrable (0 : α → β) μ) : h.to_L1 0 = 0 := rfl

@[simp] lemma to_L1_eq_mk (f : α → β) (hf : integrable f μ) :
  (hf.to_L1 f : α →ₘ[μ] β) = ae_eq_fun.mk f hf.ae_strongly_measurable :=
rfl

@[simp] lemma to_L1_eq_to_L1_iff (f g : α → β) (hf : integrable f μ) (hg : integrable g μ) :
  to_L1 f hf = to_L1 g hg ↔ f =ᵐ[μ] g :=
mem_ℒp.to_Lp_eq_to_Lp_iff _ _

lemma to_L1_add (f g : α → β) (hf : integrable f μ) (hg : integrable g μ) :
  to_L1 (f + g) (hf.add hg) = to_L1 f hf + to_L1 g hg := rfl

lemma to_L1_neg (f : α → β) (hf : integrable f μ) :
  to_L1 (- f) (integrable.neg hf) = - to_L1 f hf := rfl

lemma to_L1_sub (f g : α → β) (hf : integrable f μ) (hg : integrable g μ) :
  to_L1 (f - g) (hf.sub hg) = to_L1 f hf - to_L1 g hg := rfl

lemma norm_to_L1 (f : α → β) (hf : integrable f μ) :
  ‖hf.to_L1 f‖ = ennreal.to_real (∫⁻ a, edist (f a) 0 ∂μ) :=
by { simp [to_L1, snorm, snorm'], simp [edist_eq_coe_nnnorm] }

lemma norm_to_L1_eq_lintegral_norm (f : α → β) (hf : integrable f μ) :
  ‖hf.to_L1 f‖ = ennreal.to_real (∫⁻ a, (ennreal.of_real ‖f a‖) ∂μ) :=
by { rw [norm_to_L1, lintegral_norm_eq_lintegral_edist] }

@[simp] lemma edist_to_L1_to_L1 (f g : α → β) (hf : integrable f μ) (hg : integrable g μ) :
  edist (hf.to_L1 f) (hg.to_L1 g) = ∫⁻ a, edist (f a) (g a) ∂μ :=
by { simp [integrable.to_L1, snorm, snorm'], simp [edist_eq_coe_nnnorm_sub] }

@[simp] lemma edist_to_L1_zero (f : α → β) (hf : integrable f μ) :
  edist (hf.to_L1 f) 0 = ∫⁻ a, edist (f a) 0 ∂μ :=
by { simp [integrable.to_L1, snorm, snorm'], simp [edist_eq_coe_nnnorm] }

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

lemma to_L1_smul (f : α → β) (hf : integrable f μ) (k : 𝕜) :
  to_L1 (λ a, k • f a) (hf.smul k) = k • to_L1 f hf := rfl

lemma to_L1_smul' (f : α → β) (hf : integrable f μ) (k : 𝕜) :
  to_L1 (k • f) (hf.smul k) = k • to_L1 f hf := rfl

end integrable

end measure_theory

open measure_theory

variables {E : Type*} [normed_add_comm_group E]
          {𝕜 : Type*} [nontrivially_normed_field 𝕜] [normed_space 𝕜 E]
          {H : Type*} [normed_add_comm_group H] [normed_space 𝕜 H]

lemma measure_theory.integrable.apply_continuous_linear_map {φ : α → H →L[𝕜] E}
  (φ_int : integrable φ μ) (v : H) : integrable (λ a, φ a v) μ :=
(φ_int.norm.mul_const ‖v‖).mono' (φ_int.ae_strongly_measurable.apply_continuous_linear_map v)
  (eventually_of_forall $ λ a, (φ a).le_op_norm v)

lemma continuous_linear_map.integrable_comp {φ : α → H} (L : H →L[𝕜] E)
  (φ_int : integrable φ μ) : integrable (λ (a : α), L (φ a)) μ :=
((integrable.norm φ_int).const_mul ‖L‖).mono'
  (L.continuous.comp_ae_strongly_measurable φ_int.ae_strongly_measurable)
  (eventually_of_forall $ λ a, L.le_op_norm (φ a))


import data.real.basic
variables x t : ℝ

theorem Q0305a (H:t>0) : abs x < t ↔ -t < x ∧ x < t := sorry

theorem Q0305b : abs(x+1)<3 ↔ -4<x ∧ x<2 := sorry

theorem Q0305c : abs (x-2) < abs (x-4) ↔ x < 3 := sorry


import regular_sequence
import reals

namespace regular_sequence

def canonical_bound(x : regular_sequence): ℕ :=
  nat.ceil (|x 1|) + 2

lemma abs_le_canonical_bound(x : regular_sequence) (n: ℕ) (n_pos: 0 < n): |x n| ≤ canonical_bound x :=
  begin
    calc |x n| = |x n - x 1 + x 1| : by simp
          ... ≤ |x n - x 1| + |x 1| : abs_add _ _
          ... ≤ (n:ℚ)⁻¹ + (1:ℚ)⁻¹ + |x 1|:
            begin
              apply add_le_add_right,
              {
                have := x.property n_pos (nat.succ_pos 0),
                simp at this,
                exact this,
              },
            end
          ... ≤ 1 + 1 + |x 1| : by { simp,
            rw inv_le,
            {
              simp only [nat.one_le_cast, inv_one],
              exact n_pos,
            },
            {
              simp,
              exact n_pos,
            },
            {
              exact zero_lt_one,
            },
          }
          ... ≤ canonical_bound x :
          begin
            rw canonical_bound,
            simp,
            norm_num,
            rw add_comm,
            exact add_le_add_right (nat.le_ceil _) 2,
          end
  end

def mul: regular_sequence → regular_sequence → regular_sequence :=
  λ x y,
  { val := let k := max (canonical_bound x) (canonical_bound y) in
          λ n, x (2*k*n) * y (2*k*n),
    property :=
    begin
      intros m n m_pos n_pos,
      set kx := canonical_bound x with h_kx,
      set ky := canonical_bound y with h_ky,
      set k := max kx ky with hk,
      simp,

      have k_pos: 0 < k,
        {
          rw hk,
          rw lt_max_iff,
          left,
          rw h_kx,
          unfold canonical_bound,
          simp,
        },

      have two_k_m_pos: 0 < 2 * k * m,
        {
          apply nat.mul_pos,
          exact nat.succ_mul_pos 1 k_pos,
          assumption,
        },

      have two_k_n_pos: 0 < 2 * k * n,
        {
          apply nat.mul_pos,
          exact nat.succ_mul_pos 1 k_pos,
          assumption,
        },

      have hx := abs_le_canonical_bound x,
      have hy := abs_le_canonical_bound y,
      cases x,
      cases y,
      obtain := x_property two_k_m_pos two_k_n_pos,
      obtain := y_property two_k_m_pos two_k_n_pos,

      change |x_val (2 * k * m) * y_val (2 * k * m) - x_val (2 * k * n) * y_val (2 * k * n)| ≤ (m:ℚ)⁻¹ + (n:ℚ)⁻¹,

      calc |x_val (2 * k * m) * y_val (2 * k * m) - (x_val (2 * k * n) * y_val (2 * k * n))|
       = |(x_val (2*k*m)) * (y_val (2*k*m) - y_val (2*k*n)) + (y_val (2*k*n)) * (x_val (2*k*m) - x_val (2*k*n))| : by { congr, ring_nf,}
        ... ≤ |(x_val (2*k*m)) * (y_val (2*k*m) - y_val (2*k*n))| + |(y_val (2*k*n)) * (x_val (2*k*m) - x_val (2*k*n))| : abs_add _ _
        ... ≤ k * |(y_val (2*k*m) - y_val (2*k*n))| + k * |(x_val (2*k*m) - x_val (2*k*n))| :
        begin
          apply add_le_add,
          {
            rw abs_mul,
            apply mul_le_mul,
            {
              transitivity (kx:ℚ),
              {
                rw h_kx,
                apply hx (2*k*m) two_k_m_pos,
              },
              {
                rw hk,
                norm_cast,
                exact le_max_left kx ky,
              },
            },
            {
              refl,
            },
            {
              exact abs_nonneg (y_val (2 * k * m) - y_val (2 * k * n)),
            },
            {
              exact nat.cast_nonneg k,
            },
          },
          {
            rw abs_mul,
            apply mul_le_mul,
            {
              transitivity (ky:ℚ),
              {
                rw h_ky,
                apply hy (2*k*n) two_k_n_pos,
              },
              {
                rw hk,
                norm_cast,
                exact le_max_right kx ky,
              },
            },
            {
              refl,
            },
            {
              exact abs_nonneg (x_val (2 * k * m) - x_val (2 * k * n)),
            },
            {
              exact nat.cast_nonneg k,
            },
          },
        end

        ... ≤ k*((↑(2 * k * m))⁻¹ + (↑(2 * k * n))⁻¹) + k*((↑(2 * k * m))⁻¹ + (↑(2 * k * n))⁻¹) :
        begin
          apply add_le_add;
          {
            rw mul_le_mul_left,
            {
              assumption,
            },
            {
              exact nat.cast_pos.mpr k_pos,
            },
          },
        end
       ... = (m: ℚ)⁻¹+ (n:ℚ)⁻¹ :
       begin
         rw ←mul_add,
         rw add_assoc,
         rw add_comm (↑(2 * k * m))⁻¹ (↑(2 * k * n))⁻¹,
         nth_rewrite 1 ←add_assoc,
         push_cast,

         simp,
         ring_nf,
         rw add_mul,
         congr;
          {
            rw mul_comm,
            rw ←mul_assoc,
            simp,
            norm_num;
            rw mul_inv₀,
            rw mul_inv₀,
            nth_rewrite 1 mul_assoc,
            rw mul_assoc,
            nth_rewrite 1 ←mul_assoc,
            simp only [one_mul, mul_inv_cancel, ne.def, not_false_iff, bit0_eq_zero, one_ne_zero],
            rw ←mul_assoc,
            rw mul_inv_cancel,
            {
              simp,
            },
            {
              rw hk at k_pos,
              apply ne_of_gt,
              have := (@nat.cast_pos ℚ _  _ (max kx ky)).mpr,
              push_cast at this,
              exact this k_pos,
            },
          },
       end
    end
  }

instance : has_mul regular_sequence :=
  ⟨mul⟩

end regular_sequence

namespace real

def mul: real → real → real :=
  quotient.lift₂ (λ x y, ⟦regular_sequence.mul x y⟧)
  begin
    sorry,
  end

instance : has_mul real :=
  ⟨mul⟩

end real


import data.set.basic -- hide
open set -- hide

variables {X Y : Type} -- hide

/- Lemma : no-side-bar
Giving two subsets of a type `A₁ ⊆ X` `A₂ ⊆ X` and two of another type `B₁ ⊆ Y` `B₂ ⊆ Y`
satisfying `A₁ ⊇ A₂` and `B₁ ⊇ B₂`, we can prove that `A₁ × B₁ ⊇ A₂ × B₂` (as products of sets).
-/
lemma sInter_of_inter {A₁ A₂ : set X} {B₁ B₂ : set Y} (hA : A₁ ⊇ A₂) (hB : B₁ ⊇ B₂) :
  A₁.prod B₁ ⊇ A₂.prod B₂ :=
begin
  intros x hx,
  exact ⟨hA hx.1, hB hx.2⟩,
end


/-
Copyright (c) 2021 Yury Kudryashov. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yury Kudryashov
-/
import measure_theory.integral.interval_integral
import analysis.normed_space.pointwise
import analysis.special_functions.non_integrable
import analysis.analytic.basic

/-!
# Integral over a circle in `ℂ`

In this file we define `∮ z in C(c, R), f z` to be the integral $\oint_{|z-c|=|R|} f(z)\,dz$ and
prove some properties of this integral. We give definition and prove most lemmas for a function
`f : ℂ → E`, where `E` is a complex Banach space with second countable topology. For this reason,
some lemmas use, e.g., `(z - c)⁻¹ • f z` instead of `f z / (z - c)`.

## Main definitions

* `circle_map c R`: the exponential map $θ ↦ c + R e^{θi}$;

* `circle_integrable f c R`: a function `f : ℂ → E` is integrable on the circle with center `c` and
  radius `R` if `f ∘ circle_map c R` is integrable on `[0, 2π]`;

* `circle_integral f c R`: the integral $\oint_{|z-c|=|R|} f(z)\,dz$, defined as
  $\int_{0}^{2π}(c + Re^{θ i})' f(c+Re^{θ i})\,dθ$;

* `cauchy_power_series f c R`: the power series that is equal to
  $\sum_{n=0}^{\infty} \oint_{|z-c|=R} \left(\frac{w-c}{z - c}\right)^n \frac{1}{z-c}f(z)\,dz$ at
  `w - c`. The coefficients of this power series depend only on `f ∘ circle_map c R`, and the power
  series converges to `f w` if `f` is differentiable on the closed ball `metric.closed_ball c R`
  and `w` belongs to the corresponding open ball.

## Main statements

* `has_fpower_series_on_cauchy_integral`: for any circle integrable function `f`, the power series
  `cauchy_power_series f c R`, `R > 0`, converges to the Cauchy integral
  `(2 * π * I : ℂ)⁻¹ • ∮ z in C(c, R), (z - w)⁻¹ • f z` on the open disc `metric.ball c R`;

* `circle_integral.integral_sub_zpow_of_undef`, `circle_integral.integral_sub_zpow_of_ne`, and
  `circle_integral.integral_sub_inv_of_mem_ball`: formulas for `∮ z in C(c, R), (z - w) ^ n`,
  `n : ℤ`. These lemmas cover the following cases:

  - `circle_integral.integral_sub_zpow_of_undef`, `n < 0` and `|w - c| = |R|`: in this case the
    function is not integrable, so the integral is equal to its default value (zero);

  - `circle_integral.integral_sub_zpow_of_ne`, `n ≠ -1`: in the cases not covered by the previous
    lemma, we have `(z - w) ^ n = ((z - w) ^ (n + 1) / (n + 1))'`, thus the integral equals zero;

  - `circle_integral.integral_sub_inv_of_mem_ball`, `n = -1`, `|w - c| < R`: in this case the
    integral is equal to `2πi`.

  The case `n = -1`, `|w -c| > R` is not covered by these lemmas. While it is possible to construct
  an explicit primitive, it is easier to apply Cauchy theorem, so we postpone the proof till we have
  this theorem (see #10000).

## Notation

- `∮ z in C(c, R), f z`: notation for the integral $\oint_{|z-c|=|R|} f(z)\,dz$, defined as
  $\int_{0}^{2π}(c + Re^{θ i})' f(c+Re^{θ i})\,dθ$.

## Tags

integral, circle, Cauchy integral
-/

variables {E : Type*} [measurable_space E] [normed_group E]

noncomputable theory

open_locale real nnreal interval pointwise topological_space
open complex measure_theory topological_space metric function set filter asymptotics

/-!
### `circle_map`, a parametrization of a circle
-/

/-- The exponential map $θ ↦ c + R e^{θi}$. The range of this map is the circle in `ℂ` with center
`c` and radius `|R|`. -/
def circle_map (c : ℂ) (R : ℝ) : ℝ → ℂ := λ θ, c + R * exp (θ * I)

/-- `circle_map` is `2π`-periodic. -/
lemma periodic_circle_map (c : ℂ) (R : ℝ) : periodic (circle_map c R) (2 * π) :=
λ θ, by simp [circle_map, add_mul, exp_periodic _]

@[simp] lemma circle_map_sub_center (c : ℂ) (R : ℝ) (θ : ℝ) :
  circle_map c R θ - c = circle_map 0 R θ :=
by simp [circle_map]

@[simp] lemma abs_circle_map_zero (R : ℝ) (θ : ℝ) : abs (circle_map 0 R θ) = |R| :=
by simp [circle_map]

lemma circle_map_mem_sphere' (c : ℂ) (R : ℝ) (θ : ℝ) : circle_map c R θ ∈ sphere c (|R|) :=
by simp

lemma circle_map_mem_sphere (c : ℂ) {R : ℝ} (hR : 0 ≤ R) (θ : ℝ) : circle_map c R θ ∈ sphere c R :=
by simpa only [_root_.abs_of_nonneg hR] using circle_map_mem_sphere' c R θ

lemma circle_map_mem_closed_ball (c : ℂ) {R : ℝ} (hR : 0 ≤ R) (θ : ℝ) :
  circle_map c R θ ∈ closed_ball c R :=
sphere_subset_closed_ball (circle_map_mem_sphere c hR θ)

/-- The range of `circle_map c R` is the circle with center `c` and radius `|R|`. -/
@[simp] lemma range_circle_map (c : ℂ) (R : ℝ) : range (circle_map c R) = sphere c (|R|) :=
calc range (circle_map c R) = c +ᵥ R • range (λ θ : ℝ, exp (θ * I)) :
  by simp only [← image_vadd, ← image_smul, ← range_comp, vadd_eq_add, circle_map, (∘), real_smul]
... = sphere c (|R|) : by simp [smul_sphere R (0 : ℂ) zero_le_one, real.norm_eq_abs]

/-- The image of `(0, 2π]` under `circle_map c R` is the circle with center `c` and radius `|R|`. -/
@[simp] lemma image_circle_map_Ioc (c : ℂ) (R : ℝ) :
  circle_map c R '' Ioc 0 (2 * π) = sphere c (|R|) :=
by rw [← range_circle_map, ← (periodic_circle_map c R).image_Ioc real.two_pi_pos 0, zero_add]

@[simp] lemma circle_map_eq_center_iff {c : ℂ} {R : ℝ} {θ : ℝ} : circle_map c R θ = c ↔ R = 0 :=
by simp [circle_map, exp_ne_zero]

@[simp] lemma circle_map_zero_radius (c : ℂ) : circle_map c 0 = const ℝ c :=
funext $ λ θ, circle_map_eq_center_iff.2 rfl

lemma circle_map_ne_center {c : ℂ} {R : ℝ} (hR : R ≠ 0) {θ : ℝ} : circle_map c R θ ≠ c :=
mt circle_map_eq_center_iff.1 hR

lemma has_deriv_at_circle_map (c : ℂ) (R : ℝ) (θ : ℝ) :
  has_deriv_at (circle_map c R) (circle_map 0 R θ * I) θ :=
by simpa only [mul_assoc, one_mul, of_real_clm_apply, circle_map, of_real_one, zero_add]
 using ((of_real_clm.has_deriv_at.mul_const I).cexp_real.const_mul (R : ℂ)).const_add c

/- TODO: prove `times_cont_diff ℝ (circle_map c R)`. This needs a version of `times_cont_diff.mul`
for multiplication in a normed algebra over the base field. -/

lemma differentiable_circle_map (c : ℂ) (R : ℝ) :
  differentiable ℝ (circle_map c R) :=
λ θ, (has_deriv_at_circle_map c R θ).differentiable_at

@[continuity] lemma continuous_circle_map (c : ℂ) (R : ℝ) : continuous (circle_map c R) :=
(differentiable_circle_map c R).continuous

@[measurability] lemma measurable_circle_map (c : ℂ) (R : ℝ) : measurable (circle_map c R) :=
(continuous_circle_map c R).measurable

@[simp] lemma deriv_circle_map (c : ℂ) (R : ℝ) (θ : ℝ) :
  deriv (circle_map c R) θ = circle_map 0 R θ * I :=
(has_deriv_at_circle_map _ _ _).deriv

lemma deriv_circle_map_eq_zero_iff {c : ℂ} {R : ℝ} {θ : ℝ} :
  deriv (circle_map c R) θ = 0 ↔ R = 0 :=
by simp [I_ne_zero]

lemma deriv_circle_map_ne_zero {c : ℂ} {R : ℝ} {θ : ℝ} (hR : R ≠ 0) :
  deriv (circle_map c R) θ ≠ 0 :=
mt deriv_circle_map_eq_zero_iff.1 hR

lemma lipschitz_with_circle_map (c : ℂ) (R : ℝ) :
  lipschitz_with R.nnabs (circle_map c R) :=
lipschitz_with_of_nnnorm_deriv_le (differentiable_circle_map _ _) $ λ θ,
  nnreal.coe_le_coe.1 $ by simp

/-!
### Integrability of a function on a circle
-/

/-- We say that a function `f : ℂ → E` is integrable on the circle with center `c` and radius `R` if
the function `f ∘ circle_map c R` is integrable on `[0, 2π]`.

Note that the actual function used in the definition of `circle_integral` is
`(deriv (circle_map c R) θ) • f (circle_map c R θ)`. Integrability of this function is equivalent
to integrability of `f ∘ circle_map c R` whenever `R ≠ 0`. -/
def circle_integrable (f : ℂ → E) (c : ℂ) (R : ℝ) : Prop :=
interval_integrable (λ θ : ℝ, f (circle_map c R θ)) volume 0 (2 * π)

@[simp] lemma circle_integrable_const (a : E) (c : ℂ) (R : ℝ) :
  circle_integrable (λ _, a) c R :=
interval_integrable_const

namespace circle_integrable

variables {f g : ℂ → E} {c : ℂ} {R : ℝ}

lemma add [borel_space E] [second_countable_topology E]
  (hf : circle_integrable f c R) (hg : circle_integrable g c R) :
  circle_integrable (f + g) c R :=
hf.add hg

lemma neg [borel_space E] (hf : circle_integrable f c R) : circle_integrable (-f) c R := hf.neg

/-- The function we actually integrate over `[0, 2π]` in the definition of `circle_integral` is
integrable. -/
lemma out [borel_space E] [normed_space ℂ E] [second_countable_topology E]
  (hf : circle_integrable f c R) :
  interval_integrable (λ θ : ℝ, deriv (circle_map c R) θ • f (circle_map c R θ)) volume 0 (2 * π) :=
begin
  simp only [circle_integrable, deriv_circle_map, interval_integrable_iff] at *,
  refine (hf.norm.const_mul (|R|)).mono' _ _,
  { exact (((continuous_circle_map _ _).ae_measurable _).mul_const I).smul hf.ae_measurable },
  { simp [norm_smul] }
end

end circle_integrable

@[simp] lemma circle_integrable_zero_radius {f : ℂ → E} {c : ℂ} : circle_integrable f c 0 :=
by simp [circle_integrable]

lemma circle_integrable_iff [borel_space E] [normed_space ℂ E] [second_countable_topology E]
  {f : ℂ → E} {c : ℂ} {R : ℝ} (h₀ : R ≠ 0) : circle_integrable f c R ↔
  interval_integrable (λ θ : ℝ, deriv (circle_map c R) θ • f (circle_map c R θ)) volume 0 (2 * π) :=
begin
  refine ⟨λ h, h.out, λ h, _⟩,
  simp only [circle_integrable, interval_integrable_iff, deriv_circle_map] at h ⊢,
  refine (h.norm.const_mul (|R|⁻¹)).mono' _ _,
  { have H : ∀ {θ}, circle_map 0 R θ * I ≠ 0 := λ θ, by simp [h₀, I_ne_zero],
    simpa only [inv_smul_smul₀ H]
      using (((continuous_circle_map 0 R).ae_measurable _).mul_const I).inv.smul h.ae_measurable },
  { simp [norm_smul, h₀] },
end

lemma continuous_on.circle_integrable' [borel_space E] {f : ℂ → E} {c : ℂ} {R : ℝ}
  (hf : continuous_on f (sphere c (|R|))) :
  circle_integrable f c R :=
(hf.comp_continuous (continuous_circle_map _ _)
  (circle_map_mem_sphere' _ _)).interval_integrable _ _

lemma continuous_on.circle_integrable [borel_space E] {f : ℂ → E} {c : ℂ} {R : ℝ} (hR : 0 ≤ R)
  (hf : continuous_on f (sphere c R)) :
  circle_integrable f c R :=
continuous_on.circle_integrable' $ (_root_.abs_of_nonneg hR).symm ▸ hf

/-- The function `λ z, (z - w) ^ n`, `n : ℤ`, is circle integrable on the circle with center `c` and
radius `|R|` if and only if `R = 0` or `0 ≤ n`, or `w` does not belong to this circle. -/
@[simp] lemma circle_integrable_sub_zpow_iff {c w : ℂ} {R : ℝ} {n : ℤ} :
  circle_integrable (λ z, (z - w) ^ n) c R ↔ R = 0 ∨ 0 ≤ n ∨ w ∉ sphere c (|R|) :=
begin
  split,
  { intro h, contrapose! h, rcases h with ⟨hR, hn, hw⟩,
    simp only [circle_integrable_iff hR, deriv_circle_map],
    rw ← image_circle_map_Ioc at hw, rcases hw with ⟨θ, hθ, rfl⟩,
    replace hθ : θ ∈ [0, 2 * π], from Icc_subset_interval (Ioc_subset_Icc_self hθ),
    refine not_interval_integrable_of_sub_inv_is_O_punctured _ real.two_pi_pos.ne hθ,
    set f : ℝ → ℂ := λ θ', circle_map c R θ' - circle_map c R θ,
    have : ∀ᶠ θ' in 𝓝[≠] θ, f θ' ∈ ball (0 : ℂ) 1 \ {0},
    { suffices : ∀ᶠ z in 𝓝[≠] (circle_map c R θ), z - circle_map c R θ ∈ ball (0 : ℂ) 1 \ {0},
        from ((differentiable_circle_map c R θ).has_deriv_at.tendsto_punctured_nhds
          (deriv_circle_map_ne_zero hR)).eventually this,
      filter_upwards [self_mem_nhds_within,
        mem_nhds_within_of_mem_nhds (ball_mem_nhds _ zero_lt_one)],
      simp [dist_eq, sub_eq_zero] { contextual := tt } },
    refine ((((has_deriv_at_circle_map c R θ).is_O_sub).mono inf_le_left).inv_rev
      (this.mono (λ θ', and.right))).trans _,
    refine is_O.of_bound (|R|)⁻¹ (this.mono $ λ θ' hθ', _),
    set x := abs (f θ'),
    suffices : x⁻¹ ≤ x ^ n, by simpa [inv_mul_cancel_left₀, mt _root_.abs_eq_zero.1 hR],
    have : x ∈ Ioo (0 : ℝ) 1, by simpa [and.comm, x] using hθ',
    rw ← zpow_neg_one,
    refine (zpow_strict_anti this.1 this.2).le_iff_le.2 (int.lt_add_one_iff.1 _), exact hn },
  { rintro (rfl|H),
    exacts [circle_integrable_zero_radius,
      ((continuous_on_id.sub continuous_on_const).zpow _ $ λ z hz, H.symm.imp_left $
        λ hw, sub_ne_zero.2 $ ne_of_mem_of_not_mem hz hw).circle_integrable'] },
end

@[simp] lemma circle_integrable_sub_inv_iff {c w : ℂ} {R : ℝ} :
  circle_integrable (λ z, (z - w)⁻¹) c R ↔ R = 0 ∨ w ∉ sphere c (|R|) :=
by { simp only [← zpow_neg_one, circle_integrable_sub_zpow_iff], norm_num }

variables [normed_space ℂ E] [complete_space E] [borel_space E] [second_countable_topology E]

/-- Definition for $\oint_{|z-c|=R} f(z)\,dz$. -/
def circle_integral (f : ℂ → E) (c : ℂ) (R : ℝ) : E :=
∫ (θ : ℝ) in 0..2 * π, deriv (circle_map c R) θ • f (circle_map c R θ)

notation `∮` binders ` in ` `C(` c `, ` R `)` `, ` r:(scoped:60 f, circle_integral f c R) := r

namespace circle_integral

@[simp] lemma integral_radius_zero (f : ℂ → E) (c : ℂ) : ∮ z in C(c, 0), f z = 0 :=
by simp [circle_integral]

lemma integral_congr {f g : ℂ → E} {c : ℂ} {R : ℝ} (hR : 0 ≤ R) (h : eq_on f g (sphere c R)) :
  ∮ z in C(c, R), f z = ∮ z in C(c, R), g z :=
interval_integral.integral_congr $ λ θ hθ, by simp only [h (circle_map_mem_sphere _ hR _)]

lemma integral_undef {f : ℂ → E} {c : ℂ} {R : ℝ} (hf : ¬circle_integrable f c R) :
  ∮ z in C(c, R), f z = 0 :=
begin
  rcases eq_or_ne R 0 with rfl|h0, { simp },
  exact interval_integral.integral_undef (mt (circle_integrable_iff h0).mpr hf)
end

lemma integral_sub {f g : ℂ → E} {c : ℂ} {R : ℝ} (hf : circle_integrable f c R)
  (hg : circle_integrable g c R) :
  ∮ z in C(c, R), f z - g z = (∮ z in C(c, R), f z) - ∮ z in C(c, R), g z :=
by simp only [circle_integral, smul_sub, interval_integral.integral_sub hf.out hg.out]

lemma norm_integral_le_of_norm_le_const' {f : ℂ → E} {c : ℂ} {R C : ℝ}
  (hf : ∀ z ∈ sphere c (|R|), ∥f z∥ ≤ C) :
  ∥∮ z in C(c, R), f z∥ ≤ 2 * π * |R| * C :=
calc ∥∮ z in C(c, R), f z∥ ≤ |R| * C * |2 * π - 0| :
  interval_integral.norm_integral_le_of_norm_le_const $ λ θ _,
    (calc ∥deriv (circle_map c R) θ • f (circle_map c R θ)∥ = |R| * ∥f (circle_map c R θ)∥ :
      by simp [norm_smul]
    ... ≤ |R| * C : mul_le_mul_of_nonneg_left (hf _ $ circle_map_mem_sphere' _ _ _)
      (_root_.abs_nonneg _))
... = 2 * π * |R| * C :
  by { rw [sub_zero, _root_.abs_of_pos real.two_pi_pos], ac_refl }

lemma norm_integral_le_of_norm_le_const {f : ℂ → E} {c : ℂ} {R C : ℝ} (hR : 0 ≤ R)
  (hf : ∀ z ∈ sphere c R, ∥f z∥ ≤ C) :
  ∥∮ z in C(c, R), f z∥ ≤ 2 * π * R * C :=
have |R| = R, from _root_.abs_of_nonneg hR,
calc ∥∮ z in C(c, R), f z∥ ≤ 2 * π * |R| * C :
  norm_integral_le_of_norm_le_const' $ by rwa this
... = 2 * π * R * C : by rw this

/-- If `f` is continuous on the circle `|z - c| = R`, `R > 0`, the `∥f z∥` is less than or equal to
`C : ℝ` on this circle, and this norm is strictly less than `C` at some point `z` of the circle,
then `∥∮ z in C(c, R), f z∥ < 2 * π * R * C`. -/
lemma norm_integral_lt_of_norm_le_const_of_lt {f : ℂ → E} {c : ℂ} {R C : ℝ} (hR : 0 < R)
  (hc : continuous_on f (sphere c R)) (hf : ∀ z ∈ sphere c R, ∥f z∥ ≤ C)
  (hlt : ∃ z ∈ sphere c R, ∥f z∥ < C) :
  ∥∮ z in C(c, R), f z∥ < 2 * π * R * C :=
begin
  rw [← _root_.abs_of_pos hR, ← image_circle_map_Ioc] at hlt,
  rcases hlt with ⟨_, ⟨θ₀, hmem, rfl⟩, hlt⟩,
  calc ∥∮ z in C(c, R), f z∥ ≤ ∫ θ in 0..2 * π, ∥deriv (circle_map c R) θ • f (circle_map c R θ)∥ :
    interval_integral.norm_integral_le_integral_norm real.two_pi_pos.le
  ... < ∫ θ in 0..2 * π, R * C :
    begin
      simp only [norm_smul, deriv_circle_map, norm_eq_abs, complex.abs_mul, abs_I, mul_one,
        abs_circle_map_zero, abs_of_pos hR],
      refine interval_integral.integral_lt_integral_of_continuous_on_of_le_of_exists_lt
        real.two_pi_pos _ continuous_on_const (λ θ hθ, _) ⟨θ₀, Ioc_subset_Icc_self hmem, _⟩,
      { exact continuous_on_const.mul (hc.comp (continuous_circle_map _ _).continuous_on
          (λ θ hθ, circle_map_mem_sphere _ hR.le _)).norm },
      { exact mul_le_mul_of_nonneg_left (hf _ $ circle_map_mem_sphere _ hR.le _) hR.le },
      { exact (mul_lt_mul_left hR).2 hlt }
    end
  ... = 2 * π * R * C : by simp [mul_assoc]
end

@[simp] lemma integral_smul {𝕜 : Type*} [is_R_or_C 𝕜] [normed_space 𝕜 E] [smul_comm_class 𝕜 ℂ E]
  (a : 𝕜) (f : ℂ → E) (c : ℂ) (R : ℝ) :
  ∮ z in C(c, R), a • f z = a • ∮ z in C(c, R), f z :=
by simp only [circle_integral, ← smul_comm a, interval_integral.integral_smul]

@[simp] lemma integral_smul_const (f : ℂ → ℂ) (a : E) (c : ℂ) (R : ℝ) :
  ∮ z in C(c, R), (f z • a) = (∮ z in C(c, R), f z) • a :=
by simp only [circle_integral, interval_integral.integral_smul_const, ← smul_assoc]

@[simp] lemma integral_const_mul (a : ℂ) (f : ℂ → ℂ) (c : ℂ) (R : ℝ) :
  ∮ z in C(c, R), a * f z = a * ∮ z in C(c, R), f z :=
integral_smul a f c R

@[simp] lemma integral_sub_center_inv (c : ℂ) {R : ℝ} (hR : R ≠ 0) :
  ∮ z in C(c, R), (z - c)⁻¹ = 2 * π * I :=
by simp [circle_integral, ← div_eq_mul_inv, mul_div_cancel_left _ (circle_map_ne_center hR)]

/-- If `f' : ℂ → E` is a derivative of a complex differentiable function on the circle
`metric.sphere c |R|`, then `∮ z in C(c, R), f' z = 0`. -/
lemma integral_eq_zero_of_has_deriv_within_at' {f f' : ℂ → E} {c : ℂ} {R : ℝ}
  (h : ∀ z ∈ sphere c (|R|), has_deriv_within_at f (f' z) (sphere c (|R|)) z) :
  ∮ z in C(c, R), f' z = 0 :=
begin
  by_cases hi : circle_integrable f' c R,
  { rw ← sub_eq_zero.2 ((periodic_circle_map c R).comp f).eq,
    refine interval_integral.integral_eq_sub_of_has_deriv_at (λ θ hθ, _) hi.out,
    exact (h _ (circle_map_mem_sphere' _ _ _)).scomp_has_deriv_at θ
      (differentiable_circle_map _ _ _).has_deriv_at (circle_map_mem_sphere' _ _) },
  { exact integral_undef hi }
end

/-- If `f' : ℂ → E` is a derivative of a complex differentiable function on the circle
`metric.sphere c R`, then `∮ z in C(c, R), f' z = 0`. -/
lemma integral_eq_zero_of_has_deriv_within_at {f f' : ℂ → E} {c : ℂ} {R : ℝ} (hR : 0 ≤ R)
  (h : ∀ z ∈ sphere c R, has_deriv_within_at f (f' z) (sphere c R) z) :
  ∮ z in C(c, R), f' z = 0 :=
integral_eq_zero_of_has_deriv_within_at' $ (_root_.abs_of_nonneg hR).symm.subst h

/-- If `n < 0` and `|w - c| = |R|`, then `(z - w) ^ n` is not circle integrable on the circle with
center `c` and radius `(|R|)`, so the integral `∮ z in C(c, R), (z - w) ^ n` is equal to zero. -/
lemma integral_sub_zpow_of_undef {n : ℤ} {c w : ℂ} {R : ℝ} (hn : n < 0) (hw : w ∈ sphere c (|R|)) :
  ∮ z in C(c, R), (z - w) ^ n = 0 :=
begin
  rcases eq_or_ne R 0 with rfl|h0, { apply integral_radius_zero },
  apply integral_undef,
  simp [circle_integrable_sub_zpow_iff, *]
end

/-- If `n ≠ -1` is an integer number, then the integral of `(z - w) ^ n` over the circle equals
zero. -/
lemma integral_sub_zpow_of_ne {n : ℤ} (hn : n ≠ -1) (c w : ℂ) (R : ℝ) :
  ∮ z in C(c, R), (z - w) ^ n = 0 :=
begin
  rcases em (w ∈ sphere c (|R|) ∧ n < -1) with ⟨hw, hn⟩|H,
  { exact integral_sub_zpow_of_undef (hn.trans dec_trivial) hw },
  push_neg at H,
  have hd : ∀ z, (z ≠ w ∨ -1 ≤ n) → has_deriv_at (λ z, (z - w) ^ (n + 1) / (n + 1)) ((z - w) ^ n) z,
  { intros z hne,
    convert ((has_deriv_at_zpow (n + 1) _ (hne.imp _ _)).comp z
      ((has_deriv_at_id z).sub_const w)).div_const _ using 1,
    { have hn' : (n + 1 : ℂ) ≠ 0,
        by rwa [ne, ← eq_neg_iff_add_eq_zero, ← int.cast_one, ← int.cast_neg, int.cast_inj],
      simp [mul_assoc, mul_div_cancel_left _ hn'] },
    exacts [sub_ne_zero.2, neg_le_iff_add_nonneg.1] },
  refine integral_eq_zero_of_has_deriv_within_at' (λ z hz, (hd z _).has_deriv_within_at),
  exact (ne_or_eq z w).imp_right (λ h, H $ h ▸ hz)
end

end circle_integral

/-- The power series that is equal to
$\sum_{n=0}^{\infty} \oint_{|z-c|=R} \left(\frac{w-c}{z - c}\right)^n \frac{1}{z-c}f(z)\,dz$ at
`w - c`. The coefficients of this power series depend only on `f ∘ circle_map c R`, and the power
series converges to `f w` if `f` is differentiable on the closed ball `metric.closed_ball c R` and
`w` belongs to the corresponding open ball. For any circle integrable function `f`, this power
series converges to the Cauchy integral for `f`. -/
def cauchy_power_series (f : ℂ → E) (c : ℂ) (R : ℝ) :
  formal_multilinear_series ℂ ℂ E :=
λ n, continuous_multilinear_map.mk_pi_field ℂ _ $
  (2 * π * I : ℂ)⁻¹ • ∮ z in C(c, R), (z - c)⁻¹ ^ n • (z - c)⁻¹ • f z

lemma cauchy_power_series_apply (f : ℂ → E) (c : ℂ) (R : ℝ) (n : ℕ) (w : ℂ) :
  cauchy_power_series f c R n (λ _, w) =
    (2 * π * I : ℂ)⁻¹ • ∮ z in C(c, R), (w / (z - c)) ^ n • (z - c)⁻¹ • f z :=
by simp only [cauchy_power_series, continuous_multilinear_map.mk_pi_field_apply, fin.prod_const,
  div_eq_mul_inv, mul_pow, mul_smul, circle_integral.integral_smul, ← smul_comm (w ^ n)]

lemma norm_cauchy_power_series_le (f : ℂ → E) (c : ℂ) (R : ℝ) (n : ℕ) :
  ∥cauchy_power_series f c R n∥ ≤
    (2 * π)⁻¹ * (∫ θ : ℝ in 0..2*π, ∥f (circle_map c R θ)∥) * (|R|⁻¹) ^ n :=
calc ∥cauchy_power_series f c R n∥
    = (2 * π)⁻¹ * ∥∮ z in C(c, R), (z - c)⁻¹ ^ n • (z - c)⁻¹ • f z∥ :
  by simp [cauchy_power_series, norm_smul, real.pi_pos.le]
... ≤ (2 * π)⁻¹ * ∫ θ in 0..2*π, ∥deriv (circle_map c R) θ • (circle_map c R θ - c)⁻¹ ^ n •
  (circle_map c R θ - c)⁻¹ • f (circle_map c R θ)∥ :
  mul_le_mul_of_nonneg_left (interval_integral.norm_integral_le_integral_norm real.two_pi_pos.le)
    (by simp [real.pi_pos.le])
... = (2 * π)⁻¹ * (|R|⁻¹ ^ n * (|R| * (|R|⁻¹ * ∫ (x : ℝ) in 0..2 * π, ∥f (circle_map c R x)∥))) :
  by simp [norm_smul, mul_left_comm (|R|)]
... ≤ (2 * π)⁻¹ * (∫ θ : ℝ in 0..2*π, ∥f (circle_map c R θ)∥) * |R|⁻¹ ^ n :
  begin
    rcases eq_or_ne R 0 with rfl|hR,
    { cases n; simp [real.two_pi_pos] },
    { rw [mul_inv_cancel_left₀, mul_assoc, mul_comm (|R|⁻¹ ^ n)],
      rwa [ne.def, _root_.abs_eq_zero] }
  end

lemma le_radius_cauchy_power_series (f : ℂ → E) (c : ℂ) (R : ℝ≥0) :
  ↑R ≤ (cauchy_power_series f c R).radius :=
begin
  refine (cauchy_power_series f c R).le_radius_of_bound
    ((2 * π)⁻¹ * (∫ θ : ℝ in 0..2*π, ∥f (circle_map c R θ)∥)) (λ n, _),
  refine (mul_le_mul_of_nonneg_right (norm_cauchy_power_series_le _ _ _ _)
    (pow_nonneg R.coe_nonneg _)).trans _,
  rw [_root_.abs_of_nonneg R.coe_nonneg],
  cases eq_or_ne (R ^ n : ℝ) 0 with hR hR,
  { rw [hR, mul_zero],
    exact mul_nonneg (inv_nonneg.2 real.two_pi_pos.le)
      (interval_integral.integral_nonneg real.two_pi_pos.le (λ _ _, norm_nonneg _)) },
  { rw [inv_pow₀, inv_mul_cancel_right₀ hR] }
end

/-- For any circle integrable function `f`, the power series `cauchy_power_series f c R` multiplied
by `2πI` converges to the integral `∮ z in C(c, R), (z - w)⁻¹ • f z` on the open disc
`metric.ball c R`. -/
lemma has_sum_two_pi_I_cauchy_power_series_integral {f : ℂ → E} {c : ℂ} {R : ℝ} {w : ℂ}
  (hf : circle_integrable f c R) (hw : abs w < R) :
  has_sum (λ n : ℕ, ∮ z in C(c, R), (w / (z - c)) ^ n • (z - c)⁻¹ • f z)
    (∮ z in C(c, R), (z - (c + w))⁻¹ • f z) :=
begin
  have hR : 0 < R := (abs_nonneg w).trans_lt hw,
  have hwR : abs w / R ∈ Ico (0 : ℝ) 1,
    from ⟨div_nonneg (abs_nonneg w) hR.le, (div_lt_one hR).2 hw⟩,
  refine interval_integral.has_sum_integral_of_dominated_convergence
    (λ n θ, ∥f (circle_map c R θ)∥ * (abs w / R) ^ n) (λ n, _) (λ n, _) _ _ _,
  { simp only [deriv_circle_map], have := hf.def.1, measurability },
  { simp [norm_smul, abs_of_pos hR, mul_left_comm R, mul_inv_cancel_left₀ hR.ne', mul_comm (∥_∥)] },
  { exact eventually_of_forall (λ _ _, (summable_geometric_of_lt_1 hwR.1 hwR.2).mul_left _) },
  { simpa only [tsum_mul_left, tsum_geometric_of_lt_1 hwR.1 hwR.2]
      using hf.norm.mul_continuous_on continuous_on_const },
  { refine eventually_of_forall (λ θ hθ, has_sum.const_smul _),
    simp only [smul_smul],
    refine has_sum.smul_const _,
    have : ∥w / (circle_map c R θ - c)∥ < 1, by simpa [abs_of_pos hR] using hwR.2,
    convert (has_sum_geometric_of_norm_lt_1 this).mul_right _,
    simp [← sub_sub, ← mul_inv₀, sub_mul, div_mul_cancel _ (circle_map_ne_center hR.ne')] }
end

/-- For any circle integrable function `f`, the power series `cauchy_power_series f c R`, `R > 0`,
converges to the Cauchy integral `(2 * π * I : ℂ)⁻¹ • ∮ z in C(c, R), (z - w)⁻¹ • f z` on the open
disc `metric.ball c R`. -/
lemma has_sum_cauchy_power_series_integral {f : ℂ → E} {c : ℂ} {R : ℝ} {w : ℂ}
  (hf : circle_integrable f c R) (hw : abs w < R) :
  has_sum (λ n, cauchy_power_series f c R n (λ _, w))
    ((2 * π * I : ℂ)⁻¹ • ∮ z in C(c, R), (z - (c + w))⁻¹ • f z) :=
begin
  simp only [cauchy_power_series_apply],
  exact (has_sum_two_pi_I_cauchy_power_series_integral hf hw).const_smul
end

/-- For any circle integrable function `f`, the power series `cauchy_power_series f c R`, `R > 0`,
converges to the Cauchy integral `(2 * π * I : ℂ)⁻¹ • ∮ z in C(c, R), (z - w)⁻¹ • f z` on the open
disc `metric.ball c R`. -/
lemma sum_cauchy_power_series_eq_integral {f : ℂ → E} {c : ℂ} {R : ℝ} {w : ℂ}
  (hf : circle_integrable f c R) (hw : abs w < R) :
  (cauchy_power_series f c R).sum w =
    ((2 * π * I : ℂ)⁻¹ • ∮ z in C(c, R), (z - (c + w))⁻¹ • f z) :=
(has_sum_cauchy_power_series_integral hf hw).tsum_eq

/-- For any circle integrable function `f`, the power series `cauchy_power_series f c R`, `R > 0`,
converges to the Cauchy integral `(2 * π * I : ℂ)⁻¹ • ∮ z in C(c, R), (z - w)⁻¹ • f z` on the open
disc `metric.ball c R`. -/
lemma has_fpower_series_on_cauchy_integral {f : ℂ → E} {c : ℂ} {R : ℝ≥0}
  (hf : circle_integrable f c R) (hR : 0 < R) :
  has_fpower_series_on_ball
    (λ w, (2 * π * I : ℂ)⁻¹ • ∮ z in C(c, R), (z - w)⁻¹ • f z)
    (cauchy_power_series f c R) c R :=
{ r_le := le_radius_cauchy_power_series _ _ _,
  r_pos := ennreal.coe_pos.2 hR,
  has_sum := λ y hy,
    begin
      refine has_sum_cauchy_power_series_integral hf _,
      rw [← norm_eq_abs, ← coe_nnnorm, nnreal.coe_lt_coe, ← ennreal.coe_lt_coe],
      exact mem_emetric_ball_zero_iff.1 hy
    end }

namespace circle_integral

/-- Integral $\oint_{|z-c|=R} \frac{dz}{z-w}=2πi$ whenever $|w-c|<R$. -/
lemma integral_sub_inv_of_mem_ball {c w : ℂ} {R : ℝ} (hw : w ∈ ball c R) :
  ∮ z in C(c, R), (z - w)⁻¹ = 2 * π * I :=
begin
  have hR : 0 < R := dist_nonneg.trans_lt hw,
  suffices H : has_sum (λ n : ℕ, ∮ z in C(c, R), ((w - c) / (z - c)) ^ n * (z - c)⁻¹) (2 * π * I),
  { have A : circle_integrable (λ _, (1 : ℂ)) c R, from continuous_on_const.circle_integrable',
    refine (H.unique _).symm,
    simpa only [smul_eq_mul, mul_one, add_sub_cancel'_right]
      using has_sum_two_pi_I_cauchy_power_series_integral A hw },
  have H : ∀ n : ℕ, n ≠ 0 → ∮ z in C(c, R), (z - c) ^ (-n - 1 : ℤ) = 0,
  { refine λ n hn, integral_sub_zpow_of_ne _ _ _ _, simpa },
  have : ∮ z in C(c, R), ((w - c) / (z - c)) ^ 0 * (z - c)⁻¹ = 2 * π * I, by simp [hR.ne'],
  refine this ▸ has_sum_single _ (λ n hn, _),
  simp only [div_eq_mul_inv, mul_pow, integral_const_mul, mul_assoc],
  rw [(integral_congr hR.le (λ z hz, _)).trans (H n hn), mul_zero],
  rw [← pow_succ', ← zpow_coe_nat, inv_zpow₀, ← zpow_neg₀, int.coe_nat_succ, neg_add,
    sub_eq_add_neg _ (1 : ℤ)]
end

end circle_integral


import data.mv_polynomial.basic
import data.mv_polynomial.comm_ring
import data.zmod.basic
import ring_theory.ideal.operations

open mv_polynomial
noncomputable theory

section
-- 2x3 case.

abbreviation R := mv_polynomial (fin 6) (zmod 101)
def f1 : R := (X 0)*(X 3)
def f2 : R  := (X 1)*(X 4)
def f3 : R  := (X 2)*(X 5)
def f4 : R  := (X 0)*(X 1)*(X 2) - (X 3)*(X 4)*(X 5)
def g : R  := (X 0)*(X 1)*(X 2)
def h : R  := (X 3)*(X 4)*(X 5)
--def I := ideal.span ({f1, f2, f3, f4} : set R)

-- Let I be the ideal generated by f1, f2, f3, f4.
-- We want to show that g ∉ I and that g ∈ socle of I, i.e.,
-- g multiplies every variable into I. Now we show that
-- g ∈ socle of I. Showing that g ∉ I requires Grobner basis

-- We first show that g * (X i) ∈ I for i = 3, 4, 5. By
-- the symmetry of the problem, it suffices to show that
-- g * (X 3) ∈ I.

lemma g_times_var_three_in_I : g*(X 3) = (X 1)*(X 2)*f1 :=
begin
  rw [g, f1],
  ring,
end

-- Now to show that g (X 0) ∈ I, we need a lemma, which
-- says that g ≃ h modulo I.
lemma g_equiv_h : g = h + f4 :=
begin
  rw [f4, g, h],
  ring,
end

lemma g_times_var_zero_in_I : g*(X 0) = (X 4) * (X 5) * f1 + f4 * (X 0) :=
begin
  rw [g_equiv_h, h, f1, f4],
  ring,
end

end


/-
Copyright (c) 2020 Markus Himmel. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Markus Himmel
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.ring_theory.ideal.operations
import Mathlib.PostPort

universes u v

namespace Mathlib

/-!
# Ideals in product rings

For commutative rings `R` and `S` and ideals `I ≤ R`, `J ≤ S`, we define `ideal.prod I J` as the
product `I × J`, viewed as an ideal of `R × S`. In `ideal_prod_eq` we show that every ideal of
`R × S` is of this form.  Furthermore, we show that every prime ideal of `R × S` is of the form
`p × S` or `R × p`, where `p` is a prime ideal.
-/

namespace ideal

/-- `I × J` as an ideal of `R × S`. -/
def prod {R : Type u} {S : Type v} [comm_ring R] [comm_ring S] (I : ideal R) (J : ideal S) :
    ideal (R × S) :=
  submodule.mk (set_of fun (x : R × S) => prod.fst x ∈ I ∧ prod.snd x ∈ J) sorry sorry sorry

@[simp] theorem mem_prod {R : Type u} {S : Type v} [comm_ring R] [comm_ring S] (I : ideal R)
    (J : ideal S) {r : R} {s : S} : (r, s) ∈ prod I J ↔ r ∈ I ∧ s ∈ J :=
  iff.rfl

@[simp] theorem prod_top_top {R : Type u} {S : Type v} [comm_ring R] [comm_ring S] : prod ⊤ ⊤ = ⊤ :=
  sorry

/-- Every ideal of the product ring is of the form `I × J`, where `I` and `J` can be explicitly
    given as the image under the projection maps. -/
theorem ideal_prod_eq {R : Type u} {S : Type v} [comm_ring R] [comm_ring S] (I : ideal (R × S)) :
    I = prod (map (ring_hom.fst R S) I) (map (ring_hom.snd R S) I) :=
  sorry

@[simp] theorem map_fst_prod {R : Type u} {S : Type v} [comm_ring R] [comm_ring S] (I : ideal R)
    (J : ideal S) : map (ring_hom.fst R S) (prod I J) = I :=
  sorry

@[simp] theorem map_snd_prod {R : Type u} {S : Type v} [comm_ring R] [comm_ring S] (I : ideal R)
    (J : ideal S) : map (ring_hom.snd R S) (prod I J) = J :=
  sorry

@[simp] theorem map_prod_comm_prod {R : Type u} {S : Type v} [comm_ring R] [comm_ring S]
    (I : ideal R) (J : ideal S) : map (↑ring_equiv.prod_comm) (prod I J) = prod J I :=
  sorry

/-- Ideals of `R × S` are in one-to-one correspondence with pairs of ideals of `R` and ideals of
    `S`. -/
def ideal_prod_equiv {R : Type u} {S : Type v} [comm_ring R] [comm_ring S] :
    ideal (R × S) ≃ ideal R × ideal S :=
  equiv.mk (fun (I : ideal (R × S)) => (map (ring_hom.fst R S) I, map (ring_hom.snd R S) I))
    (fun (I : ideal R × ideal S) => prod (prod.fst I) (prod.snd I)) sorry sorry

@[simp] theorem ideal_prod_equiv_symm_apply {R : Type u} {S : Type v} [comm_ring R] [comm_ring S]
    (I : ideal R) (J : ideal S) : coe_fn (equiv.symm ideal_prod_equiv) (I, J) = prod I J :=
  rfl

theorem prod.ext_iff {R : Type u} {S : Type v} [comm_ring R] [comm_ring S] {I : ideal R}
    {I' : ideal R} {J : ideal S} {J' : ideal S} : prod I J = prod I' J' ↔ I = I' ∧ J = J' :=
  sorry

theorem is_prime_of_is_prime_prod_top {R : Type u} {S : Type v} [comm_ring R] [comm_ring S]
    {I : ideal R} (h : is_prime (prod I ⊤)) : is_prime I :=
  sorry

theorem is_prime_of_is_prime_prod_top' {R : Type u} {S : Type v} [comm_ring R] [comm_ring S]
    {I : ideal S} (h : is_prime (prod ⊤ I)) : is_prime I :=
  is_prime_of_is_prime_prod_top
    (eq.mpr (id (Eq._oldrec (Eq.refl (is_prime (prod I ⊤))) (Eq.symm (map_prod_comm_prod ⊤ I))))
      (map_is_prime_of_equiv ring_equiv.prod_comm))

theorem is_prime_ideal_prod_top {R : Type u} {S : Type v} [comm_ring R] [comm_ring S] {I : ideal R}
    [h : is_prime I] : is_prime (prod I ⊤) :=
  sorry

theorem is_prime_ideal_prod_top' {R : Type u} {S : Type v} [comm_ring R] [comm_ring S] {I : ideal S}
    [h : is_prime I] : is_prime (prod ⊤ I) :=
  eq.mpr (id (Eq._oldrec (Eq.refl (is_prime (prod ⊤ I))) (Eq.symm (map_prod_comm_prod I ⊤))))
    (map_is_prime_of_equiv ring_equiv.prod_comm)

theorem ideal_prod_prime_aux {R : Type u} {S : Type v} [comm_ring R] [comm_ring S] {I : ideal R}
    {J : ideal S} : is_prime (prod I J) → I = ⊤ ∨ J = ⊤ :=
  sorry

/-- Classification of prime ideals in product rings: the prime ideals of `R × S` are precisely the
    ideals of the form `p × S` or `R × p`, where `p` is a prime ideal of `R` or `S`. -/
theorem ideal_prod_prime {R : Type u} {S : Type v} [comm_ring R] [comm_ring S] (I : ideal (R × S)) :
    is_prime I ↔
        (∃ (p : ideal R), is_prime p ∧ I = prod p ⊤) ∨ ∃ (p : ideal S), is_prime p ∧ I = prod ⊤ p :=
  sorry

/-- The prime ideals of `R × S` are in bijection with the disjoint union of the prime ideals
    of `R` and the prime ideals of `S`. -/
def prime_ideals_equiv (R : Type u) (S : Type v) [comm_ring R] [comm_ring S] :
    (Subtype fun (K : ideal (R × S)) => is_prime K) ≃
        (Subtype fun (I : ideal R) => is_prime I) ⊕ Subtype fun (J : ideal S) => is_prime J :=
  equiv.symm (equiv.of_bijective prime_ideals_equiv_impl sorry)

@[simp] theorem prime_ideals_equiv_symm_inl {R : Type u} {S : Type v} [comm_ring R] [comm_ring S]
    (I : ideal R) (h : is_prime I) :
    coe_fn (equiv.symm (prime_ideals_equiv R S)) (sum.inl { val := I, property := h }) =
        { val := prod I ⊤, property := is_prime_ideal_prod_top } :=
  rfl

@[simp] theorem prime_ideals_equiv_symm_inr {R : Type u} {S : Type v} [comm_ring R] [comm_ring S]
    (J : ideal S) (h : is_prime J) :
    coe_fn (equiv.symm (prime_ideals_equiv R S)) (sum.inr { val := J, property := h }) =
        { val := prod ⊤ J, property := is_prime_ideal_prod_top' } :=
  rfl

end Mathlib


import convex
  data.real.ereal

variables {V: Type} [inner_product_space ℝ V] [finite_dimensional ℝ V]

noncomputable def support_function (A : set V) (u : V) : ereal :=
@supr ereal _ _ (λ a : A, (⟪a.1, u⟫_ℝ : ereal))

lemma normal_face_support_function (A : set V) (u : V) :
normal_face A u = { x ∈ A | (⟪x, u⟫_ℝ : ereal) = support_function A u } :=
begin
  apply le_antisymm,
  {
    rintro x hx,
    simp only [set.mem_sep_eq],
    simp only [mem_normal_face] at hx,
    split,
    {tauto},
    simp only [support_function],
    apply eq.symm ∘ is_lub.supr_eq,
    apply is_greatest.is_lub,
    split,
    {
      simp only [
        set.mem_range, ereal.coe_eq_coe_iff,
        set_coe.exists, exists_prop],
      refine ⟨x, _⟩,
      tauto,
    },
    {
      simp [mem_upper_bounds],
      tauto,
    }
  },
  {
    rintro x hx,
    simp only [mem_normal_face],
    simp only [set.mem_sep_eq] at hx,
    split,
    {tauto},
    rintro y hy,
    simp only [support_function] at hx,
    apply ereal.coe_le_coe_iff.mp,
    simp only [hx.2],
    rw [show y = (⟨y, hy⟩ : A).val, by refl],
    have := le_supr (λ x : A, (⟪x.val, u⟫_ℝ : ereal)),
    simp only [subtype.val_eq_coe, set_coe.forall, subtype.coe_mk] at this,
    apply this,
    assumption,
  }
end

noncomputable def finite_support_function {A : set V}
(h : is_convex_body A) : V → ℝ :=
λ u, supr (λ a : A, ⟪a.1, u⟫_ℝ)

/- lemma support_function_finite {A : set V}
(Abd : is_convex_body A) (u : V) :
support_function A u = (finite_support_function Abd u : ereal) := sorry -/

def pos_homogeneous (f : V → ℝ) :=
∀ v : V, ∀ a : ℝ, a ≥ 0 → f (a • v) = a * (f v)


import data.int.basic
import data.int.modeq
import tactic.ring
import ring_theory.coprime.basic
import init.data.nat.gcd
import init.meta.tactic
import init.core
import data.int.basic
import data.num.basic
import logic.basic
-- Based on class project by Rukiyah Walker
open classical
--lemma 1.64: Let x₀, y₀, a, b be positive integers with a and b relatively prime, x₀ < b, and y₀ < a.
--Then the equation
--ax + by = ax₀ + by₀
--has a unique solution (x,y) in nonnegative integers.

lemma congr_args {x₀ y₀ a b x y: ℤ} : (x,y) = (x₀,y₀) → a*x + b*y = a*x₀ + b*y₀ :=
  λ h0,
  have hxy1: x = x₀, from congr_arg (λ p:ℤ×ℤ, p.1) h0,
  have hxy2: y = y₀, from congr_arg (λ p:ℤ×ℤ, p.2) h0,
  calc _ = a*x₀ + b*y: by rw ← hxy1
    ... = _: by rw hxy2

lemma lemma_1_64 (x₀ y₀ a b x y: ℤ )
  (h1:a > 0)(h2:b > 0)
--  (h3:x₀ > 0)
--  (h4: y₀ > 0)
  (h5:is_coprime a b)
  (h6:x₀ < b)(h7:y₀ < a)
  (h8:x ≥ 0)(h9:y ≥ 0):
  a*x + b*y = a*x₀ + b*y₀ ↔ (x,y) = (x₀, y₀) :=

--second direction (→):
have hab: a*x + b*y = a*x₀ + b*y₀ → (x,y) = (x₀,y₀), from
    λ hab0: a*x + b*y = a*x₀ + b*y₀,
    have hab1: a*x - a*x₀ + b*y = b*y₀, from calc
                              _ = a*x + b*y - a*x₀: by rw add_sub_right_comm
                            ... = _: sub_eq_of_eq_add' hab0,
    have hab2: b*(y₀-y)=a*(x - x₀), from calc
                      _ = b*y₀-b*y  : mul_sub _ _ _
                    ... = a*x-a*x₀  : (eq_sub_of_add_eq hab1).symm
                    ... = a*(x-x₀)  : (mul_sub _ _ _).symm,
    have hab3: b ∣ a*(x - x₀), from dvd.intro (y₀ - y) hab2,
    have hab4: is_coprime b a, from is_coprime_comm.mp h5,
    have hx: b ∣ (x - x₀), from is_coprime.dvd_of_dvd_mul_left hab4 hab3,
    have hx1: (x - x₀) ≡ 0 [ZMOD b], from int.modeq_zero_iff_dvd.mpr hx,
    have hx2: ∃ n, (x - x₀) = n*b, from exists_eq_mul_left_of_dvd hx,
    exists.elim hx2
      (
        λ n,
        λ hn: (x - x₀) = n*b,
        have hn1: x = x₀ + n*b, from eq_add_of_sub_eq' hn,
        or.elim (classical.em (n < 0))
        (
          λ hn2: n < 0,
            have hnx: n ≤ -1, from sub_nonpos.mp hn2,
            have hnx1: n*b ≤ (-1)*b, from (mul_le_mul_right h2).mpr hnx,
            have hnx2: x < 0, from calc
                       _ = x₀ + n*b: hn1
                     ... ≤ x₀ + (-1)*b: add_le_add_left hnx1 x₀
                     ... = x₀ - b: by ring
                     ... < 0: sub_neg.mpr h6,
            absurd h8 (not_le.mpr hnx2)
        )
        (λ hn3: ¬ n < 0,
          or.elim (em' (n = 0))
          (
            λ hnn0: ¬ n = 0,
            have hnn1: n < 0 ∨ n > 0, from ne.lt_or_lt hnn0,
            or.elim (hnn1)
            (
              λ hnn2: n < 0,
              absurd hnn2 hn3
            )
            (
              λ hnn3: n > 0,
              have hnn4: n*b ≥ (1)*b, from (mul_le_mul_right h2).mpr hnn3,
              have hnn5:  x ≥ x₀ + b, from calc
                          _ = x₀ + n*b: hn1
                        ... ≥ x₀ + 1*b: add_le_add_left hnn4 x₀
                        ... = _: by ring,

              have hnn6: a*x ≥ a*(x₀ + b), from (mul_le_mul_left h1).mpr hnn5,
              have hnn7: b*y ≥ b*0, from (mul_le_mul_left h2).mpr h9,

              have hnn8: b*a > b*y₀, from (mul_lt_mul_left h2).mpr h7,
              have hnn9: a*x + b*y > a*x₀ + b*y₀, from calc
                                  _ ≥ a*(x₀ + b) + b*0: add_le_add hnn6 hnn7
                                ... = a*(x₀+b) : by ring
                                ... = a*x₀+a*b: mul_add a x₀ b
                                ... = a*x₀+b*a: by rw (mul_comm a b)
                                ... > _: add_lt_add_left hnn8 (a * x₀),
              absurd hab0 (ne_of_gt hnn9)
            )
          )
          (
           λ hhhn0: n = 0,
              have hhhn1: x = x₀, from calc
                          x = x₀ + n*b: hn1
                        ... = x₀ + 0*b: by rw hhhn0
                        ... = x₀ : by ring,
             have hhhn2: a*x + b*y = a*x + b*y₀, from calc
                                 _ = a*x₀+b*y₀: hab0
                               ... = _: by rw hhhn1,
             have hhhn3: b*y = b*y₀, from (add_right_inj (a * x)).mp hhhn2,
             have hbzero: b≠ 0, from ne_of_gt h2,
             have b≠ 0 → b*y=b*y₀ → y=y₀, from
              λ (ha : b ≠ 0), (mul_right_inj' ha).mp,
             have hhhn4: y = y₀, from this hbzero hhhn3,
            show (x, y) = (x₀, y₀), from congr (congr_arg prod.mk hhhn1) hhhn4
          )
        )
      ),
show a*x + b*y = a*x₀ + b*y₀ ↔ (x,y) = (x₀, y₀), from {mp := hab, mpr := congr_args}


import data.nat.basic
import data.nat.parity
-- open_locale classical
decidable theory

-- --Do I want these to be bools or Props?
def myIsEven := nat.even
def myIsOdd (n : ℕ) := ¬ (myIsEven n)

#reduce myIsEven 2
--#eval myIsEven 2

--Alice only sees r and Bob only sees c. The strategy isn't (r,c) → (...) but two maps, r→(r1 r2 r3) and c → (c1 c2 c3)
--I'm using 0 and 1 instead of Green and Red as the two options to fill squares. This makes checking parity of strategies easier

------------METHOD 1: enumerate all the constraints as concisely as possible and reduce to show we get a contraditcion----------------------------------
def checkStrategyrc (r c : ℕ) (strategy : ((ℕ → ℕ × ℕ × ℕ) × (ℕ → ℕ × ℕ × ℕ))) : bool :=
        let r1 := (strategy.1 r).1,
        r2 := (strategy.1 r).2.1,
        r3 := (strategy.1 r).2.2,
        c1 := (strategy.2 c).1,
        c2 := (strategy.2 c).2.1,
        c3 := (strategy.2 c).2.2

        in myIsEven(r1 + r2 + r3) ∧ myIsOdd(c1 + c2 + c3) ∧
        ((r = 1 ∧ c = 1 ∧ r1 = c1) ∨ (r = 1 ∧ c = 2 ∧ r2 = c1) ∨ (r = 1 ∧ c = 3 ∧ r3 = c1)
        ∨(r = 2 ∧ c = 1 ∧ r1 = c2) ∨ (r = 2 ∧ c = 2 ∧ r2 = c2) ∨ (r = 2 ∧ c = 3 ∧ r3 = c2)
        ∨(r = 3 ∧ c = 1 ∧ r1 = c3) ∨ (r = 3 ∧ c = 2 ∧ r2 = c3) ∨ (r = 3 ∧ c = 3 ∧ r3 = c3))

--checks all three conditions are met for the strategy
def checkStrategy (strategy : ((ℕ → ℕ × ℕ × ℕ) × (ℕ → ℕ × ℕ × ℕ))) : bool :=
    (checkStrategyrc 1 1 strategy) ∧ (checkStrategyrc 1 2 strategy) ∧ (checkStrategyrc 1 3 strategy) ∧
    (checkStrategyrc 2 1 strategy) ∧ (checkStrategyrc 2 2 strategy) ∧ (checkStrategyrc 2 3 strategy) ∧
    (checkStrategyrc 3 1 strategy) ∧ (checkStrategyrc 3 2 strategy) ∧ (checkStrategyrc 3 3 strategy)

--given a strategy, we can't have it satisfy all the conditions
theorem noStrategy2 (strategy : ((ℕ → ℕ × ℕ × ℕ) × (ℕ → ℕ × ℕ × ℕ))) (r c : ℕ) : ¬ (checkStrategy (strategy)) :=
begin
intro s,
rw checkStrategy at s,
repeat {rw checkStrategyrc at s},
simp at s,
--every case here has a false equality and-ed with something else. How do I replace them with false and reduce?
--how do I tell it that we only care about the cases where r,c ∈ {1,2,3} and then do cases on those?
end