/-
Copyright (c) 2021 Kalle Kytölä. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kalle Kytölä

! This file was ported from Lean 3 source module measure_theory.measure.finite_measure
! leanprover-community/mathlib commit f2ce6086713c78a7f880485f7917ea547a215982
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Topology.ContinuousFunction.Bounded
import Mathbin.Topology.Algebra.Module.WeakDual
import Mathbin.MeasureTheory.Integral.Bochner

/-!
# Finite measures

This file defines the type of finite measures on a given measurable space. When the underlying
space has a topology and the measurable space structure (sigma algebra) is finer than the Borel
sigma algebra, then the type of finite measures is equipped with the topology of weak convergence
of measures. The topology of weak convergence is the coarsest topology w.r.t. which
for every bounded continuous `ℝ≥0`-valued function `f`, the integration of `f` against the
measure is continuous.

## Main definitions

The main definitions are
 * the type `measure_theory.finite_measure Ω` with the topology of weak convergence;
 * `measure_theory.finite_measure.to_weak_dual_bcnn : finite_measure Ω → (weak_dual ℝ≥0 (Ω →ᵇ ℝ≥0))`
   allowing to interpret a finite measure as a continuous linear functional on the space of
   bounded continuous nonnegative functions on `Ω`. This is used for the definition of the
   topology of weak convergence.

## Main results

 * Finite measures `μ` on `Ω` give rise to continuous linear functionals on the space of
   bounded continuous nonnegative functions on `Ω` via integration:
   `measure_theory.finite_measure.to_weak_dual_bcnn : finite_measure Ω → (weak_dual ℝ≥0 (Ω →ᵇ ℝ≥0))`
 * `measure_theory.finite_measure.tendsto_iff_forall_integral_tendsto`: Convergence of finite
   measures is characterized by the convergence of integrals of all bounded continuous functions.
   This shows that the chosen definition of topology coincides with the common textbook definition
   of weak convergence of measures. A similar characterization by the convergence of integrals (in
   the `measure_theory.lintegral` sense) of all bounded continuous nonnegative functions is
   `measure_theory.finite_measure.tendsto_iff_forall_lintegral_tendsto`.

## Implementation notes

The topology of weak convergence of finite Borel measures is defined using a mapping from
`measure_theory.finite_measure Ω` to `weak_dual ℝ≥0 (Ω →ᵇ ℝ≥0)`, inheriting the topology from the
latter.

The implementation of `measure_theory.finite_measure Ω` and is directly as a subtype of
`measure_theory.measure Ω`, and the coercion to a function is the composition `ennreal.to_nnreal`
and the coercion to function of `measure_theory.measure Ω`. Another alternative would have been to
use a bijection with `measure_theory.vector_measure Ω ℝ≥0` as an intermediate step. Some
considerations:
 * Potential advantages of using the `nnreal`-valued vector measure alternative:
   * The coercion to function would avoid need to compose with `ennreal.to_nnreal`, the
     `nnreal`-valued API could be more directly available.
 * Potential drawbacks of the vector measure alternative:
   * The coercion to function would lose monotonicity, as non-measurable sets would be defined to
     have measure 0.
   * No integration theory directly. E.g., the topology definition requires
     `measure_theory.lintegral` w.r.t. a coercion to `measure_theory.measure Ω` in any case.

## References

* [Billingsley, *Convergence of probability measures*][billingsley1999]

## Tags

weak convergence of measures, finite measure

-/

noncomputable section

open MeasureTheory

open Set

open Filter

open BoundedContinuousFunction

open Topology ENNReal NNReal BoundedContinuousFunction

namespace MeasureTheory

namespace FiniteMeasure

section FiniteMeasure

/-! ### Finite measures

In this section we define the `Type` of `finite_measure Ω`, when `Ω` is a measurable space. Finite
measures on `Ω` are a module over `ℝ≥0`.

If `Ω` is moreover a topological space and the sigma algebra on `Ω` is finer than the Borel sigma
algebra (i.e. `[opens_measurable_space Ω]`), then `finite_measure Ω` is equipped with the topology
of weak convergence of measures. This is implemented by defining a pairing of finite measures `μ`
on `Ω` with continuous bounded nonnegative functions `f : Ω →ᵇ ℝ≥0` via integration, and using the
associated weak topology (essentially the weak-star topology on the dual of `Ω →ᵇ ℝ≥0`).
-/

variable {Ω : Type _} [MeasurableSpace Ω]

/-- Finite measures are defined as the subtype of measures that have the property of being finite
measures (i.e., their total mass is finite). -/
def MeasureTheory.FiniteMeasure (Ω : Type _) [MeasurableSpace Ω] : Type _ :=
  { μ : Measure Ω // IsFiniteMeasure μ }
#align measure_theory.finite_measure MeasureTheory.FiniteMeasure

/-- A finite measure can be interpreted as a measure. -/
instance : Coe (FiniteMeasure Ω) (MeasureTheory.Measure Ω) :=
  coeSubtype

instance isFiniteMeasure (μ : FiniteMeasure Ω) : IsFiniteMeasure (μ : Measure Ω) :=
  μ.Prop
#align measure_theory.finite_measure.is_finite_measure MeasureTheory.FiniteMeasure.isFiniteMeasure

instance : CoeFun (FiniteMeasure Ω) fun _ => Set Ω → ℝ≥0 :=
  ⟨fun μ s => (μ s).toNNReal⟩

theorem coeFn_eq_toNNReal_coeFn_to_measure (ν : FiniteMeasure Ω) :
    (ν : Set Ω → ℝ≥0) = fun s => ((ν : Measure Ω) s).toNNReal :=
  rfl
#align measure_theory.finite_measure.coe_fn_eq_to_nnreal_coe_fn_to_measure MeasureTheory.FiniteMeasure.coeFn_eq_toNNReal_coeFn_to_measure

@[simp]
theorem eNNReal_coeFn_eq_coeFn_to_measure (ν : FiniteMeasure Ω) (s : Set Ω) :
    (ν s : ℝ≥0∞) = (ν : Measure Ω) s :=
  ENNReal.coe_toNNReal (measure_lt_top (↑ν) s).Ne
#align measure_theory.finite_measure.ennreal_coe_fn_eq_coe_fn_to_measure MeasureTheory.FiniteMeasure.eNNReal_coeFn_eq_coeFn_to_measure

@[simp]
theorem val_eq_to_measure (ν : FiniteMeasure Ω) : ν.val = (ν : Measure Ω) :=
  rfl
#align measure_theory.finite_measure.val_eq_to_measure MeasureTheory.FiniteMeasure.val_eq_to_measure

theorem coe_injective : Function.Injective (coe : FiniteMeasure Ω → Measure Ω) :=
  Subtype.coe_injective
#align measure_theory.finite_measure.coe_injective MeasureTheory.FiniteMeasure.coe_injective

theorem apply_mono (μ : FiniteMeasure Ω) {s₁ s₂ : Set Ω} (h : s₁ ⊆ s₂) : μ s₁ ≤ μ s₂ :=
  by
  change ((μ : Measure Ω) s₁).toNNReal ≤ ((μ : Measure Ω) s₂).toNNReal
  have key : (μ : Measure Ω) s₁ ≤ (μ : Measure Ω) s₂ := (μ : Measure Ω).mono h
  apply (ENNReal.toNNReal_le_toNNReal (measure_ne_top _ s₁) (measure_ne_top _ s₂)).mpr key
#align measure_theory.finite_measure.apply_mono MeasureTheory.FiniteMeasure.apply_mono

/-- The (total) mass of a finite measure `μ` is `μ univ`, i.e., the cast to `nnreal` of
`(μ : measure Ω) univ`. -/
def mass (μ : FiniteMeasure Ω) : ℝ≥0 :=
  μ univ
#align measure_theory.finite_measure.mass MeasureTheory.FiniteMeasure.mass

@[simp]
theorem eNNReal_mass {μ : FiniteMeasure Ω} : (μ.mass : ℝ≥0∞) = (μ : Measure Ω) univ :=
  eNNReal_coeFn_eq_coeFn_to_measure μ Set.univ
#align measure_theory.finite_measure.ennreal_mass MeasureTheory.FiniteMeasure.eNNReal_mass

instance hasZero : Zero (FiniteMeasure Ω) where zero := ⟨0, MeasureTheory.isFiniteMeasureZero⟩
#align measure_theory.finite_measure.has_zero MeasureTheory.FiniteMeasure.hasZero

@[simp]
theorem Zero.mass : (0 : FiniteMeasure Ω).mass = 0 :=
  rfl
#align measure_theory.finite_measure.zero.mass MeasureTheory.FiniteMeasure.Zero.mass

@[simp]
theorem mass_zero_iff (μ : FiniteMeasure Ω) : μ.mass = 0 ↔ μ = 0 :=
  by
  refine' ⟨fun μ_mass => _, fun hμ => by simp only [hμ, zero.mass]⟩
  ext1
  apply measure.measure_univ_eq_zero.mp
  rwa [← ennreal_mass, ENNReal.coe_eq_zero]
#align measure_theory.finite_measure.mass_zero_iff MeasureTheory.FiniteMeasure.mass_zero_iff

theorem mass_nonzero_iff (μ : FiniteMeasure Ω) : μ.mass ≠ 0 ↔ μ ≠ 0 :=
  by
  rw [not_iff_not]
  exact finite_measure.mass_zero_iff μ
#align measure_theory.finite_measure.mass_nonzero_iff MeasureTheory.FiniteMeasure.mass_nonzero_iff

@[ext]
theorem eq_of_forall_measure_apply_eq (μ ν : FiniteMeasure Ω)
    (h : ∀ s : Set Ω, MeasurableSet s → (μ : Measure Ω) s = (ν : Measure Ω) s) : μ = ν :=
  by
  ext1
  ext1 s s_mble
  exact h s s_mble
#align measure_theory.finite_measure.eq_of_forall_measure_apply_eq MeasureTheory.FiniteMeasure.eq_of_forall_measure_apply_eq

theorem eq_of_forall_apply_eq (μ ν : FiniteMeasure Ω)
    (h : ∀ s : Set Ω, MeasurableSet s → μ s = ν s) : μ = ν :=
  by
  ext1 s s_mble
  simpa [ennreal_coe_fn_eq_coe_fn_to_measure] using congr_arg (coe : ℝ≥0 → ℝ≥0∞) (h s s_mble)
#align measure_theory.finite_measure.eq_of_forall_apply_eq MeasureTheory.FiniteMeasure.eq_of_forall_apply_eq

instance : Inhabited (FiniteMeasure Ω) :=
  ⟨0⟩

instance : Add (FiniteMeasure Ω) where add μ ν := ⟨μ + ν, MeasureTheory.isFiniteMeasureAdd⟩

variable {R : Type _} [SMul R ℝ≥0] [SMul R ℝ≥0∞] [IsScalarTower R ℝ≥0 ℝ≥0∞]
  [IsScalarTower R ℝ≥0∞ ℝ≥0∞]

instance : SMul R (FiniteMeasure Ω)
    where smul (c : R) μ := ⟨c • μ, MeasureTheory.isFiniteMeasureSmulOfNnrealTower⟩

@[simp, norm_cast]
theorem coe_zero : (coe : FiniteMeasure Ω → Measure Ω) 0 = 0 :=
  rfl
#align measure_theory.finite_measure.coe_zero MeasureTheory.FiniteMeasure.coe_zero

@[simp, norm_cast]
theorem coe_add (μ ν : FiniteMeasure Ω) : ↑(μ + ν) = (↑μ + ↑ν : Measure Ω) :=
  rfl
#align measure_theory.finite_measure.coe_add MeasureTheory.FiniteMeasure.coe_add

@[simp, norm_cast]
theorem coe_smul (c : R) (μ : FiniteMeasure Ω) : ↑(c • μ) = (c • ↑μ : Measure Ω) :=
  rfl
#align measure_theory.finite_measure.coe_smul MeasureTheory.FiniteMeasure.coe_smul

@[simp, norm_cast]
theorem coeFn_zero : (⇑(0 : FiniteMeasure Ω) : Set Ω → ℝ≥0) = (0 : Set Ω → ℝ≥0) :=
  by
  funext
  rfl
#align measure_theory.finite_measure.coe_fn_zero MeasureTheory.FiniteMeasure.coeFn_zero

@[simp, norm_cast]
theorem coeFn_add (μ ν : FiniteMeasure Ω) : (⇑(μ + ν) : Set Ω → ℝ≥0) = (⇑μ + ⇑ν : Set Ω → ℝ≥0) :=
  by
  funext
  simp [← ENNReal.coe_eq_coe]
#align measure_theory.finite_measure.coe_fn_add MeasureTheory.FiniteMeasure.coeFn_add

@[simp, norm_cast]
theorem coeFn_smul [IsScalarTower R ℝ≥0 ℝ≥0] (c : R) (μ : FiniteMeasure Ω) :
    (⇑(c • μ) : Set Ω → ℝ≥0) = c • (⇑μ : Set Ω → ℝ≥0) :=
  by
  funext
  simp [← ENNReal.coe_eq_coe, ENNReal.coe_smul]
#align measure_theory.finite_measure.coe_fn_smul MeasureTheory.FiniteMeasure.coeFn_smul

instance : AddCommMonoid (FiniteMeasure Ω) :=
  coe_injective.AddCommMonoid coe coe_zero coe_add fun _ _ => coe_smul _ _

/-- Coercion is an `add_monoid_hom`. -/
@[simps]
def coeAddMonoidHom : FiniteMeasure Ω →+ Measure Ω
    where
  toFun := coe
  map_zero' := coe_zero
  map_add' := coe_add
#align measure_theory.finite_measure.coe_add_monoid_hom MeasureTheory.FiniteMeasure.coeAddMonoidHom

instance {Ω : Type _} [MeasurableSpace Ω] : Module ℝ≥0 (FiniteMeasure Ω) :=
  Function.Injective.module _ coeAddMonoidHom coe_injective coe_smul

@[simp]
theorem coeFn_smul_apply [IsScalarTower R ℝ≥0 ℝ≥0] (c : R) (μ : FiniteMeasure Ω) (s : Set Ω) :
    (c • μ) s = c • μ s := by simp only [coe_fn_smul, Pi.smul_apply]
#align measure_theory.finite_measure.coe_fn_smul_apply MeasureTheory.FiniteMeasure.coeFn_smul_apply

/-- Restrict a finite measure μ to a set A. -/
def restrict (μ : FiniteMeasure Ω) (A : Set Ω) : FiniteMeasure Ω
    where
  val := (μ : Measure Ω).restrict A
  property := MeasureTheory.isFiniteMeasureRestrict μ A
#align measure_theory.finite_measure.restrict MeasureTheory.FiniteMeasure.restrict

theorem restrict_measure_eq (μ : FiniteMeasure Ω) (A : Set Ω) :
    (μ.restrict A : Measure Ω) = (μ : Measure Ω).restrict A :=
  rfl
#align measure_theory.finite_measure.restrict_measure_eq MeasureTheory.FiniteMeasure.restrict_measure_eq

theorem restrict_apply_measure (μ : FiniteMeasure Ω) (A : Set Ω) {s : Set Ω}
    (s_mble : MeasurableSet s) : (μ.restrict A : Measure Ω) s = (μ : Measure Ω) (s ∩ A) :=
  Measure.restrict_apply s_mble
#align measure_theory.finite_measure.restrict_apply_measure MeasureTheory.FiniteMeasure.restrict_apply_measure

theorem restrict_apply (μ : FiniteMeasure Ω) (A : Set Ω) {s : Set Ω} (s_mble : MeasurableSet s) :
    (μ.restrict A) s = μ (s ∩ A) :=
  by
  apply congr_arg ENNReal.toNNReal
  exact measure.restrict_apply s_mble
#align measure_theory.finite_measure.restrict_apply MeasureTheory.FiniteMeasure.restrict_apply

theorem restrict_mass (μ : FiniteMeasure Ω) (A : Set Ω) : (μ.restrict A).mass = μ A := by
  simp only [mass, restrict_apply μ A MeasurableSet.univ, univ_inter]
#align measure_theory.finite_measure.restrict_mass MeasureTheory.FiniteMeasure.restrict_mass

theorem restrict_eq_zero_iff (μ : FiniteMeasure Ω) (A : Set Ω) : μ.restrict A = 0 ↔ μ A = 0 := by
  rw [← mass_zero_iff, restrict_mass]
#align measure_theory.finite_measure.restrict_eq_zero_iff MeasureTheory.FiniteMeasure.restrict_eq_zero_iff

theorem restrict_nonzero_iff (μ : FiniteMeasure Ω) (A : Set Ω) : μ.restrict A ≠ 0 ↔ μ A ≠ 0 := by
  rw [← mass_nonzero_iff, restrict_mass]
#align measure_theory.finite_measure.restrict_nonzero_iff MeasureTheory.FiniteMeasure.restrict_nonzero_iff

variable [TopologicalSpace Ω]

/-- The pairing of a finite (Borel) measure `μ` with a nonnegative bounded continuous
function is obtained by (Lebesgue) integrating the (test) function against the measure.
This is `finite_measure.test_against_nn`. -/
def testAgainstNn (μ : FiniteMeasure Ω) (f : Ω →ᵇ ℝ≥0) : ℝ≥0 :=
  (∫⁻ ω, f ω ∂(μ : Measure Ω)).toNNReal
#align measure_theory.finite_measure.test_against_nn MeasureTheory.FiniteMeasure.testAgainstNn

theorem BoundedContinuousFunction.Nnreal.to_eNNReal_comp_measurable {Ω : Type _}
    [TopologicalSpace Ω] [MeasurableSpace Ω] [OpensMeasurableSpace Ω] (f : Ω →ᵇ ℝ≥0) :
    Measurable fun ω => (f ω : ℝ≥0∞) :=
  measurable_coe_nNReal_eNNReal.comp f.Continuous.Measurable
#align bounded_continuous_function.nnreal.to_ennreal_comp_measurable BoundedContinuousFunction.Nnreal.to_eNNReal_comp_measurable

theorem MeasureTheory.lintegral_lt_top_of_bounded_continuous_to_nNReal (μ : Measure Ω)
    [IsFiniteMeasure μ] (f : Ω →ᵇ ℝ≥0) : (∫⁻ ω, f ω ∂μ) < ∞ :=
  by
  apply IsFiniteMeasure.lintegral_lt_top_of_bounded_to_eNNReal
  use nndist f 0
  intro x
  have key := BoundedContinuousFunction.Nnreal.upper_bound f x
  rw [ENNReal.coe_le_coe]
  have eq : nndist f 0 = ⟨dist f 0, dist_nonneg⟩ :=
    by
    ext
    simp only [Real.coe_toNNReal', max_eq_left_iff, Subtype.coe_mk, coe_nndist]
  rwa [Eq] at key
#align measure_theory.lintegral_lt_top_of_bounded_continuous_to_nnreal MeasureTheory.lintegral_lt_top_of_bounded_continuous_to_nNReal

@[simp]
theorem testAgainstNn_coe_eq {μ : FiniteMeasure Ω} {f : Ω →ᵇ ℝ≥0} :
    (μ.testAgainstNn f : ℝ≥0∞) = ∫⁻ ω, f ω ∂(μ : Measure Ω) :=
  ENNReal.coe_toNNReal (lintegral_lt_top_of_bounded_continuous_to_nNReal _ f).Ne
#align measure_theory.finite_measure.test_against_nn_coe_eq MeasureTheory.FiniteMeasure.testAgainstNn_coe_eq

theorem testAgainstNn_const (μ : FiniteMeasure Ω) (c : ℝ≥0) :
    μ.testAgainstNn (BoundedContinuousFunction.const Ω c) = c * μ.mass := by
  simp [← ENNReal.coe_eq_coe]
#align measure_theory.finite_measure.test_against_nn_const MeasureTheory.FiniteMeasure.testAgainstNn_const

theorem testAgainstNn_mono (μ : FiniteMeasure Ω) {f g : Ω →ᵇ ℝ≥0} (f_le_g : (f : Ω → ℝ≥0) ≤ g) :
    μ.testAgainstNn f ≤ μ.testAgainstNn g :=
  by
  simp only [← ENNReal.coe_le_coe, test_against_nn_coe_eq]
  exact lintegral_mono fun ω => ENNReal.coe_mono (f_le_g ω)
#align measure_theory.finite_measure.test_against_nn_mono MeasureTheory.FiniteMeasure.testAgainstNn_mono

@[simp]
theorem testAgainstNn_zero (μ : FiniteMeasure Ω) : μ.testAgainstNn 0 = 0 := by
  simpa only [MulZeroClass.zero_mul] using μ.test_against_nn_const 0
#align measure_theory.finite_measure.test_against_nn_zero MeasureTheory.FiniteMeasure.testAgainstNn_zero

@[simp]
theorem testAgainstNn_one (μ : FiniteMeasure Ω) : μ.testAgainstNn 1 = μ.mass :=
  by
  simp only [test_against_nn, coe_one, Pi.one_apply, ENNReal.coe_one, lintegral_one]
  rfl
#align measure_theory.finite_measure.test_against_nn_one MeasureTheory.FiniteMeasure.testAgainstNn_one

@[simp]
theorem Zero.testAgainstNn_apply (f : Ω →ᵇ ℝ≥0) : (0 : FiniteMeasure Ω).testAgainstNn f = 0 := by
  simp only [test_against_nn, coe_zero, lintegral_zero_measure, ENNReal.zero_toNNReal]
#align measure_theory.finite_measure.zero.test_against_nn_apply MeasureTheory.FiniteMeasure.Zero.testAgainstNn_apply

theorem Zero.testAgainstNn : (0 : FiniteMeasure Ω).testAgainstNn = 0 :=
  by
  funext
  simp only [zero.test_against_nn_apply, Pi.zero_apply]
#align measure_theory.finite_measure.zero.test_against_nn MeasureTheory.FiniteMeasure.Zero.testAgainstNn

@[simp]
theorem smul_testAgainstNn_apply (c : ℝ≥0) (μ : FiniteMeasure Ω) (f : Ω →ᵇ ℝ≥0) :
    (c • μ).testAgainstNn f = c • μ.testAgainstNn f := by
  simp only [test_against_nn, coe_smul, smul_eq_mul, ← ENNReal.smul_toNNReal, ENNReal.smul_def,
    lintegral_smul_measure]
#align measure_theory.finite_measure.smul_test_against_nn_apply MeasureTheory.FiniteMeasure.smul_testAgainstNn_apply

variable [OpensMeasurableSpace Ω]

theorem testAgainstNn_add (μ : FiniteMeasure Ω) (f₁ f₂ : Ω →ᵇ ℝ≥0) :
    μ.testAgainstNn (f₁ + f₂) = μ.testAgainstNn f₁ + μ.testAgainstNn f₂ :=
  by
  simp only [← ENNReal.coe_eq_coe, BoundedContinuousFunction.coe_add, ENNReal.coe_add, Pi.add_apply,
    test_against_nn_coe_eq]
  exact lintegral_add_left (BoundedContinuousFunction.Nnreal.to_eNNReal_comp_measurable _) _
#align measure_theory.finite_measure.test_against_nn_add MeasureTheory.FiniteMeasure.testAgainstNn_add

theorem testAgainstNn_smul [IsScalarTower R ℝ≥0 ℝ≥0] [PseudoMetricSpace R] [Zero R]
    [BoundedSMul R ℝ≥0] (μ : FiniteMeasure Ω) (c : R) (f : Ω →ᵇ ℝ≥0) :
    μ.testAgainstNn (c • f) = c • μ.testAgainstNn f :=
  by
  simp only [← ENNReal.coe_eq_coe, BoundedContinuousFunction.coe_smul, test_against_nn_coe_eq,
    ENNReal.coe_smul]
  simp_rw [← smul_one_smul ℝ≥0∞ c (f _ : ℝ≥0∞), ← smul_one_smul ℝ≥0∞ c (lintegral _ _ : ℝ≥0∞),
    smul_eq_mul]
  exact
    @lintegral_const_mul _ _ (μ : Measure Ω) (c • 1) _
      (BoundedContinuousFunction.Nnreal.to_eNNReal_comp_measurable f)
#align measure_theory.finite_measure.test_against_nn_smul MeasureTheory.FiniteMeasure.testAgainstNn_smul

theorem testAgainstNn_lipschitz_estimate (μ : FiniteMeasure Ω) (f g : Ω →ᵇ ℝ≥0) :
    μ.testAgainstNn f ≤ μ.testAgainstNn g + nndist f g * μ.mass :=
  by
  simp only [← μ.test_against_nn_const (nndist f g), ← test_against_nn_add, ← ENNReal.coe_le_coe,
    BoundedContinuousFunction.coe_add, const_apply, ENNReal.coe_add, Pi.add_apply,
    coe_nnreal_ennreal_nndist, test_against_nn_coe_eq]
  apply lintegral_mono
  have le_dist : ∀ ω, dist (f ω) (g ω) ≤ nndist f g := BoundedContinuousFunction.dist_coe_le_dist
  intro ω
  have le' : f ω ≤ g ω + nndist f g :=
    by
    apply (NNReal.le_add_nndist (f ω) (g ω)).trans
    rw [add_le_add_iff_left]
    exact dist_le_coe.mp (le_dist ω)
  have le : (f ω : ℝ≥0∞) ≤ (g ω : ℝ≥0∞) + nndist f g :=
    by
    rw [← ENNReal.coe_add]
    exact ENNReal.coe_mono le'
  rwa [coe_nnreal_ennreal_nndist] at le
#align measure_theory.finite_measure.test_against_nn_lipschitz_estimate MeasureTheory.FiniteMeasure.testAgainstNn_lipschitz_estimate

theorem testAgainstNn_lipschitz (μ : FiniteMeasure Ω) :
    LipschitzWith μ.mass fun f : Ω →ᵇ ℝ≥0 => μ.testAgainstNn f :=
  by
  rw [lipschitzWith_iff_dist_le_mul]
  intro f₁ f₂
  suffices abs (μ.test_against_nn f₁ - μ.test_against_nn f₂ : ℝ) ≤ μ.mass * dist f₁ f₂ by
    rwa [NNReal.dist_eq]
  apply abs_le.mpr
  constructor
  · have key' := μ.test_against_nn_lipschitz_estimate f₂ f₁
    rw [mul_comm] at key'
    suffices ↑(μ.test_against_nn f₂) ≤ ↑(μ.test_against_nn f₁) + ↑μ.mass * dist f₁ f₂ by linarith
    have key := NNReal.coe_mono key'
    rwa [NNReal.coe_add, NNReal.coe_mul, nndist_comm] at key
  · have key' := μ.test_against_nn_lipschitz_estimate f₁ f₂
    rw [mul_comm] at key'
    suffices ↑(μ.test_against_nn f₁) ≤ ↑(μ.test_against_nn f₂) + ↑μ.mass * dist f₁ f₂ by linarith
    have key := NNReal.coe_mono key'
    rwa [NNReal.coe_add, NNReal.coe_mul] at key
#align measure_theory.finite_measure.test_against_nn_lipschitz MeasureTheory.FiniteMeasure.testAgainstNn_lipschitz

/-- Finite measures yield elements of the `weak_dual` of bounded continuous nonnegative
functions via `measure_theory.finite_measure.test_against_nn`, i.e., integration. -/
def toWeakDualBcnn (μ : FiniteMeasure Ω) : WeakDual ℝ≥0 (Ω →ᵇ ℝ≥0)
    where
  toFun f := μ.testAgainstNn f
  map_add' := testAgainstNn_add μ
  map_smul' := testAgainstNn_smul μ
  cont := μ.testAgainstNn_lipschitz.Continuous
#align measure_theory.finite_measure.to_weak_dual_bcnn MeasureTheory.FiniteMeasure.toWeakDualBcnn

@[simp]
theorem coe_toWeakDualBcnn (μ : FiniteMeasure Ω) : ⇑μ.toWeakDualBcnn = μ.testAgainstNn :=
  rfl
#align measure_theory.finite_measure.coe_to_weak_dual_bcnn MeasureTheory.FiniteMeasure.coe_toWeakDualBcnn

@[simp]
theorem toWeakDualBcnn_apply (μ : FiniteMeasure Ω) (f : Ω →ᵇ ℝ≥0) :
    μ.toWeakDualBcnn f = (∫⁻ x, f x ∂(μ : Measure Ω)).toNNReal :=
  rfl
#align measure_theory.finite_measure.to_weak_dual_bcnn_apply MeasureTheory.FiniteMeasure.toWeakDualBcnn_apply

/-- The topology of weak convergence on `measure_theory.finite_measure Ω` is inherited (induced)
from the weak-* topology on `weak_dual ℝ≥0 (Ω →ᵇ ℝ≥0)` via the function
`measure_theory.finite_measure.to_weak_dual_bcnn`. -/
instance : TopologicalSpace (FiniteMeasure Ω) :=
  TopologicalSpace.induced toWeakDualBcnn inferInstance

theorem toWeakDualBcnn_continuous : Continuous (@toWeakDualBcnn Ω _ _ _) :=
  continuous_induced_dom
#align measure_theory.finite_measure.to_weak_dual_bcnn_continuous MeasureTheory.FiniteMeasure.toWeakDualBcnn_continuous

/- Integration of (nonnegative bounded continuous) test functions against finite Borel measures
depends continuously on the measure. -/
theorem continuous_testAgainstNn_eval (f : Ω →ᵇ ℝ≥0) :
    Continuous fun μ : FiniteMeasure Ω => μ.testAgainstNn f :=
  (by apply (WeakBilin.eval_continuous _ _).comp to_weak_dual_bcnn_continuous :
    Continuous ((fun φ : WeakDual ℝ≥0 (Ω →ᵇ ℝ≥0) => φ f) ∘ toWeakDualBcnn))
#align measure_theory.finite_measure.continuous_test_against_nn_eval MeasureTheory.FiniteMeasure.continuous_testAgainstNn_eval

/-- The total mass of a finite measure depends continuously on the measure. -/
theorem continuous_mass : Continuous fun μ : FiniteMeasure Ω => μ.mass :=
  by
  simp_rw [← test_against_nn_one]
  exact continuous_test_against_nn_eval 1
#align measure_theory.finite_measure.continuous_mass MeasureTheory.FiniteMeasure.continuous_mass

/-- Convergence of finite measures implies the convergence of their total masses. -/
theorem Filter.Tendsto.mass {γ : Type _} {F : Filter γ} {μs : γ → FiniteMeasure Ω}
    {μ : FiniteMeasure Ω} (h : Tendsto μs F (𝓝 μ)) : Tendsto (fun i => (μs i).mass) F (𝓝 μ.mass) :=
  (continuous_mass.Tendsto μ).comp h
#align filter.tendsto.mass Filter.Tendsto.mass

theorem tendsto_iff_weak_star_tendsto {γ : Type _} {F : Filter γ} {μs : γ → FiniteMeasure Ω}
    {μ : FiniteMeasure Ω} :
    Tendsto μs F (𝓝 μ) ↔ Tendsto (fun i => (μs i).toWeakDualBcnn) F (𝓝 μ.toWeakDualBcnn) :=
  Inducing.tendsto_nhds_iff ⟨rfl⟩
#align measure_theory.finite_measure.tendsto_iff_weak_star_tendsto MeasureTheory.FiniteMeasure.tendsto_iff_weak_star_tendsto

theorem tendsto_iff_forall_toWeakDualBcnn_tendsto {γ : Type _} {F : Filter γ}
    {μs : γ → FiniteMeasure Ω} {μ : FiniteMeasure Ω} :
    Tendsto μs F (𝓝 μ) ↔
      ∀ f : Ω →ᵇ ℝ≥0, Tendsto (fun i => (μs i).toWeakDualBcnn f) F (𝓝 (μ.toWeakDualBcnn f)) :=
  by
  rw [tendsto_iff_weak_star_tendsto, tendsto_iff_forall_eval_tendsto_topDualPairing]
  rfl
#align measure_theory.finite_measure.tendsto_iff_forall_to_weak_dual_bcnn_tendsto MeasureTheory.FiniteMeasure.tendsto_iff_forall_toWeakDualBcnn_tendsto

theorem tendsto_iff_forall_testAgainstNn_tendsto {γ : Type _} {F : Filter γ}
    {μs : γ → FiniteMeasure Ω} {μ : FiniteMeasure Ω} :
    Tendsto μs F (𝓝 μ) ↔
      ∀ f : Ω →ᵇ ℝ≥0, Tendsto (fun i => (μs i).testAgainstNn f) F (𝓝 (μ.testAgainstNn f)) :=
  by
  rw [finite_measure.tendsto_iff_forall_to_weak_dual_bcnn_tendsto]
  rfl
#align measure_theory.finite_measure.tendsto_iff_forall_test_against_nn_tendsto MeasureTheory.FiniteMeasure.tendsto_iff_forall_testAgainstNn_tendsto

/-- If the total masses of finite measures tend to zero, then the measures tend to
zero. This formulation concerns the associated functionals on bounded continuous
nonnegative test functions. See `finite_measure.tendsto_zero_of_tendsto_zero_mass` for
a formulation stating the weak convergence of measures. -/
theorem tendsto_zero_testAgainstNn_of_tendsto_zero_mass {γ : Type _} {F : Filter γ}
    {μs : γ → FiniteMeasure Ω} (mass_lim : Tendsto (fun i => (μs i).mass) F (𝓝 0)) (f : Ω →ᵇ ℝ≥0) :
    Tendsto (fun i => (μs i).testAgainstNn f) F (𝓝 0) :=
  by
  apply tendsto_iff_dist_tendsto_zero.mpr
  have obs := fun i => (μs i).testAgainstNn_lipschitz_estimate f 0
  simp_rw [test_against_nn_zero, zero_add] at obs
  simp_rw [show ∀ i, dist ((μs i).testAgainstNn f) 0 = (μs i).testAgainstNn f by
      simp only [dist_nndist, NNReal.nndist_zero_eq_val', eq_self_iff_true, imp_true_iff]]
  refine' squeeze_zero (fun i => NNReal.coe_nonneg _) obs _
  simp_rw [NNReal.coe_mul]
  have lim_pair : tendsto (fun i => (⟨nndist f 0, (μs i).mass⟩ : ℝ × ℝ)) F (𝓝 ⟨nndist f 0, 0⟩) :=
    by
    refine' (Prod.tendsto_iff _ _).mpr ⟨tendsto_const_nhds, _⟩
    exact (nnreal.continuous_coe.tendsto 0).comp mass_lim
  have key := tendsto_mul.comp lim_pair
  rwa [MulZeroClass.mul_zero] at key
#align measure_theory.finite_measure.tendsto_zero_test_against_nn_of_tendsto_zero_mass MeasureTheory.FiniteMeasure.tendsto_zero_testAgainstNn_of_tendsto_zero_mass

/-- If the total masses of finite measures tend to zero, then the measures tend to zero. -/
theorem tendsto_zero_of_tendsto_zero_mass {γ : Type _} {F : Filter γ} {μs : γ → FiniteMeasure Ω}
    (mass_lim : Tendsto (fun i => (μs i).mass) F (𝓝 0)) : Tendsto μs F (𝓝 0) :=
  by
  rw [tendsto_iff_forall_test_against_nn_tendsto]
  intro f
  convert tendsto_zero_test_against_nn_of_tendsto_zero_mass mass_lim f
  rw [zero.test_against_nn_apply]
#align measure_theory.finite_measure.tendsto_zero_of_tendsto_zero_mass MeasureTheory.FiniteMeasure.tendsto_zero_of_tendsto_zero_mass

/-- A characterization of weak convergence in terms of integrals of bounded continuous
nonnegative functions. -/
theorem tendsto_iff_forall_lintegral_tendsto {γ : Type _} {F : Filter γ} {μs : γ → FiniteMeasure Ω}
    {μ : FiniteMeasure Ω} :
    Tendsto μs F (𝓝 μ) ↔
      ∀ f : Ω →ᵇ ℝ≥0,
        Tendsto (fun i => ∫⁻ x, f x ∂(μs i : Measure Ω)) F (𝓝 (∫⁻ x, f x ∂(μ : Measure Ω))) :=
  by
  rw [tendsto_iff_forall_to_weak_dual_bcnn_tendsto]
  simp_rw [to_weak_dual_bcnn_apply _ _, ← test_against_nn_coe_eq, ENNReal.tendsto_coe,
    ENNReal.toNNReal_coe]
#align measure_theory.finite_measure.tendsto_iff_forall_lintegral_tendsto MeasureTheory.FiniteMeasure.tendsto_iff_forall_lintegral_tendsto

end FiniteMeasure

-- section
section FiniteMeasureBoundedConvergence

/-! ### Bounded convergence results for finite measures

This section is about bounded convergence theorems for finite measures.
-/

variable {Ω : Type _} [MeasurableSpace Ω] [TopologicalSpace Ω] [OpensMeasurableSpace Ω]

/-- A bounded convergence theorem for a finite measure:
If bounded continuous non-negative functions are uniformly bounded by a constant and tend to a
limit, then their integrals against the finite measure tend to the integral of the limit.
This formulation assumes:
 * the functions tend to a limit along a countably generated filter;
 * the limit is in the almost everywhere sense;
 * boundedness holds almost everywhere;
 * integration is `measure_theory.lintegral`, i.e., the functions and their integrals are
   `ℝ≥0∞`-valued.
-/
theorem tendsto_lintegral_nn_filter_of_le_const {ι : Type _} {L : Filter ι} [L.IsCountablyGenerated]
    (μ : Measure Ω) [IsFiniteMeasure μ] {fs : ι → Ω →ᵇ ℝ≥0} {c : ℝ≥0}
    (fs_le_const : ∀ᶠ i in L, ∀ᵐ ω : Ω ∂μ, fs i ω ≤ c) {f : Ω → ℝ≥0}
    (fs_lim : ∀ᵐ ω : Ω ∂μ, Tendsto (fun i => fs i ω) L (𝓝 (f ω))) :
    Tendsto (fun i => ∫⁻ ω, fs i ω ∂μ) L (𝓝 (∫⁻ ω, f ω ∂μ)) :=
  by
  simpa only using
    tendsto_lintegral_filter_of_dominated_convergence (fun _ => c)
      (eventually_of_forall fun i => (ennreal.continuous_coe.comp (fs i).Continuous).Measurable) _
      (@lintegral_const_lt_top _ _ μ _ _ (@ENNReal.coe_ne_top c)).Ne _
  · simpa only [ENNReal.coe_le_coe] using fs_le_const
  · simpa only [ENNReal.tendsto_coe] using fs_lim
#align measure_theory.finite_measure.tendsto_lintegral_nn_filter_of_le_const MeasureTheory.FiniteMeasure.tendsto_lintegral_nn_filter_of_le_const

/-- A bounded convergence theorem for a finite measure:
If a sequence of bounded continuous non-negative functions are uniformly bounded by a constant
and tend pointwise to a limit, then their integrals (`measure_theory.lintegral`) against the finite
measure tend to the integral of the limit.

A related result with more general assumptions is
`measure_theory.finite_measure.tendsto_lintegral_nn_filter_of_le_const`.
-/
theorem tendsto_lintegral_nn_of_le_const (μ : FiniteMeasure Ω) {fs : ℕ → Ω →ᵇ ℝ≥0} {c : ℝ≥0}
    (fs_le_const : ∀ n ω, fs n ω ≤ c) {f : Ω → ℝ≥0}
    (fs_lim : ∀ ω, Tendsto (fun n => fs n ω) atTop (𝓝 (f ω))) :
    Tendsto (fun n => ∫⁻ ω, fs n ω ∂(μ : Measure Ω)) atTop (𝓝 (∫⁻ ω, f ω ∂(μ : Measure Ω))) :=
  tendsto_lintegral_nn_filter_of_le_const μ
    (eventually_of_forall fun n => eventually_of_forall (fs_le_const n))
    (eventually_of_forall fs_lim)
#align measure_theory.finite_measure.tendsto_lintegral_nn_of_le_const MeasureTheory.FiniteMeasure.tendsto_lintegral_nn_of_le_const

/-- A bounded convergence theorem for a finite measure:
If bounded continuous non-negative functions are uniformly bounded by a constant and tend to a
limit, then their integrals against the finite measure tend to the integral of the limit.
This formulation assumes:
 * the functions tend to a limit along a countably generated filter;
 * the limit is in the almost everywhere sense;
 * boundedness holds almost everywhere;
 * integration is the pairing against non-negative continuous test functions
   (`measure_theory.finite_measure.test_against_nn`).

A related result using `measure_theory.lintegral` for integration is
`measure_theory.finite_measure.tendsto_lintegral_nn_filter_of_le_const`.
-/
theorem tendsto_testAgainstNn_filter_of_le_const {ι : Type _} {L : Filter ι}
    [L.IsCountablyGenerated] {μ : FiniteMeasure Ω} {fs : ι → Ω →ᵇ ℝ≥0} {c : ℝ≥0}
    (fs_le_const : ∀ᶠ i in L, ∀ᵐ ω : Ω ∂(μ : Measure Ω), fs i ω ≤ c) {f : Ω →ᵇ ℝ≥0}
    (fs_lim : ∀ᵐ ω : Ω ∂(μ : Measure Ω), Tendsto (fun i => fs i ω) L (𝓝 (f ω))) :
    Tendsto (fun i => μ.testAgainstNn (fs i)) L (𝓝 (μ.testAgainstNn f)) :=
  by
  apply
    (ENNReal.tendsto_toNNReal
        (lintegral_lt_top_of_bounded_continuous_to_nnreal (μ : Measure Ω) f).Ne).comp
  exact tendsto_lintegral_nn_filter_of_le_const μ fs_le_const fs_lim
#align measure_theory.finite_measure.tendsto_test_against_nn_filter_of_le_const MeasureTheory.FiniteMeasure.tendsto_testAgainstNn_filter_of_le_const

/-- A bounded convergence theorem for a finite measure:
If a sequence of bounded continuous non-negative functions are uniformly bounded by a constant and
tend pointwise to a limit, then their integrals (`measure_theory.finite_measure.test_against_nn`)
against the finite measure tend to the integral of the limit.

Related results:
 * `measure_theory.finite_measure.tendsto_test_against_nn_filter_of_le_const`:
   more general assumptions
 * `measure_theory.finite_measure.tendsto_lintegral_nn_of_le_const`:
   using `measure_theory.lintegral` for integration.
-/
theorem tendsto_testAgainstNn_of_le_const {μ : FiniteMeasure Ω} {fs : ℕ → Ω →ᵇ ℝ≥0} {c : ℝ≥0}
    (fs_le_const : ∀ n ω, fs n ω ≤ c) {f : Ω →ᵇ ℝ≥0}
    (fs_lim : ∀ ω, Tendsto (fun n => fs n ω) atTop (𝓝 (f ω))) :
    Tendsto (fun n => μ.testAgainstNn (fs n)) atTop (𝓝 (μ.testAgainstNn f)) :=
  tendsto_testAgainstNn_filter_of_le_const
    (eventually_of_forall fun n => eventually_of_forall (fs_le_const n))
    (eventually_of_forall fs_lim)
#align measure_theory.finite_measure.tendsto_test_against_nn_of_le_const MeasureTheory.FiniteMeasure.tendsto_testAgainstNn_of_le_const

end FiniteMeasureBoundedConvergence

-- section
section FiniteMeasureConvergenceByBoundedContinuousFunctions

/-! ### Weak convergence of finite measures with bounded continuous real-valued functions

In this section we characterize the weak convergence of finite measures by the usual (defining)
condition that the integrals of all bounded continuous real-valued functions converge.
-/

variable {Ω : Type _} [MeasurableSpace Ω] [TopologicalSpace Ω] [OpensMeasurableSpace Ω]

theorem integrableOfBoundedContinuousToNnreal (μ : Measure Ω) [IsFiniteMeasure μ] (f : Ω →ᵇ ℝ≥0) :
    Integrable ((coe : ℝ≥0 → ℝ) ∘ ⇑f) μ :=
  by
  refine' ⟨(nnreal.continuous_coe.comp f.continuous).Measurable.AeStronglyMeasurable, _⟩
  simp only [has_finite_integral, NNReal.nnnorm_eq]
  exact lintegral_lt_top_of_bounded_continuous_to_nnreal _ f
#align measure_theory.finite_measure.integrable_of_bounded_continuous_to_nnreal MeasureTheory.FiniteMeasure.integrableOfBoundedContinuousToNnreal

theorem integrableOfBoundedContinuousToReal (μ : Measure Ω) [IsFiniteMeasure μ] (f : Ω →ᵇ ℝ) :
    Integrable (⇑f) μ :=
  by
  refine' ⟨f.continuous.measurable.ae_strongly_measurable, _⟩
  have aux : (coe : ℝ≥0 → ℝ) ∘ ⇑f.nnnorm = fun x => ‖f x‖ :=
    by
    ext ω
    simp only [Function.comp_apply, BoundedContinuousFunction.nnnorm_coe_fun_eq, coe_nnnorm]
  apply (has_finite_integral_iff_norm ⇑f).mpr
  rw [← of_real_integral_eq_lintegral_of_real]
  · exact ENNReal.ofReal_lt_top
  · exact aux ▸ integrable_of_bounded_continuous_to_nnreal μ f.nnnorm
  · exact eventually_of_forall fun ω => norm_nonneg (f ω)
#align measure_theory.finite_measure.integrable_of_bounded_continuous_to_real MeasureTheory.FiniteMeasure.integrableOfBoundedContinuousToReal

theorem BoundedContinuousFunction.integral_eq_integral_nnrealPart_sub (μ : Measure Ω)
    [IsFiniteMeasure μ] (f : Ω →ᵇ ℝ) :
    (∫ ω, f ω ∂μ) = (∫ ω, f.nnrealPart ω ∂μ) - ∫ ω, (-f).nnrealPart ω ∂μ := by
  simp only [f.self_eq_nnreal_part_sub_nnreal_part_neg, Pi.sub_apply, integral_sub,
    integrable_of_bounded_continuous_to_nnreal]
#align bounded_continuous_function.integral_eq_integral_nnreal_part_sub BoundedContinuousFunction.integral_eq_integral_nnrealPart_sub

theorem lintegral_lt_top_of_bounded_continuous_to_real {Ω : Type _} [MeasurableSpace Ω]
    [TopologicalSpace Ω] (μ : Measure Ω) [IsFiniteMeasure μ] (f : Ω →ᵇ ℝ) :
    (∫⁻ ω, ENNReal.ofReal (f ω) ∂μ) < ∞ :=
  lintegral_lt_top_of_bounded_continuous_to_nNReal _ f.nnrealPart
#align measure_theory.finite_measure.lintegral_lt_top_of_bounded_continuous_to_real MeasureTheory.FiniteMeasure.lintegral_lt_top_of_bounded_continuous_to_real

theorem tendsto_of_forall_integral_tendsto {γ : Type _} {F : Filter γ} {μs : γ → FiniteMeasure Ω}
    {μ : FiniteMeasure Ω}
    (h :
      ∀ f : Ω →ᵇ ℝ,
        Tendsto (fun i => ∫ x, f x ∂(μs i : Measure Ω)) F (𝓝 (∫ x, f x ∂(μ : Measure Ω)))) :
    Tendsto μs F (𝓝 μ) :=
  by
  apply (@tendsto_iff_forall_lintegral_tendsto Ω _ _ _ γ F μs μ).mpr
  intro f
  have key :=
    @ENNReal.tendsto_toReal_iff _ F _
      (fun i => (lintegral_lt_top_of_bounded_continuous_to_nnreal (μs i : Measure Ω) f).Ne) _
      (lintegral_lt_top_of_bounded_continuous_to_nnreal (μ : Measure Ω) f).Ne
  simp only [ENNReal.ofReal_coe_nnreal] at key
  apply key.mp
  have lip : LipschitzWith 1 (coe : ℝ≥0 → ℝ) := isometry_subtype_coe.lipschitz
  set f₀ := BoundedContinuousFunction.comp _ lip f with def_f₀
  have f₀_eq : ⇑f₀ = (coe : ℝ≥0 → ℝ) ∘ ⇑f := by rfl
  have f₀_nn : 0 ≤ ⇑f₀ := fun _ => by simp only [f₀_eq, Pi.zero_apply, NNReal.zero_le_coe]
  have f₀_ae_nn : 0 ≤ᵐ[(μ : Measure Ω)] ⇑f₀ := eventually_of_forall f₀_nn
  have f₀_ae_nns : ∀ i, 0 ≤ᵐ[(μs i : Measure Ω)] ⇑f₀ := fun i => eventually_of_forall f₀_nn
  have aux :=
    integral_eq_lintegral_of_nonneg_ae f₀_ae_nn f₀.continuous.measurable.ae_strongly_measurable
  have auxs := fun i =>
    integral_eq_lintegral_of_nonneg_ae (f₀_ae_nns i) f₀.continuous.measurable.ae_strongly_measurable
  simp only [f₀_eq, ENNReal.ofReal_coe_nnreal] at aux auxs
  simpa only [← aux, ← auxs] using h f₀
#align measure_theory.finite_measure.tendsto_of_forall_integral_tendsto MeasureTheory.FiniteMeasure.tendsto_of_forall_integral_tendsto

theorem BoundedContinuousFunction.Nnreal.toReal_lintegral_eq_integral (f : Ω →ᵇ ℝ≥0)
    (μ : Measure Ω) : (∫⁻ x, (f x : ℝ≥0∞) ∂μ).toReal = ∫ x, f x ∂μ :=
  by
  rw [integral_eq_lintegral_of_nonneg_ae _
      (nnreal.continuous_coe.comp f.continuous).Measurable.AeStronglyMeasurable]
  · simp only [ENNReal.ofReal_coe_nnreal]
  · apply eventually_of_forall
    simp only [Pi.zero_apply, NNReal.zero_le_coe, imp_true_iff]
#align bounded_continuous_function.nnreal.to_real_lintegral_eq_integral BoundedContinuousFunction.Nnreal.toReal_lintegral_eq_integral

/-- A characterization of weak convergence in terms of integrals of bounded continuous
real-valued functions. -/
theorem tendsto_iff_forall_integral_tendsto {γ : Type _} {F : Filter γ} {μs : γ → FiniteMeasure Ω}
    {μ : FiniteMeasure Ω} :
    Tendsto μs F (𝓝 μ) ↔
      ∀ f : Ω →ᵇ ℝ,
        Tendsto (fun i => ∫ x, f x ∂(μs i : Measure Ω)) F (𝓝 (∫ x, f x ∂(μ : Measure Ω))) :=
  by
  refine' ⟨_, tendsto_of_forall_integral_tendsto⟩
  rw [tendsto_iff_forall_lintegral_tendsto]
  intro h f
  simp_rw [BoundedContinuousFunction.integral_eq_integral_nnrealPart_sub]
  set f_pos := f.nnreal_part with def_f_pos
  set f_neg := (-f).nnrealPart with def_f_neg
  have tends_pos :=
    (ENNReal.tendsto_toReal
          (lintegral_lt_top_of_bounded_continuous_to_nnreal (μ : Measure Ω) f_pos).Ne).comp
      (h f_pos)
  have tends_neg :=
    (ENNReal.tendsto_toReal
          (lintegral_lt_top_of_bounded_continuous_to_nnreal (μ : Measure Ω) f_neg).Ne).comp
      (h f_neg)
  have aux :
    ∀ g : Ω →ᵇ ℝ≥0,
      (ENNReal.toReal ∘ fun i : γ => ∫⁻ x : Ω, ↑(g x) ∂(μs i : Measure Ω)) = fun i : γ =>
        (∫⁻ x : Ω, ↑(g x) ∂(μs i : Measure Ω)).toReal :=
    fun _ => rfl
  simp_rw [aux, BoundedContinuousFunction.Nnreal.toReal_lintegral_eq_integral] at
    tends_pos tends_neg
  exact tendsto.sub tends_pos tends_neg
#align measure_theory.finite_measure.tendsto_iff_forall_integral_tendsto MeasureTheory.FiniteMeasure.tendsto_iff_forall_integral_tendsto

end FiniteMeasureConvergenceByBoundedContinuousFunctions

-- section
end FiniteMeasure

-- namespace
end MeasureTheory

-- namespace


/-
Copyright (c) 2018 Chris Hughes. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Chris Hughes
-/

import algebra.big_operators data.real.cau_seq tactic.ring algebra.archimedean data.nat.choose analysis.limits .disjoint_finset

open nat is_absolute_value finset

variables {α : Type*} {β : Type*} (f g : ℕ → α) (n m : ℕ)

local infix `^` := monoid.pow

section sum_range
variable [add_comm_monoid α]

lemma sum_range_succ : (range (succ n)).sum f = f n + (range n).sum f :=
have h : n ∉ finset.range n := by rw finset.mem_range; exact lt_irrefl _,
by rw [finset.range_succ, finset.sum_insert h]

lemma sum_range_succ' : ∀ n : ℕ, f ∑ succ n = (λ m, f (succ m)) ∑ n + f 0
| 0        := by simp
| (succ n) := by rw [sum_range_succ (λ m, f (succ m)), add_assoc, ← sum_range_succ'];
                 exact sum_range_succ _ _

lemma sum_range_comm : f ∑ n = (λ m, f (n - (succ m))) ∑ n :=
begin
  induction n with n hi,
  { simp },
  { rw [sum_range_succ, sum_range_succ', hi, succ_sub_one, add_comm],
    simp [succ_sub_succ] }
end

lemma sum_range_diag_flip1 (f : ℕ → ℕ → α) :
    (range n).sum (λ m, (range (m+1)).sum (λ k, f k (m - k))) =
    (range n).sum (λ m, (range (n - m)).sum (f m)) :=
let f' : ℕ → ℕ → α := λ m k, if m + k < n then f m k else 0 in
calc (range n).sum (λ m, (range (m+1)).sum (λ k, f k (m - k))) =
    (range n).sum (λ m, (range n).sum (λ k, f' k (m - k))) :
    sum_congr rfl (λ x hx, begin end)
#print nat.lt_sub
lemma sum_range_diag_flip2 (f : ℕ → ℕ → α) :
    (range n).sum (λ m, (range (m+1)).sum (λ k, f k (m - k))) =
    (range n).sum (λ m, (range (n - m)).sum (f m)) :=
have h₁ : ((range n).sigma (range ∘ succ)).sum
    (λ (a : Σ m, ℕ), f (a.2) (a.1 - a.2)) =
    (range n).sum (λ m, (range (m + 1)).sum
    (λ k, f k (m - k))) := sum_sigma,
have h₂ : ((range n).sigma (λ m, range (n - m))).sum (λ a : Σ (m : ℕ), ℕ, f (a.1) (a.2)) =
    (range n).sum (λ m, sum (range (n - m)) (f m)) := sum_sigma,
h₁ ▸ h₂ ▸ sum_bij
    (λ a _, ⟨a.2, a.1 - a.2⟩)
    (λ a ha, have h₁ : a.1 < n := mem_range.1 (mem_sigma.1 ha).1,
      have h₂ : a.2 < succ a.1 := mem_range.1 (mem_sigma.1 ha).2,
        mem_sigma.2 ⟨mem_range.2 (lt_of_lt_of_le h₂ h₁),
        mem_range.2 ((nat.sub_lt_sub_right_iff (le_of_lt_succ h₂)).2 h₁)⟩)
    (λ _ _, rfl)
    (λ ⟨a₁, a₂⟩ ⟨b₁, b₂⟩ ha hb h,
      have ha : a₁ < n ∧ a₂ ≤ a₁ :=
          ⟨mem_range.1 (mem_sigma.1 ha).1, le_of_lt_succ (mem_range.1 (mem_sigma.1 ha).2)⟩,
      have hb : b₁ < n ∧ b₂ ≤ b₁ :=
          ⟨mem_range.1 (mem_sigma.1 hb).1, le_of_lt_succ (mem_range.1 (mem_sigma.1 hb).2)⟩,
      have h : a₂ = b₂ ∧ _ := sigma.mk.inj h,
      have h' : a₁ - a₂ = b₁ - b₂ := eq_of_heq h.2,
      sigma.mk.inj_iff.2 ⟨by rwa [nat.sub_eq_iff_eq_add ha.2, h.1, nat.sub_add_cancel hb.2] at h',
        (heq_of_eq h.1)⟩)
    (λ ⟨a₁, a₂⟩ ha,
      have ha : a₁ < n ∧ a₂ < n - a₁ :=
          ⟨mem_range.1 (mem_sigma.1 ha).1, (mem_range.1 (mem_sigma.1 ha).2)⟩,
      ⟨⟨a₂ + a₁, a₁⟩, ⟨mem_sigma.2 ⟨mem_range.2 ((nat.lt_sub_right_iff_add_lt (le_of_lt ha.1)).1 ha.2),
        mem_range.2 (lt_succ_of_le (le_add_left _ _))⟩,
      sigma.mk.inj_iff.2 ⟨rfl, heq_of_eq (nat.add_sub_cancel _ _).symm⟩⟩⟩)

lemma sum_range_diag_flip (f : ℕ → ℕ → α) :
    (λ m, (λ k, f k (m - k)) ∑ (succ m)) ∑ n = (λ m, (λ k, f m k) ∑ (n - m)) ∑ n :=
begin
  suffices : ∀ j < n, (λ m, (λ k, f k (m - k)) ∑ succ (min j m)) ∑ n = (λ m, (λ k, f m k) ∑ (n - m)) ∑ succ j,
  { cases n with n,
    { simp },
    { rw ← this n (lt_succ_self _),
      apply finset.sum_congr rfl,
      assume m hm,
      rw finset.mem_range at hm,
      rw min_eq_right (le_of_lt_succ hm) } },
  assume j hj,
  induction j with j hi,
  { clear hj,
    induction n; simp * at * },
  { specialize hi (le_of_succ_le hj),
    rw [sum_range_succ _ (succ j), ← hi],
    clear hi,
    induction n with n hi,
    { exact absurd hj dec_trivial },
    { cases lt_or_eq_of_le (le_of_lt_succ hj) with hj' hj',
      { specialize hi hj',
        rw [sum_range_succ, sum_range_succ _ n, hi, min_eq_left (le_of_lt hj'), succ_sub (le_of_lt hj'),
            min_eq_left (le_of_lt (lt_of_succ_lt_succ hj)), sum_range_succ _ (_ - _), sum_range_succ _ (succ j)],
        simp },
      { rw [sum_range_succ, sum_range_succ _ n, ← hj', min_eq_left (le_refl _), min_eq_left (le_succ _), sum_range_succ _ (succ _),
          succ_sub (le_refl _), nat.sub_self, sum_range_succ _ 0, finset.range_zero, finset.sum_empty, add_zero, ← add_assoc],
        refine congr_arg _ (finset.sum_congr rfl _),
        assume m hm,
        rw finset.mem_range at hm,
        rw [min_eq_right (le_of_lt hm), min_eq_right (le_of_lt_succ hm)] } } }
end

end sum_range

theorem binomial [comm_semiring α] (x y : α) : ∀ n : ℕ,
    (x + y)^n = (λ m, x^m * y^(n - m) * choose n m) ∑ succ n
| 0        := by simp
| (succ n) :=
begin
  rw [_root_.pow_succ, binomial, add_mul, finset.mul_sum, finset.mul_sum, sum_range_succ, sum_range_succ',
      sum_range_succ, sum_range_succ', add_assoc, ← add_assoc (_ ∑ n), ← finset.sum_add_distrib],
  have h₁ : x * (x^n * y^(n - n) * choose n n) = x^succ n * y^(succ n - succ n)
      * choose (succ n) (succ n) :=
    by simp [_root_.pow_succ, mul_assoc, mul_comm, mul_left_comm],
  have  h₂ : y * (x^0 * y^(n - 0) * choose n 0) = x^0 * y^(succ n - 0) * choose (succ n) 0 :=
    by simp [_root_.pow_succ, mul_assoc, mul_comm, mul_left_comm],
  have h₃ : (λ m, x * (x^m * y^(n - m) * choose n m) + y * (x^succ m * y^(n - succ m)
      * choose n (succ m))) ∑ n
      = (λ m, x^succ m * y^(succ n - succ m) * ↑(choose (succ n) (succ m))) ∑ n :=
    finset.sum_congr rfl
      begin
        assume m hm,
        rw finset.mem_range at hm,
        rw [← mul_assoc y, ← mul_assoc y, mul_right_comm y, ← _root_.pow_succ, add_one, ← succ_sub hm],
        simp [succ_sub_succ, _root_.pow_succ, choose_succ_succ, mul_add, mul_comm,
            mul_assoc, mul_left_comm]
      end,
  rw [h₁, h₂, h₃]
end

lemma zero_pow [semiring α] {n : ℕ} (hn : 0 < n) : (0 : α)^n = 0 :=
begin
  induction n with n hi,
  { exact absurd hn dec_trivial },
  { cases n with n,
    { simp },
    { simp [hi dec_trivial, _root_.pow_succ _ (succ _), zero_mul] } }
end

lemma pow_abv (x : β) {n : ℕ} (hn : 1 ≤ n) (abv: β → α) [is_absolute_value abv] : abv (x^n) = (abv x)^n :=
begin
  induction n with n hi,
  { exact absurd hn dec_trivial },
  { cases n with n,
    { simp },
    { simp [hi dec_trivial, _root_.pow_succ _ (succ _), abv_mul abv] } }
end

section geo_series
open cau_seq
variables [discrete_linear_ordered_field α] [ring β] {abv : β → α} [is_absolute_value abv]

private lemma lim_zero_pow_lt_one_aux [archimedean α] {x : β} (hx : abv x < 1) : ∀ ε > 0, ∃ i : ℕ, ∀ j ≥ i, abv (x^j) < ε :=
begin
  assume ε ε0,
  cases classical.em (x = 0),
  { existsi 1,
    assume j hj,
    simpa [h, _root_.zero_pow hj, abv_zero abv] },
  { have hx : (abv x)⁻¹ > 1 := one_lt_inv ((abv_pos abv).mpr h) hx,
    cases pow_unbounded_of_gt_one ε⁻¹ hx with i hi,
    have hax : 0 < abv x  := by rwa abv_pos abv,
    existsi max i 1,
    assume j hj,
    rw [pow_abv _ (le_trans (le_max_right _ _) hj), ← inv_lt_inv ε0 (pow_pos hax _),
        pow_inv _ _ (ne_of_lt hax).symm],
    exact lt_of_lt_of_le hi (pow_le_pow (le_of_lt hx) (le_trans (le_max_left _ _) hj)) }
end

lemma is_cau_pow_lt_one [archimedean α] {x : β} (hx : abv x < 1) : is_cau_seq abv (λ n, x^n) :=
of_near _ (const abv 0) $ by simp only [const_apply, sub_zero]; exact lim_zero_pow_lt_one_aux hx

lemma lim_zero_pow_lt_one [archimedean α] (x : β) (hx : abv x < 1) : lim_zero ⟨λ n, x^n, is_cau_pow_lt_one _ hx⟩ :=
lim_zero_pow_lt_one_aux abv hx

lemma sum_geo {x : β} (hx : x ≠ 1) : ∀ n, (λ m, x^m) ∑ n * (1 - x) = 1 - x^n
| 0       := by simp
| (n + 1) := by rw [sum_range_succ, add_mul, sum_geo]; simp [mul_add, _root_.pow_succ']

lemma is_cau_abv_geo_series [archimedean α] {x : β} (hx : abv x < 1) : is_cau_seq abs (λ n, (λ m, (abv x)^m) ∑ n) :=
begin
  have haa : abs (abv x) < 1 := by rwa abs_of_nonneg (abv_nonneg abv _),
  have hax1 : ¬ 1 - abv x = 0 := by rw [sub_eq_zero_iff_eq]; exact (ne_of_lt hx).symm,
  have hax1' : ¬ abv x = 1 := by rwa [eq_comm, ← sub_eq_zero_iff_eq],
  let s : cau_seq α abs := (cau_seq.const abs 1 - ⟨_, is_cau_pow_lt_one abs haa⟩) *
      cau_seq.inv (cau_seq.const abs (1 - abv x)) (by rwa const_lim_zero),
  refine (cau_seq.of_eq s _ _).2,
  assume n,
  simp [s],
  rw [← div_eq_mul_inv, div_eq_iff_mul_eq],
  exact sum_geo hax1' _, assumption,
end

end geo_series
-- -- proof that two different ways of representing a sum across a 2D plane are equal, used
-- -- in proof of exp (x + y) = exp x * exp y
-- lemma series_series_diag_flip [add_comm_monoid α] (f : ℕ → ℕ → α) (n : ℕ) : series (λ i,
-- series (λ k, f k (i - k)) i) n = series (λ i, series (λ k, f i k) (n - i)) n := begin
--   have : ∀ m : ℕ, m ≤ n → series (λ (i : ℕ), series (λ k, f k (i - k)) (min m i)) n =
--   series (λ i, series (λ k, f i k) (n - i)) m := by
--   { assume m mn, induction m with m' hi,
--     simp[series_succ,series_zero,mul_add,max_eq_left (zero_le n)],
--     simp only [series_succ _ m'],rw ←hi (le_of_succ_le mn),clear hi,
--     induction n with n' hi,
--     simp[series_succ],exact absurd mn dec_trivial,cases n' with n₂,
--     simp [series_succ],rw [min_eq_left mn,series_succ,min_eq_left (le_of_succ_le mn)],
--     rw eq_zero_of_le_zero (le_of_succ_le_succ mn),simp,
--     cases lt_or_eq_of_le mn,
--     simp [series_succ _ (succ n₂),min_eq_left mn,hi (le_of_lt_succ h)],rw [←add_assoc,←add_assoc],
--     suffices : series (f (succ m')) (n₂ - m') + series (λ (k : ℕ), f k (succ (succ n₂) - k)) (succ m')
--     = series (f (succ m')) (succ n₂ - m') +
--         series (λ (k : ℕ), f k (succ (succ n₂) - k)) (min m' (succ (succ n₂))),
--       rw this,rw[min_eq_left (le_of_succ_le mn),series_succ,succ_sub_succ,succ_sub (le_of_succ_le_succ (le_of_lt_succ h)),series_succ],
--       rw [add_comm (series (λ (k : ℕ), f k (succ (succ n₂) - k)) m'),add_assoc],
--     rw ←h,simp[nat.sub_self],clear hi mn h,simp[series_succ,nat.sub_self],
--     suffices : series (λ (i : ℕ), series (λ (k : ℕ), f k (i - k)) (min (succ m') i)) m' = series (λ (i : ℕ), series (λ (k : ℕ), f k (i - k)) (min m' i)) m',
--       rw [this,min_eq_left (le_succ _)],clear n₂,
--     have h₁ : ∀ i ≤ m', (λ (i : ℕ), series (λ (k : ℕ), f k (i - k)) (min (succ m') i)) i = (λ (i : ℕ), series (λ (k : ℕ), f k (i - k)) (min m' i)) i,
--       assume i im,simp, rw [min_eq_right im,min_eq_right (le_succ_of_le im)],
--     rw series_congr h₁},
--   specialize this n (le_refl _),
--   rw ←this,refine series_congr _,assume i ni,rw min_eq_right ni,
-- end

-- open monoid

-- theorem series_binomial {α : Type*} [comm_semiring α] (x y : α) (i : ℕ) : pow (x + y) i =
-- series (λ j, choose i j * pow x j * pow y (i - j)) i := begin
--   induction i with i' hi,
--   simp!,unfold monoid.pow,rw hi,
--   rw [←series_mul_left],
--   have : ∀ j : ℕ, j ≤ i' → (λ (i : ℕ), (x + y) * (↑(choose i' i) * pow x i * pow y (i' - i))) j
--   = choose i' j * pow x (succ j) * pow y (i' - j) + choose i' j * pow x j * pow y (succ i' - j) := by
--   { assume j ji,dsimp only,rw add_mul,
--     have :  x * (↑(choose i' j) * pow x j * pow y (i' - j)) + y * (↑(choose i' j) * pow x j * pow y (i' - j))
--     = ↑(choose i' j) * (x * pow x j) * pow y (i' - j) + ↑(choose i' j) * pow x j * (y * pow y (i' - j)),
--       simp[mul_comm,_root_.mul_assoc,mul_left_comm],
--     rw [this,←_root_.pow_succ,←_root_.pow_succ,succ_sub ji]},
--   rw [series_congr this],clear this,
--   clear hi,rw series_add,
--   have : series (λ (i : ℕ), ↑(choose i' i) * pow x i * pow y (succ i' - i)) i' =
--       series (λ (i : ℕ), ↑(choose i' i) * pow x i * pow y (succ i' - i)) (succ i') := by
--   { simp[series_succ],},
--   rw [this,series_succ₁,series_succ₁],
--   simp[nat.sub_self],rw ←series_add,
--   refine congr_arg _ (series_congr _),
--   assume j ji,unfold choose,rw [nat.cast_add,add_mul,add_mul],
-- end

-- lemma geo_series_eq {α : Type*} [field α] (x : α) (n : ℕ) : x ≠ 1 → series (pow x) n = (1 - pow x (succ n)) / (1 - x) := begin
--   assume x1,have x1' : 1 + -x ≠ 0,assume h,rw [eq_comm, ←sub_eq_iff_eq_add] at h,simp at h,trivial,
--   induction n with n' hi,
--   {simp![div_self x1']},
--   {rw eq_div_iff_mul_eq,simpa,
--   rw [_root_.series_succ,_root_.pow_succ _ (succ n')],
--   rw hi,simp,rw [add_mul,div_mul_cancel _ x1',mul_add],ring,exact x1'},
-- end

-- lemma is_cau_geo_series {α : Type*} [discrete_linear_ordered_field α] [archimedean α] (x : α) :
-- abs x < 1 → is_cau_seq abs (series (pow x)) := begin
--   assume x1, have : series (pow x) = λ n,(1 - pow x (succ n)) / (1 - x),
--     apply funext,assume n,refine geo_series_eq x n _ ,assume h, rw h at x1,exact absurd x1 (by norm_num),rw this,
--   have absx : 0 < abs (1 - x),refine abs_pos_of_ne_zero _,assume h,rw sub_eq_zero_iff_eq at h,rw ←h at x1,
--   have : ¬abs (1 : α) < 1,norm_num,trivial,simp at absx,
--   cases classical.em (x = 0),rw h,simp[monoid.pow],assume ε ε0,existsi 1,assume j j1,simpa!,
--   have x2: 1 < (abs x)⁻¹,rw lt_inv,simpa,{norm_num},exact abs_pos_of_ne_zero h,
--   have pos_x : 0 < abs x := abs_pos_of_ne_zero h,
--   assume ε ε0,
--   cases pow_unbounded_of_gt_one (2 / (ε * abs (1 - x))) x2 with i hi,
--   have ε2 : 0 < 2 / (ε * abs (1 - x)) := div_pos (by norm_num) (mul_pos ε0 absx),
--   rw [pow_inv,lt_inv ε2 (pow_pos pos_x _)] at hi,
--   existsi i,assume j ji,rw [inv_eq_one_div,div_div_eq_mul_div,_root_.one_mul,lt_div_iff (by norm_num : (0 : α) < 2)] at hi,
--   rw [div_sub_div_same,abs_div,div_lt_iff absx],
--   refine lt_of_le_of_lt _ hi,
--   simp,
--   refine le_trans (abs_add _ _) _,
--   have : pow (abs x) i * 2 = pow (abs x) i + pow (abs x) i,ring,
--   rw this,
--   refine add_le_add _ _,
--   {rw [←_root_.one_mul (pow (abs x) i),pow_abs,_root_.pow_succ,abs_mul],
--   exact mul_le_mul_of_nonneg_right (le_of_lt x1) (abs_nonneg _)},
--   {rw [abs_neg,←pow_abs],
--   rw [←inv_le_inv (pow_pos pos_x _) (pow_pos pos_x _),←pow_inv,←pow_inv],
--   refine pow_le_pow (le_of_lt x2) (le_succ_of_le ji),}
-- end

-- lemma is_cau_geo_series_const {α : Type*} [discrete_linear_ordered_field α] [archimedean α] (a x : α) :
-- abs x < 1 → is_cau_seq abs (series (λ n, a * pow x n)) := begin
--   assume x1 ε ε0,
--   cases classical.em (a = 0),
--   existsi 0,intros,rw [series_mul_left],induction j,simp!,assumption,rw h,simpa!,
--   cases is_cau_geo_series x x1 (ε / abs a) (div_pos ε0 (abs_pos_of_ne_zero h)) with i hi,
--   existsi i,assume j ji,rw [series_mul_left,series_mul_left,←mul_sub,abs_mul,mul_comm,←lt_div_iff],
--   exact hi j ji,exact abs_pos_of_ne_zero h,
-- end

-- lemma is_cau_series_of_abv_le_cau {α : Type*} {β : Type*} [discrete_linear_ordered_field α] [ring β] {f : ℕ → β}
-- {g : ℕ → α} {abv : β → α} [is_absolute_value abv] (n : ℕ) : (∀ m, n ≤ m → abv (f m) ≤ g m) →
-- is_cau_seq abs (series g) → is_cau_seq abv (series f) := begin
--   assume hm hg ε ε0,cases hg (ε / 2) (div_pos ε0 (by norm_num)) with i hi,
--   existsi max n i,
--   assume j ji,
--   have hi₁ := hi j (le_trans (le_max_right n i) ji),
--   have hi₂ := hi (max n i) (le_max_right n i),
--   have sub_le := abs_sub_le (series g j) (series g i) (series g (max n i)),
--   have := add_lt_add hi₁ hi₂,rw abs_sub (series g (max n i)) at this,
--   have ε2 : ε / 2 + ε / 2 = ε,ring,
--   rw ε2 at this,
--   refine lt_of_le_of_lt _ this,
--   refine le_trans _ sub_le,
--   refine le_trans _ (le_abs_self _),
--   generalize hk : j - max n i = k,clear this ε2 hi₂ hi₁ hi ε0 ε hg sub_le,
--   rw nat.sub_eq_iff_eq_add ji at hk,rw hk, clear hk ji j,
--   induction k with k' hi,simp,rw abv_zero abv,
--   rw succ_add,unfold series,
--   rw [add_comm,add_sub_assoc],
--   refine le_trans (abv_add _ _ _) _,
--   rw [add_comm (series g (k' + max n i)),add_sub_assoc],
--   refine add_le_add _ _,
--   refine hm _ _,rw [←zero_add n,←succ_add],refine add_le_add _ _,exact zero_le _,
--   simp, exact le_max_left _ _,assumption,
-- end

-- -- The form of ratio test with  0 ≤ r < 1, and abv (f (succ m)) ≤ r * abv (f m) handled zero terms of series the best
-- lemma series_ratio_test {α : Type*} {β : Type*} [discrete_linear_ordered_field α] [ring β]
-- [archimedean α] {abv : β → α} [is_absolute_value abv] {f : ℕ → β} (n : ℕ) (r : α) :
-- 0 ≤ r → r < 1 → (∀ m, n ≤ m → abv (f (succ m)) ≤ r * abv (f m)) → is_cau_seq abv (series f)
--   := begin
--   assume r0 r1 h,
--   refine is_cau_series_of_abv_le_cau (succ n) _ (is_cau_geo_series_const (abv (f (succ n)) * pow r⁻¹ (succ n)) r _),
--   assume m mn,
--   generalize hk : m - (succ n) = k,rw nat.sub_eq_iff_eq_add mn at hk,
--   cases classical.em (r = 0) with r_zero r_pos,have m_pos := lt_of_lt_of_le (succ_pos n) mn,
--   have := pred_le_pred mn,simp at this,
--   have := h (pred m) this,simp[r_zero,succ_pred_eq_of_pos m_pos] at this,
--   refine le_trans this _,refine mul_nonneg _ _,refine mul_nonneg (abv_nonneg _ _) (pow_nonneg (inv_nonneg.mpr r0) _),exact pow_nonneg r0 _,
--   replace r_pos : 0 < r,cases lt_or_eq_of_le r0 with h h,exact h,exact absurd h.symm r_pos,
--   revert m n,
--   induction k with k' hi,assume m n h mn hk,
--   rw [hk,zero_add,mul_right_comm,←pow_inv _ _ (ne_of_lt r_pos).symm,←div_eq_mul_inv,mul_div_cancel],
--   exact (ne_of_lt (pow_pos r_pos _)).symm,
--   assume m n h mn hk,rw [hk,succ_add],
--   have kn : k' + (succ n) ≥ (succ n), rw ←zero_add (succ n),refine add_le_add _ _,exact zero_le _,simp,
--   replace hi := hi (k' + (succ n)) n h kn rfl,
--   rw [(by simp!;ring : pow r (succ (k' + succ n)) = pow r (k' + succ n) * r),←_root_.mul_assoc],
--   replace h := h (k' + succ n) (le_of_succ_le kn),rw mul_comm at h,
--   exact le_trans h (mul_le_mul_of_nonneg_right hi r0),
--   rwa abs_of_nonneg r0,
-- end

-- lemma series_cau_of_abv_cau {α : Type*} {β : Type*} [discrete_linear_ordered_field α] [ring β] {abv : β → α} {f : ℕ → β}
-- [is_absolute_value abv] : is_cau_seq abs (series (λ n, abv (f n))) → is_cau_seq abv (series f) :=
--    λ h, is_cau_series_of_abv_le_cau 0 (λ n h, le_refl _) h

-- -- I did not use the equivalent function on cauchy sequences as I do not have a proof
-- -- series (λ n, series (λ m, a m * b (n - m)) n) j) is a cauchy sequence. Using this lemma
-- -- and of_near, this can be proven to be a cauchy sequence
-- lemma series_cauchy_prod {α β : Type*} [discrete_linear_ordered_field α] [ring β] {a b : ℕ → β}
-- {abv : β → α} [is_absolute_value abv] : is_cau_seq abs (series (λ n, abv (a n))) → is_cau_seq abv (series b) →
-- ∀ ε : α, 0 < ε → ∃ i : ℕ, ∀ j ≥ i, abv (series a j * series b j - series (λ n,
-- series (λ m, a m * b (n - m)) n) j) < ε := begin
-- -- slightly adapted version of theorem 9.4.7 from "The Real Numbers and Real Analysis", Ethan D. Bloch
--   assume ha hb ε ε0,
--   cases cau_seq.bounded ⟨_, hb⟩ with Q hQ,simp at hQ,
--   cases cau_seq.bounded ⟨_, ha⟩ with P hP,simp at hP,
--   have P0 : 0 < P,exact lt_of_le_of_lt (abs_nonneg _) (hP 0),
--   have Pε0 := div_pos ε0 (mul_pos (show (2 : α) > 0, from by norm_num) P0),
--   cases cau_seq.cauchy₂ ⟨_, hb⟩ Pε0 with N hN,simp at hN,
--   have Qε0 := div_pos ε0 (mul_pos (show (4 : α) > 0, from by norm_num) (lt_of_le_of_lt (abv_nonneg _ _) (hQ 0))),
--   cases cau_seq.cauchy₂ ⟨_, ha⟩ Qε0 with M hM,simp at hM,
--   existsi 2 * (max N M + 1),
--   assume K hK,have := series_series_diag_flip (λ m n, a m * b n) K,simp at this,rw this,clear this,
--   have : (λ (i : ℕ), series (λ (k : ℕ), a i * b k) (K - i)) = (λ (i : ℕ), a i * series (λ (k : ℕ), b k) (K - i)) := by
--     {apply funext,assume i,rw series_mul_left},
--   rw this,clear this,simp,
--   have : series (λ (i : ℕ), a i * series b (K - i)) K = series (λ (i : ℕ), a i * (series b (K - i) - series b K))
--   K + series (λ i, a i * series b K) K,
--     {rw ←series_add,simp[(mul_add _ _ _).symm]},
--   rw this, clear this,
--   rw series_mul_series,simp,
--   rw abv_neg abv,
--   refine lt_of_le_of_lt (abv_series_le_series_abv _) _,
--   simp [abv_mul abv],
--   suffices : series (λ (i : ℕ), abv (a i) * abv (series b (K - i) + -series b K)) (max N M + 1) +
--   (series (λ (i : ℕ), abv (a i) * abv (series b (K - i) + -series b K)) K -series (λ (i : ℕ),
--   abv (a i) * abv (series b (K - i) + -series b K)) (max N M + 1)) < ε / (2 * P) * P + ε / (4 * Q) * (2 * Q),
--   { simp [(div_div_eq_div_mul _ _ _).symm] at this,
--     rwa[div_mul_cancel _ (ne_of_lt P0).symm,(by norm_num : (4 : α) = 2 * 2),←div_div_eq_div_mul,mul_comm (2 : α),←_root_.mul_assoc,
--     div_mul_cancel _ (ne_of_lt (lt_of_le_of_lt (abv_nonneg _ _) (hQ 0))).symm,div_mul_cancel,add_halves] at this,
--     norm_num},
--   refine add_lt_add _ _,
--   {have : series (λ (i : ℕ), abv (a i) * abv (series b (K - i) + -series b K)) (max N M + 1) ≤ series
--   (λ (i : ℕ), abv (a i) * (ε / (2 * P))) (max N M + 1) := by
--     {refine series_le_series _,assume m mJ,refine mul_le_mul_of_nonneg_left _ _,
--       {refine le_of_lt (hN (K - m) K _ _),{
--       refine nat.le_sub_left_of_add_le (le_trans _ hK),
--       rw[succ_mul,_root_.one_mul],
--       exact add_le_add mJ (le_trans (le_max_left _ _) (le_of_lt (lt_add_one _)))},
--       {refine le_trans _ hK,rw ←_root_.one_mul N,
--       refine mul_le_mul (by norm_num) (by rw _root_.one_mul;exact le_trans (le_max_left _ _)
--       (le_of_lt (lt_add_one _))) (zero_le _) (zero_le _)}},
--       exact abv_nonneg abv _},
--   refine lt_of_le_of_lt this _,
--   rw [series_mul_right,mul_comm],
--   specialize hP (max N M + 1),rwa abs_of_nonneg at hP,
--   exact (mul_lt_mul_left Pε0).mpr hP,
--   exact series_nonneg (λ x h, abv_nonneg abv _)},
--   {have hNMK : max N M + 1 < K := by
--     {refine lt_of_lt_of_le _ hK,
--     rw [succ_mul,_root_.one_mul,←add_zero (max N M + 1)],
--     refine add_lt_add_of_le_of_lt (le_refl _) _,rw add_zero,
--     refine add_pos_of_nonneg_of_pos (zero_le _) (by norm_num)},
--   rw series_sub_series _ hNMK,
--   have : series (λ (k : ℕ), abv (a (k + (max N M + 1 + 1))) * abv
--   (series b (K - (k + (max N M + 1 + 1))) + -series b K)) (K - (max N M + 1 + 1)) ≤
--   series (λ (k : ℕ), abv (a (k + (max N M + 1 + 1))) * (2 * Q)) (K - (max N M + 1 + 1)) := by
--     {refine series_le_series _,
--     assume m hm,
--     refine mul_le_mul_of_nonneg_left _ _,
--     {refine le_trans (abv_add abv _ _) _,
--     rw (by ring : 2 * Q = Q + Q),
--     refine add_le_add (le_of_lt (hQ _)) _,
--     rw abv_neg abv, exact le_of_lt (hQ _)},
--     exact abv_nonneg abv _},
--   refine lt_of_le_of_lt this _,
--   rw [series_mul_right],
--   refine (mul_lt_mul_right (mul_pos (by norm_num) (lt_of_le_of_lt (abv_nonneg abv _) (hQ 0)))).mpr _,
--   refine lt_of_le_of_lt (le_abs_self _) _,
--   rw[←@series_sub_series _ _ (λ k, abv (a k)) (max N M + 1) K hNMK],
--   refine hM _ _ _ (le_trans (le_max_right _ _) (le_of_lt (lt_add_one _))),
--   refine le_trans _ hK,
--   rw [succ_mul,_root_.one_mul,←add_zero M],
--   exact add_le_add (le_trans (le_max_right _ _) (le_of_lt (lt_add_one _))) (zero_le _)},
-- end