/-
Copyright (c) 2022 Jireh Loreaux. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jireh Loreaux

! This file was ported from Lean 3 source module analysis.normed_space.star.mul
! leanprover-community/mathlib commit b2ff9a3d7a15fd5b0f060b135421d6a89a999c2f
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Analysis.NormedSpace.Star.Basic
import Mathbin.Analysis.NormedSpace.OperatorNorm

/-! # The left-regular representation is an isometry for C⋆-algebras -/

open ContinuousLinearMap

-- mathport name: «expr ⋆»
local postfix:max "⋆" => star

variable (𝕜 : Type _) {E : Type _}

variable [DenselyNormedField 𝕜] [NonUnitalNormedRing E] [StarRing E] [CstarRing E]

variable [NormedSpace 𝕜 E] [IsScalarTower 𝕜 E E] [SMulCommClass 𝕜 E E] (a : E)

/-- In a C⋆-algebra `E`, either unital or non-unital, multiplication on the left by `a : E` has
norm equal to the norm of `a`. -/
@[simp]
theorem op_nnnorm_mul : ‖mul 𝕜 E a‖₊ = ‖a‖₊ :=
  by
  rw [← Sup_closed_unit_ball_eq_nnnorm]
  refine' csupₛ_eq_of_forall_le_of_forall_lt_exists_gt _ _ fun r hr => _
  · exact (metric.nonempty_closed_ball.mpr zero_le_one).image _
  · rintro - ⟨x, hx, rfl⟩
    exact
      ((mul 𝕜 E a).unit_le_op_norm x <| mem_closed_ball_zero_iff.mp hx).trans
        (op_norm_mul_apply_le 𝕜 E a)
  · have ha : 0 < ‖a‖₊ := zero_le'.trans_lt hr
    rw [← inv_inv ‖a‖₊, NNReal.lt_inv_iff_mul_lt (inv_ne_zero ha.ne')] at hr
    obtain ⟨k, hk₁, hk₂⟩ :=
      NormedField.exists_lt_nnnorm_lt 𝕜 (mul_lt_mul_of_pos_right hr <| inv_pos.2 ha)
    refine' ⟨_, ⟨k • star a, _, rfl⟩, _⟩
    ·
      simpa only [mem_closedBall_zero_iff, norm_smul, one_mul, norm_star] using
        (NNReal.le_inv_iff_mul_le ha.ne').1 (one_mul ‖a‖₊⁻¹ ▸ hk₂.le : ‖k‖₊ ≤ ‖a‖₊⁻¹)
    · simp only [map_smul, nnnorm_smul, mul_apply', mul_smul_comm, CstarRing.nnnorm_self_mul_star]
      rwa [← NNReal.div_lt_iff (mul_pos ha ha).ne', div_eq_mul_inv, mul_inv, ← mul_assoc]
#align op_nnnorm_mul op_nnnorm_mul

/-- In a C⋆-algebra `E`, either unital or non-unital, multiplication on the right by `a : E` has
norm eqaul to the norm of `a`. -/
@[simp]
theorem op_nnnorm_mul_flip : ‖(mul 𝕜 E).flip a‖₊ = ‖a‖₊ :=
  by
  rw [← Sup_unit_ball_eq_nnnorm, ← nnnorm_star, ← @op_nnnorm_mul 𝕜 E, ← Sup_unit_ball_eq_nnnorm]
  congr 1
  simp only [mul_apply', flip_apply]
  refine' Set.Subset.antisymm _ _ <;> rintro - ⟨b, hb, rfl⟩ <;>
    refine' ⟨star b, by simpa only [norm_star, mem_ball_zero_iff] using hb, _⟩
  · simp only [← star_mul, nnnorm_star]
  · simpa using (nnnorm_star (star b * a)).symm
#align op_nnnorm_mul_flip op_nnnorm_mul_flip

variable (E)

/-- In a C⋆-algebra `E`, either unital or non-unital, the left regular representation is an
isometry. -/
theorem mul_isometry : Isometry (mul 𝕜 E) :=
  AddMonoidHomClass.isometry_of_norm _ fun a => congr_arg coe <| op_nnnorm_mul 𝕜 a
#align mul_isometry mul_isometry

/-- In a C⋆-algebra `E`, either unital or non-unital, the right regular anti-representation is an
isometry. -/
theorem mul_flip_isometry : Isometry (mul 𝕜 E).flip :=
  AddMonoidHomClass.isometry_of_norm _ fun a => congr_arg coe <| op_nnnorm_mul_flip 𝕜 a
#align mul_flip_isometry mul_flip_isometry


/-
Copyright (c) Sidharth Hariharan. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kevin Buzzard, Sidharth Hariharan

! This file was ported from Lean 3 source module data.polynomial.partial_fractions
! leanprover-community/mathlib commit 6e70e0d419bf686784937d64ed4bfde866ff229e
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathlib.Data.Polynomial.Div
import Mathlib.Data.ZMod.Basic
import Mathlib.Logic.Function.Basic
import Mathlib.RingTheory.Localization.FractionRing
import Mathlib.Tactic.FieldSimp
import Mathlib.Tactic.LinearCombination

/-!

# Partial fractions

These results were formalised by the Xena Project, at the suggestion
of Patrick Massot.

# The main theorem

* `div_eq_quo_add_sum_rem_div`: General partial fraction decomposition theorem for polynomials over
  an integral domain R :
  If f, g₁, g₂, ..., gₙ ∈ R[X] and the gᵢs are all monic and pairwise coprime, then ∃ q, r₁, ..., rₙ
  ∈ R[X] such that f / g₁g₂...gₙ = q + r₁/g₁ + ... + rₙ/gₙ and for all i, deg(rᵢ) < deg(gᵢ).

* The result is formalized here in slightly more generality, using finsets. That is, if ι is an
  arbitrary index type, g denotes a map from ι to R[X], and if s is an arbitrary finite subset of ι,
  with g i monic for all i ∈ s and for all i,j ∈ s, i ≠ j → g i is coprime to g j, then we have
  ∃ q ∈ R[X] , r : ι → R[X] such that ∀ i ∈ s, deg(r i) < deg(g i) and
  f / ∏ g i = q + ∑ (r i) / (g i), where the product and sum are over s.

* The proof is done by proving the two-denominator case and then performing finset induction for an
  arbitrary (finite) number of denominators.

## Scope for Expansion

* Proving uniqueness of the decomposition

-/

variable (R : Type) [CommRing R] [IsDomain R]

open Polynomial

open Polynomial

variable (K : Type) [Field K] [Algebra R[X] K] [IsFractionRing R[X] K]

section TwoDenominators

--Porting note: added for scoped `Algebra.cast` instance
open algebraMap

/-- Let R be an integral domain and f, g₁, g₂ ∈ R[X]. Let g₁ and g₂ be monic and coprime.
Then, ∃ q, r₁, r₂ ∈ R[X] such that f / g₁g₂ = q + r₁/g₁ + r₂/g₂ and deg(r₁) < deg(g₁) and
deg(r₂) < deg(g₂).
-/
theorem div_eq_quo_add_rem_div_add_rem_div (f : R[X]) {g₁ g₂ : R[X]} (hg₁ : g₁.Monic)
    (hg₂ : g₂.Monic) (hcoprime : IsCoprime g₁ g₂) :
    ∃ q r₁ r₂ : R[X],
      r₁.degree < g₁.degree ∧
        r₂.degree < g₂.degree ∧ (f : K) / (↑g₁ * ↑g₂) = ↑q + ↑r₁ / ↑g₁ + ↑r₂ / ↑g₂ := by
  rcases hcoprime with ⟨c, d, hcd⟩
  refine'
    ⟨f * d /ₘ g₁ + f * c /ₘ g₂, f * d %ₘ g₁, f * c %ₘ g₂, degree_modByMonic_lt _ hg₁,
      degree_modByMonic_lt _ hg₂, _⟩
  have hg₁' : (↑g₁ : K) ≠ 0 := by
    norm_cast
    exact hg₁.ne_zero_of_ne zero_ne_one
  have hg₂' : (↑g₂ : K) ≠ 0 := by
    norm_cast
    exact hg₂.ne_zero_of_ne zero_ne_one
  have hfc := modByMonic_add_div (f * c) hg₂
  have hfd := modByMonic_add_div (f * d) hg₁
  field_simp
  norm_cast
  linear_combination -1 * f * hcd + -1 * g₁ * hfc + -1 * g₂ * hfd
#align div_eq_quo_add_rem_div_add_rem_div div_eq_quo_add_rem_div_add_rem_div

end TwoDenominators

section NDenominators

open BigOperators Classical

--Porting note: added for scoped `Algebra.cast` instance
open algebraMap

/-- Let R be an integral domain and f ∈ R[X]. Let s be a finite index set.
Then, a fraction of the form f / ∏ (g i) can be rewritten as q + ∑ (r i) / (g i), where
deg(r i) < deg(g i), provided that the g i are monic and pairwise coprime.
-/
theorem div_eq_quo_add_sum_rem_div (f : R[X]) {ι : Type _} {g : ι → R[X]} {s : Finset ι}
    (hg : ∀ i ∈ s, (g i).Monic) (hcop : Set.Pairwise ↑s fun i j => IsCoprime (g i) (g j)) :
    ∃ (q : R[X])(r : ι → R[X]),
      (∀ i ∈ s, (r i).degree < (g i).degree) ∧
        ((↑f : K) / ∏ i in s, ↑(g i)) = ↑q + ∑ i in s, (r i : K) / (g i : K) := by
  induction' s using Finset.induction_on with a b hab Hind f generalizing f
  · refine' ⟨f, fun _ : ι => (0 : R[X]), fun i => _, by simp⟩
    rintro ⟨⟩
  obtain ⟨q₀, r₁, r₂, hdeg₁, _, hf : (↑f : K) / _ = _⟩ :=
    div_eq_quo_add_rem_div_add_rem_div R K f
      (hg a (b.mem_insert_self a) : Monic (g a))
      (monic_prod_of_monic _ _ fun i hi => hg i (Finset.mem_insert_of_mem hi) :
        Monic (∏ i : ι in b, g i))
      (IsCoprime.prod_right fun i hi =>
        hcop (Finset.mem_coe.2 (b.mem_insert_self a))
          (Finset.mem_coe.2 (Finset.mem_insert_of_mem hi)) (by rintro rfl; exact hab hi))
  · obtain ⟨q, r, hrdeg, IH⟩ :=
      Hind _ (fun i hi => hg i (Finset.mem_insert_of_mem hi))
        (Set.Pairwise.mono (Finset.coe_subset.2 fun i hi => Finset.mem_insert_of_mem hi) hcop)
    refine ⟨q₀ + q, fun i => if i = a then r₁ else r i, ?_, ?_⟩
    · intro i
      dsimp only
      split_ifs with h1
      · cases h1
        intro
        exact hdeg₁
      · intro hi
        exact hrdeg i (Finset.mem_of_mem_insert_of_ne hi h1)
    norm_cast  at hf IH⊢
    rw [Finset.prod_insert hab, hf, IH, Finset.sum_insert hab, if_pos rfl]
    trans (↑(q₀ + q : R[X]) : K) + (↑r₁ / ↑(g a) + ∑ i : ι in b, (r i : K) / (g i : K))
    · push_cast
      ring
    congr 2
    refine' Finset.sum_congr rfl fun x hxb => _
    rw [if_neg]
    rintro rfl
    exact hab hxb
#align div_eq_quo_add_sum_rem_div div_eq_quo_add_sum_rem_div

end NDenominators


/-
Copyright (c) 2017 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl, Mario Carneiro, Yury Kudryashov

! This file was ported from Lean 3 source module measure_theory.measure.null_measurable
! leanprover-community/mathlib commit e4edb23029fff178210b9945dcb77d293f001e1c
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.MeasureTheory.Measure.AeDisjoint

/-!
# Null measurable sets and complete measures

## Main definitions

### Null measurable sets and functions

A set `s : set α` is called *null measurable* (`measure_theory.null_measurable_set`) if it satisfies
any of the following equivalent conditions:

* there exists a measurable set `t` such that `s =ᵐ[μ] t` (this is used as a definition);
* `measure_theory.to_measurable μ s =ᵐ[μ] s`;
* there exists a measurable subset `t ⊆ s` such that `t =ᵐ[μ] s` (in this case the latter equality
  means that `μ (s \ t) = 0`);
* `s` can be represented as a union of a measurable set and a set of measure zero;
* `s` can be represented as a difference of a measurable set and a set of measure zero.

Null measurable sets form a σ-algebra that is registered as a `measurable_space` instance on
`measure_theory.null_measurable_space α μ`. We also say that `f : α → β` is
`measure_theory.null_measurable` if the preimage of a measurable set is a null measurable set.
In other words, `f : α → β` is null measurable if it is measurable as a function
`measure_theory.null_measurable_space α μ → β`.

### Complete measures

We say that a measure `μ` is complete w.r.t. the `measurable_space α` σ-algebra (or the σ-algebra is
complete w.r.t measure `μ`) if every set of measure zero is measurable. In this case all null
measurable sets and functions are measurable.

For each measure `μ`, we define `measure_theory.measure.completion μ` to be the same measure
interpreted as a measure on `measure_theory.null_measurable_space α μ` and prove that this is a
complete measure.

## Implementation notes

We define `measure_theory.null_measurable_set` as `@measurable_set (null_measurable_space α μ) _` so
that theorems about `measurable_set`s like `measurable_set.union` can be applied to
`null_measurable_set`s. However, these lemmas output terms of the same form
`@measurable_set (null_measurable_space α μ) _ _`. While this is definitionally equal to the
expected output `null_measurable_set s μ`, it looks different and may be misleading. So we copy all
standard lemmas about measurable sets to the `measure_theory.null_measurable_set` namespace and fix
the output type.

## Tags

measurable, measure, null measurable, completion
-/

open Filter Set Encodable

variable {ι α β γ : Type _}

namespace MeasureTheory

/-- A type tag for `α` with `measurable_set` given by `null_measurable_set`. -/
@[nolint unused_arguments]
def NullMeasurableSpace (α : Type _) [MeasurableSpace α]
    (μ : Measure α := by exact MeasureTheory.MeasureSpace.volume) : Type _ :=
  α
#align measure_theory.null_measurable_space MeasureTheory.NullMeasurableSpace

section

variable {m0 : MeasurableSpace α} {μ : Measure α} {s t : Set α}

instance [h : Inhabited α] : Inhabited (NullMeasurableSpace α μ) :=
  h

instance [h : Subsingleton α] : Subsingleton (NullMeasurableSpace α μ) :=
  h

instance : MeasurableSpace (NullMeasurableSpace α μ)
    where
  MeasurableSet' s := ∃ t, MeasurableSet t ∧ s =ᵐ[μ] t
  measurable_set_empty := ⟨∅, MeasurableSet.empty, ae_eq_refl _⟩
  measurable_set_compl := fun s ⟨t, htm, hts⟩ => ⟨tᶜ, htm.compl, hts.compl⟩
  measurable_set_unionᵢ s hs := by
    choose t htm hts using hs
    exact ⟨⋃ i, t i, MeasurableSet.unionᵢ htm, EventuallyEq.countable_unionᵢ hts⟩

/-- A set is called `null_measurable_set` if it can be approximated by a measurable set up to
a set of null measure. -/
def NullMeasurableSet [MeasurableSpace α] (s : Set α)
    (μ : Measure α := by exact MeasureTheory.MeasureSpace.volume) : Prop :=
  @MeasurableSet (NullMeasurableSpace α μ) _ s
#align measure_theory.null_measurable_set MeasureTheory.NullMeasurableSet

@[simp]
theorem MeasurableSet.nullMeasurableSet (h : MeasurableSet s) : NullMeasurableSet s μ :=
  ⟨s, h, ae_eq_refl _⟩
#align measurable_set.null_measurable_set MeasurableSet.nullMeasurableSet

@[simp]
theorem nullMeasurableSetEmpty : NullMeasurableSet ∅ μ :=
  MeasurableSet.empty
#align measure_theory.null_measurable_set_empty MeasureTheory.nullMeasurableSetEmpty

@[simp]
theorem nullMeasurableSetUniv : NullMeasurableSet univ μ :=
  MeasurableSet.univ
#align measure_theory.null_measurable_set_univ MeasureTheory.nullMeasurableSetUniv

namespace NullMeasurableSet

theorem ofNull (h : μ s = 0) : NullMeasurableSet s μ :=
  ⟨∅, MeasurableSet.empty, ae_eq_empty.2 h⟩
#align measure_theory.null_measurable_set.of_null MeasureTheory.NullMeasurableSet.ofNull

theorem compl (h : NullMeasurableSet s μ) : NullMeasurableSet (sᶜ) μ :=
  h.compl
#align measure_theory.null_measurable_set.compl MeasureTheory.NullMeasurableSet.compl

theorem ofCompl (h : NullMeasurableSet (sᶜ) μ) : NullMeasurableSet s μ :=
  h.ofCompl
#align measure_theory.null_measurable_set.of_compl MeasureTheory.NullMeasurableSet.ofCompl

@[simp]
theorem compl_iff : NullMeasurableSet (sᶜ) μ ↔ NullMeasurableSet s μ :=
  MeasurableSet.compl_iff
#align measure_theory.null_measurable_set.compl_iff MeasureTheory.NullMeasurableSet.compl_iff

@[nontriviality]
theorem ofSubsingleton [Subsingleton α] : NullMeasurableSet s μ :=
  Subsingleton.measurableSet
#align measure_theory.null_measurable_set.of_subsingleton MeasureTheory.NullMeasurableSet.ofSubsingleton

protected theorem congr (hs : NullMeasurableSet s μ) (h : s =ᵐ[μ] t) : NullMeasurableSet t μ :=
  let ⟨s', hm, hs'⟩ := hs
  ⟨s', hm, h.symm.trans hs'⟩
#align measure_theory.null_measurable_set.congr MeasureTheory.NullMeasurableSet.congr

protected theorem union {ι : Sort _} [Countable ι] {s : ι → Set α}
    (h : ∀ i, NullMeasurableSet (s i) μ) : NullMeasurableSet (⋃ i, s i) μ :=
  MeasurableSet.unionᵢ h
#align measure_theory.null_measurable_set.Union MeasureTheory.NullMeasurableSet.union

protected theorem bUnionDecode₂ [Encodable ι] ⦃f : ι → Set α⦄ (h : ∀ i, NullMeasurableSet (f i) μ)
    (n : ℕ) : NullMeasurableSet (⋃ b ∈ Encodable.decode₂ ι n, f b) μ :=
  MeasurableSet.bunionᵢ_decode₂ h n
#align measure_theory.null_measurable_set.bUnion_decode₂ MeasureTheory.NullMeasurableSet.bUnionDecode₂

protected theorem bUnion {f : ι → Set α} {s : Set ι} (hs : s.Countable)
    (h : ∀ b ∈ s, NullMeasurableSet (f b) μ) : NullMeasurableSet (⋃ b ∈ s, f b) μ :=
  MeasurableSet.bunionᵢ hs h
#align measure_theory.null_measurable_set.bUnion MeasureTheory.NullMeasurableSet.bUnion

protected theorem sUnion {s : Set (Set α)} (hs : s.Countable) (h : ∀ t ∈ s, NullMeasurableSet t μ) :
    NullMeasurableSet (⋃₀ s) μ := by
  rw [sUnion_eq_bUnion]
  exact MeasurableSet.bunionᵢ hs h
#align measure_theory.null_measurable_set.sUnion MeasureTheory.NullMeasurableSet.sUnion

protected theorem inter {ι : Sort _} [Countable ι] {f : ι → Set α}
    (h : ∀ i, NullMeasurableSet (f i) μ) : NullMeasurableSet (⋂ i, f i) μ :=
  MeasurableSet.interᵢ h
#align measure_theory.null_measurable_set.Inter MeasureTheory.NullMeasurableSet.inter

protected theorem bInter {f : β → Set α} {s : Set β} (hs : s.Countable)
    (h : ∀ b ∈ s, NullMeasurableSet (f b) μ) : NullMeasurableSet (⋂ b ∈ s, f b) μ :=
  MeasurableSet.binterᵢ hs h
#align measure_theory.null_measurable_set.bInter MeasureTheory.NullMeasurableSet.bInter

protected theorem sInter {s : Set (Set α)} (hs : s.Countable) (h : ∀ t ∈ s, NullMeasurableSet t μ) :
    NullMeasurableSet (⋂₀ s) μ :=
  MeasurableSet.interₛ hs h
#align measure_theory.null_measurable_set.sInter MeasureTheory.NullMeasurableSet.sInter

/- warning: measure_theory.null_measurable_set.union clashes with measure_theory.null_measurable_set.Union -> MeasureTheory.NullMeasurableSet.union
warning: measure_theory.null_measurable_set.union -> MeasureTheory.NullMeasurableSet.union is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u_2}} {m0 : MeasurableSpace.{u_2} α} {μ : MeasureTheory.Measure.{u_2} α m0} {s : Set.{u_2} α} {t : Set.{u_2} α}, (MeasureTheory.NullMeasurableSet.{u_2} α m0 s μ) -> (MeasureTheory.NullMeasurableSet.{u_2} α m0 t μ) -> (MeasureTheory.NullMeasurableSet.{u_2} α m0 (Union.union.{u_2} (Set.{u_2} α) (Set.hasUnion.{u_2} α) s t) μ)
but is expected to have type
  PUnit.{0}
Case conversion may be inaccurate. Consider using '#align measure_theory.null_measurable_set.union MeasureTheory.NullMeasurableSet.unionₓ'. -/
@[simp]
protected theorem union (hs : NullMeasurableSet s μ) (ht : NullMeasurableSet t μ) :
    NullMeasurableSet (s ∪ t) μ :=
  hs.union ht
#align measure_theory.null_measurable_set.union MeasureTheory.NullMeasurableSet.union

protected theorem unionNull (hs : NullMeasurableSet s μ) (ht : μ t = 0) :
    NullMeasurableSet (s ∪ t) μ :=
  hs.union (ofNull ht)
#align measure_theory.null_measurable_set.union_null MeasureTheory.NullMeasurableSet.unionNull

/- warning: measure_theory.null_measurable_set.inter clashes with measure_theory.null_measurable_set.Inter -> MeasureTheory.NullMeasurableSet.inter
warning: measure_theory.null_measurable_set.inter -> MeasureTheory.NullMeasurableSet.inter is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u_2}} {m0 : MeasurableSpace.{u_2} α} {μ : MeasureTheory.Measure.{u_2} α m0} {s : Set.{u_2} α} {t : Set.{u_2} α}, (MeasureTheory.NullMeasurableSet.{u_2} α m0 s μ) -> (MeasureTheory.NullMeasurableSet.{u_2} α m0 t μ) -> (MeasureTheory.NullMeasurableSet.{u_2} α m0 (Inter.inter.{u_2} (Set.{u_2} α) (Set.hasInter.{u_2} α) s t) μ)
but is expected to have type
  PUnit.{0}
Case conversion may be inaccurate. Consider using '#align measure_theory.null_measurable_set.inter MeasureTheory.NullMeasurableSet.interₓ'. -/
@[simp]
protected theorem inter (hs : NullMeasurableSet s μ) (ht : NullMeasurableSet t μ) :
    NullMeasurableSet (s ∩ t) μ :=
  hs.inter ht
#align measure_theory.null_measurable_set.inter MeasureTheory.NullMeasurableSet.inter

@[simp]
protected theorem diff (hs : NullMeasurableSet s μ) (ht : NullMeasurableSet t μ) :
    NullMeasurableSet (s \ t) μ :=
  hs.diffₓ ht
#align measure_theory.null_measurable_set.diff MeasureTheory.NullMeasurableSet.diff

@[simp]
protected theorem disjointed {f : ℕ → Set α} (h : ∀ i, NullMeasurableSet (f i) μ) (n) :
    NullMeasurableSet (disjointed f n) μ :=
  MeasurableSet.disjointed h n
#align measure_theory.null_measurable_set.disjointed MeasureTheory.NullMeasurableSet.disjointed

@[simp]
protected theorem const (p : Prop) : NullMeasurableSet { a : α | p } μ :=
  MeasurableSet.const p
#align measure_theory.null_measurable_set.const MeasureTheory.NullMeasurableSet.const

instance [MeasurableSingletonClass α] : MeasurableSingletonClass (NullMeasurableSpace α μ) :=
  ⟨fun x => (@measurableSet_singleton α _ _ x).NullMeasurableSet⟩

protected theorem insert [MeasurableSingletonClass (NullMeasurableSpace α μ)]
    (hs : NullMeasurableSet s μ) (a : α) : NullMeasurableSet (insert a s) μ :=
  hs.insert a
#align measure_theory.null_measurable_set.insert MeasureTheory.NullMeasurableSet.insert

/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (t «expr ⊇ » s) -/
theorem exists_measurable_superset_ae_eq (h : NullMeasurableSet s μ) :
    ∃ (t : _)(_ : t ⊇ s), MeasurableSet t ∧ t =ᵐ[μ] s :=
  by
  rcases h with ⟨t, htm, hst⟩
  refine' ⟨t ∪ to_measurable μ (s \ t), _, htm.union (measurable_set_to_measurable _ _), _⟩
  · exact diff_subset_iff.1 (subset_to_measurable _ _)
  · have : to_measurable μ (s \ t) =ᵐ[μ] (∅ : Set α) := by simp [ae_le_set.1 hst.le]
    simpa only [union_empty] using hst.symm.union this
#align measure_theory.null_measurable_set.exists_measurable_superset_ae_eq MeasureTheory.NullMeasurableSet.exists_measurable_superset_ae_eq

theorem toMeasurable_ae_eq (h : NullMeasurableSet s μ) : toMeasurable μ s =ᵐ[μ] s :=
  by
  rw [to_measurable, dif_pos]
  exact h.exists_measurable_superset_ae_eq.some_spec.snd.2
#align measure_theory.null_measurable_set.to_measurable_ae_eq MeasureTheory.NullMeasurableSet.toMeasurable_ae_eq

theorem compl_toMeasurable_compl_ae_eq (h : NullMeasurableSet s μ) : toMeasurable μ (sᶜ)ᶜ =ᵐ[μ] s :=
  by simpa only [compl_compl] using h.compl.to_measurable_ae_eq.compl
#align measure_theory.null_measurable_set.compl_to_measurable_compl_ae_eq MeasureTheory.NullMeasurableSet.compl_toMeasurable_compl_ae_eq

/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (t «expr ⊆ » s) -/
theorem exists_measurable_subset_ae_eq (h : NullMeasurableSet s μ) :
    ∃ (t : _)(_ : t ⊆ s), MeasurableSet t ∧ t =ᵐ[μ] s :=
  ⟨toMeasurable μ (sᶜ)ᶜ, compl_subset_comm.2 <| subset_toMeasurable _ _,
    (measurableSet_toMeasurable _ _).compl, h.compl_toMeasurable_compl_ae_eq⟩
#align measure_theory.null_measurable_set.exists_measurable_subset_ae_eq MeasureTheory.NullMeasurableSet.exists_measurable_subset_ae_eq

end NullMeasurableSet

/-- If `sᵢ` is a countable family of (null) measurable pairwise `μ`-a.e. disjoint sets, then there
exists a subordinate family `tᵢ ⊆ sᵢ` of measurable pairwise disjoint sets such that
`tᵢ =ᵐ[μ] sᵢ`. -/
theorem exists_subordinate_pairwise_disjoint [Countable ι] {s : ι → Set α}
    (h : ∀ i, NullMeasurableSet (s i) μ) (hd : Pairwise (AeDisjoint μ on s)) :
    ∃ t : ι → Set α,
      (∀ i, t i ⊆ s i) ∧
        (∀ i, s i =ᵐ[μ] t i) ∧ (∀ i, MeasurableSet (t i)) ∧ Pairwise (Disjoint on t) :=
  by
  choose t ht_sub htm ht_eq using fun i => (h i).exists_measurable_subset_ae_eq
  rcases exists_null_pairwise_disjoint_diff hd with ⟨u, hum, hu₀, hud⟩
  exact
    ⟨fun i => t i \ u i, fun i => (diff_subset _ _).trans (ht_sub _), fun i =>
      (ht_eq _).symm.trans (diff_null_ae_eq_self (hu₀ i)).symm, fun i => (htm i).diffₓ (hum i),
      hud.mono fun i j h =>
        h.mono (diff_subset_diff_left (ht_sub i)) (diff_subset_diff_left (ht_sub j))⟩
#align measure_theory.exists_subordinate_pairwise_disjoint MeasureTheory.exists_subordinate_pairwise_disjoint

theorem measure_unionᵢ {m0 : MeasurableSpace α} {μ : Measure α} [Countable ι] {f : ι → Set α}
    (hn : Pairwise (Disjoint on f)) (h : ∀ i, MeasurableSet (f i)) : μ (⋃ i, f i) = ∑' i, μ (f i) :=
  by
  rw [measure_eq_extend (MeasurableSet.unionᵢ h),
    extend_Union MeasurableSet.empty _ MeasurableSet.unionᵢ _ hn h]
  · simp [measure_eq_extend, h]
  · exact μ.empty
  · exact μ.m_Union
#align measure_theory.measure_Union MeasureTheory.measure_unionᵢ

theorem measure_Union₀ [Countable ι] {f : ι → Set α} (hd : Pairwise (AeDisjoint μ on f))
    (h : ∀ i, NullMeasurableSet (f i) μ) : μ (⋃ i, f i) = ∑' i, μ (f i) :=
  by
  rcases exists_subordinate_pairwise_disjoint h hd with ⟨t, ht_sub, ht_eq, htm, htd⟩
  calc
    μ (⋃ i, f i) = μ (⋃ i, t i) := measure_congr (EventuallyEq.countable_unionᵢ ht_eq)
    _ = ∑' i, μ (t i) := (measure_Union htd htm)
    _ = ∑' i, μ (f i) := tsum_congr fun i => measure_congr (ht_eq _).symm

#align measure_theory.measure_Union₀ MeasureTheory.measure_Union₀

theorem measure_union₀_aux (hs : NullMeasurableSet s μ) (ht : NullMeasurableSet t μ)
    (hd : AeDisjoint μ s t) : μ (s ∪ t) = μ s + μ t :=
  by
  rw [union_eq_Union, measure_Union₀, tsum_fintype, Fintype.sum_bool, cond, cond]
  exacts[(pairwise_on_bool ae_disjoint.symmetric).2 hd, fun b => Bool.casesOn b ht hs]
#align measure_theory.measure_union₀_aux MeasureTheory.measure_union₀_aux

/-- A null measurable set `t` is Carathéodory measurable: for any `s`, we have
`μ (s ∩ t) + μ (s \ t) = μ s`. -/
theorem measure_inter_add_diff₀ (s : Set α) (ht : NullMeasurableSet t μ) :
    μ (s ∩ t) + μ (s \ t) = μ s := by
  refine' le_antisymm _ _
  · rcases exists_measurable_superset μ s with ⟨s', hsub, hs'm, hs'⟩
    replace hs'm : null_measurable_set s' μ := hs'm.null_measurable_set
    calc
      μ (s ∩ t) + μ (s \ t) ≤ μ (s' ∩ t) + μ (s' \ t) :=
        add_le_add (measure_mono <| inter_subset_inter_left _ hsub)
          (measure_mono <| diff_subset_diff_left hsub)
      _ = μ (s' ∩ t ∪ s' \ t) :=
        (measure_union₀_aux (hs'm.inter ht) (hs'm.diff ht) <|
            (@disjoint_inf_sdiff _ s' t _).AeDisjoint).symm
      _ = μ s' := (congr_arg μ (inter_union_diff _ _))
      _ = μ s := hs'

  ·
    calc
      μ s = μ (s ∩ t ∪ s \ t) := by rw [inter_union_diff]
      _ ≤ μ (s ∩ t) + μ (s \ t) := measure_union_le _ _

#align measure_theory.measure_inter_add_diff₀ MeasureTheory.measure_inter_add_diff₀

theorem measure_union_add_inter₀ (s : Set α) (ht : NullMeasurableSet t μ) :
    μ (s ∪ t) + μ (s ∩ t) = μ s + μ t := by
  rw [← measure_inter_add_diff₀ (s ∪ t) ht, union_inter_cancel_right, union_diff_right, ←
    measure_inter_add_diff₀ s ht, add_comm, ← add_assoc, add_right_comm]
#align measure_theory.measure_union_add_inter₀ MeasureTheory.measure_union_add_inter₀

theorem measure_union_add_inter₀' (hs : NullMeasurableSet s μ) (t : Set α) :
    μ (s ∪ t) + μ (s ∩ t) = μ s + μ t := by
  rw [union_comm, inter_comm, measure_union_add_inter₀ t hs, add_comm]
#align measure_theory.measure_union_add_inter₀' MeasureTheory.measure_union_add_inter₀'

theorem measure_union₀ (ht : NullMeasurableSet t μ) (hd : AeDisjoint μ s t) :
    μ (s ∪ t) = μ s + μ t := by rw [← measure_union_add_inter₀ s ht, hd.eq, add_zero]
#align measure_theory.measure_union₀ MeasureTheory.measure_union₀

theorem measure_union₀' (hs : NullMeasurableSet s μ) (hd : AeDisjoint μ s t) :
    μ (s ∪ t) = μ s + μ t := by rw [union_comm, measure_union₀ hs hd.symm, add_comm]
#align measure_theory.measure_union₀' MeasureTheory.measure_union₀'

theorem measure_add_measure_compl₀ {s : Set α} (hs : NullMeasurableSet s μ) :
    μ s + μ (sᶜ) = μ univ := by rw [← measure_union₀' hs ae_disjoint_compl_right, union_compl_self]
#align measure_theory.measure_add_measure_compl₀ MeasureTheory.measure_add_measure_compl₀

section MeasurableSingletonClass

variable [MeasurableSingletonClass (NullMeasurableSpace α μ)]

theorem nullMeasurableSetSingleton (x : α) : NullMeasurableSet {x} μ :=
  measurableSet_singleton x
#align measure_theory.null_measurable_set_singleton MeasureTheory.nullMeasurableSetSingleton

@[simp]
theorem nullMeasurableSet_insert {a : α} {s : Set α} :
    NullMeasurableSet (insert a s) μ ↔ NullMeasurableSet s μ :=
  measurableSet_insert
#align measure_theory.null_measurable_set_insert MeasureTheory.nullMeasurableSet_insert

theorem nullMeasurableSetEq {a : α} : NullMeasurableSet { x | x = a } μ :=
  nullMeasurableSetSingleton a
#align measure_theory.null_measurable_set_eq MeasureTheory.nullMeasurableSetEq

protected theorem Set.Finite.nullMeasurableSet (hs : s.Finite) : NullMeasurableSet s μ :=
  Finite.measurableSet hs
#align set.finite.null_measurable_set Set.Finite.nullMeasurableSet

protected theorem Finset.nullMeasurableSet (s : Finset α) : NullMeasurableSet (↑s) μ :=
  Finset.measurableSet s
#align finset.null_measurable_set Finset.nullMeasurableSet

end MeasurableSingletonClass

theorem Set.Finite.nullMeasurableSetBUnion {f : ι → Set α} {s : Set ι} (hs : s.Finite)
    (h : ∀ b ∈ s, NullMeasurableSet (f b) μ) : NullMeasurableSet (⋃ b ∈ s, f b) μ :=
  Finite.measurableSet_bunionᵢ hs h
#align set.finite.null_measurable_set_bUnion Set.Finite.nullMeasurableSetBUnion

theorem Finset.nullMeasurableSetBUnion {f : ι → Set α} (s : Finset ι)
    (h : ∀ b ∈ s, NullMeasurableSet (f b) μ) : NullMeasurableSet (⋃ b ∈ s, f b) μ :=
  Finset.measurableSet_bunionᵢ s h
#align finset.null_measurable_set_bUnion Finset.nullMeasurableSetBUnion

theorem Set.Finite.nullMeasurableSetSUnion {s : Set (Set α)} (hs : s.Finite)
    (h : ∀ t ∈ s, NullMeasurableSet t μ) : NullMeasurableSet (⋃₀ s) μ :=
  Finite.measurableSet_unionₛ hs h
#align set.finite.null_measurable_set_sUnion Set.Finite.nullMeasurableSetSUnion

theorem Set.Finite.nullMeasurableSetBInter {f : ι → Set α} {s : Set ι} (hs : s.Finite)
    (h : ∀ b ∈ s, NullMeasurableSet (f b) μ) : NullMeasurableSet (⋂ b ∈ s, f b) μ :=
  Finite.measurableSet_binterᵢ hs h
#align set.finite.null_measurable_set_bInter Set.Finite.nullMeasurableSetBInter

theorem Finset.nullMeasurableSetBInter {f : ι → Set α} (s : Finset ι)
    (h : ∀ b ∈ s, NullMeasurableSet (f b) μ) : NullMeasurableSet (⋂ b ∈ s, f b) μ :=
  s.finite_toSet.nullMeasurableSetBInter h
#align finset.null_measurable_set_bInter Finset.nullMeasurableSetBInter

theorem Set.Finite.nullMeasurableSetSInter {s : Set (Set α)} (hs : s.Finite)
    (h : ∀ t ∈ s, NullMeasurableSet t μ) : NullMeasurableSet (⋂₀ s) μ :=
  NullMeasurableSet.sInter hs.Countable h
#align set.finite.null_measurable_set_sInter Set.Finite.nullMeasurableSetSInter

theorem nullMeasurableSetToMeasurable : NullMeasurableSet (toMeasurable μ s) μ :=
  (measurableSet_toMeasurable _ _).NullMeasurableSet
#align measure_theory.null_measurable_set_to_measurable MeasureTheory.nullMeasurableSetToMeasurable

end

section NullMeasurable

variable [MeasurableSpace α] [MeasurableSpace β] [MeasurableSpace γ] {f : α → β} {μ : Measure α}

/-- A function `f : α → β` is null measurable if the preimage of a measurable set is a null
measurable set. -/
def NullMeasurable (f : α → β) (μ : Measure α := by exact MeasureTheory.MeasureSpace.volume) :
    Prop :=
  ∀ ⦃s : Set β⦄, MeasurableSet s → NullMeasurableSet (f ⁻¹' s) μ
#align measure_theory.null_measurable MeasureTheory.NullMeasurable

protected theorem Measurable.nullMeasurable (h : Measurable f) : NullMeasurable f μ := fun s hs =>
  (h hs).NullMeasurableSet
#align measurable.null_measurable Measurable.nullMeasurable

protected theorem NullMeasurable.measurable' (h : NullMeasurable f μ) :
    @Measurable (NullMeasurableSpace α μ) β _ _ f :=
  h
#align measure_theory.null_measurable.measurable' MeasureTheory.NullMeasurable.measurable'

theorem Measurable.compNullMeasurable {g : β → γ} (hg : Measurable g) (hf : NullMeasurable f μ) :
    NullMeasurable (g ∘ f) μ :=
  hg.comp hf
#align measure_theory.measurable.comp_null_measurable MeasureTheory.Measurable.compNullMeasurable

theorem NullMeasurable.congr {g : α → β} (hf : NullMeasurable f μ) (hg : f =ᵐ[μ] g) :
    NullMeasurable g μ := fun s hs =>
  (hf hs).congr <| eventuallyEq_set.2 <| hg.mono fun x hx => by rw [mem_preimage, mem_preimage, hx]
#align measure_theory.null_measurable.congr MeasureTheory.NullMeasurable.congr

end NullMeasurable

section IsComplete

/-- A measure is complete if every null set is also measurable.
  A null set is a subset of a measurable set with measure `0`.
  Since every measure is defined as a special case of an outer measure, we can more simply state
  that a set `s` is null if `μ s = 0`. -/
class Measure.IsComplete {_ : MeasurableSpace α} (μ : Measure α) : Prop where
  out' : ∀ s, μ s = 0 → MeasurableSet s
#align measure_theory.measure.is_complete MeasureTheory.Measure.IsComplete

variable {m0 : MeasurableSpace α} {μ : Measure α} {s t : Set α}

theorem Measure.isComplete_iff : μ.IsComplete ↔ ∀ s, μ s = 0 → MeasurableSet s :=
  ⟨fun h => h.1, fun h => ⟨h⟩⟩
#align measure_theory.measure.is_complete_iff MeasureTheory.Measure.isComplete_iff

theorem Measure.IsComplete.out (h : μ.IsComplete) : ∀ s, μ s = 0 → MeasurableSet s :=
  h.1
#align measure_theory.measure.is_complete.out MeasureTheory.Measure.IsComplete.out

theorem measurableSet_of_null [μ.IsComplete] (hs : μ s = 0) : MeasurableSet s :=
  MeasureTheory.Measure.IsComplete.out' s hs
#align measure_theory.measurable_set_of_null MeasureTheory.measurableSet_of_null

theorem NullMeasurableSet.measurable_of_complete (hs : NullMeasurableSet s μ) [μ.IsComplete] :
    MeasurableSet s :=
  diff_diff_cancel_left (subset_toMeasurable μ s) ▸
    (measurableSet_toMeasurable _ _).diffₓ
      (measurableSet_of_null (ae_le_set.1 hs.toMeasurable_ae_eq.le))
#align measure_theory.null_measurable_set.measurable_of_complete MeasureTheory.NullMeasurableSet.measurable_of_complete

theorem NullMeasurable.measurable_of_complete [μ.IsComplete] {m1 : MeasurableSpace β} {f : α → β}
    (hf : NullMeasurable f μ) : Measurable f := fun s hs => (hf hs).measurable_of_complete
#align measure_theory.null_measurable.measurable_of_complete MeasureTheory.NullMeasurable.measurable_of_complete

theorem Measurable.congr_ae {α β} [MeasurableSpace α] [MeasurableSpace β] {μ : Measure α}
    [hμ : μ.IsComplete] {f g : α → β} (hf : Measurable f) (hfg : f =ᵐ[μ] g) : Measurable g :=
  (hf.NullMeasurable.congr hfg).measurable_of_complete
#align measurable.congr_ae Measurable.congr_ae

namespace Measure

/-- Given a measure we can complete it to a (complete) measure on all null measurable sets. -/
def completion {_ : MeasurableSpace α} (μ : Measure α) :
    @MeasureTheory.Measure (NullMeasurableSpace α μ) _
    where
  toOuterMeasure := μ.toOuterMeasure
  m_unionᵢ s hs hd := measure_Union₀ (hd.mono fun i j h => h.AeDisjoint) hs
  trimmed := by
    refine' le_antisymm (fun s => _) (outer_measure.le_trim _)
    rw [outer_measure.trim_eq_infi]; simp only [to_outer_measure_apply]
    refine' (infᵢ₂_mono _).trans_eq (measure_eq_infi _).symm
    exact fun t ht => infᵢ_mono' fun h => ⟨h.NullMeasurableSet, le_rfl⟩
#align measure_theory.measure.completion MeasureTheory.Measure.completion

instance completion.isComplete {m : MeasurableSpace α} (μ : Measure α) : μ.Completion.IsComplete :=
  ⟨fun z hz => NullMeasurableSet.ofNull hz⟩
#align measure_theory.measure.completion.is_complete MeasureTheory.Measure.completion.isComplete

@[simp]
theorem coe_completion {_ : MeasurableSpace α} (μ : Measure α) : ⇑μ.Completion = μ :=
  rfl
#align measure_theory.measure.coe_completion MeasureTheory.Measure.coe_completion

theorem completion_apply {_ : MeasurableSpace α} (μ : Measure α) (s : Set α) :
    μ.Completion s = μ s :=
  rfl
#align measure_theory.measure.completion_apply MeasureTheory.Measure.completion_apply

end Measure

end IsComplete

end MeasureTheory


lemma succ_add (a b : mynat) : succ a + b = succ (a + b) :=
begin
induction b with c hc,
rw add_zero,
rw add_zero,
refl,
rw add_succ,
rw add_succ,
rw hc,
refl,
end


import algebra.category.Module.basic
import .lattices

variables (R : Type) [ring R] {M : Module R}

def is_minimal {α : Type} [lattice.bounded_lattice α] (x : α) := x ≠ ⊥ ∧ ∀ y, y < x → y = ⊥

def inf_with_minimal_bot_or_idem {α : Type} [lattice.bounded_lattice α] (x y : α) : is_minimal x → (x ⊓ y = ⊥ ∨ x ⊓ y = x) :=
begin
  intros,
  cases lt_or_eq_of_le (@lattice.inf_le_left _ _ x y),
  exact or.inl (a.elim_right _ h),
  finish
end

def is_simple (N : Module R) := is_minimal (⊤ : submodule R N)

lemma submodule_of_bot_is_bot : ∀ (A : submodule R (⊥ : submodule R M)), A = ⊥ :=
begin
  intros,
  apply submodule.ext,
  intros,
  split,
    have q : (x : (⊥ : submodule R M)) = 0 := begin
      have r := subtype.mem x,
      have q := set.mem_singleton_iff.elim_left r,
      apply subtype.ext.elim_right,
      finish
    end,
    finish,
  intro,
  have q := set.eq_of_mem_singleton a,
  rw q,
  finish
end

lemma simple_is_minimal (N : submodule R M) : is_simple R N → is_minimal N :=
begin
  intros,
  dunfold is_minimal,
  split,
    have h : N = ⊥ → (⊤ : submodule R N) = ⊥ := begin
      intro,
      have i := submodule_of_bot_is_bot R (⊤ : submodule R (⊥ : submodule R M)),
      finish
    end,
    intro,
    apply a.elim_left,
    finish,
  intros,
  let f := submodule.map_subtype.order_iso N,
  have t := a.elim_right (f.symm ⟨y, le_of_lt a_1 ⟩),
  have v := @order_iso.ord _ _ _ _ f.symm ⟨y, le_of_lt a_1⟩ ⟨N, le_of_eq rfl ⟩ ,
  have w := order_isom_preserves_lt (⟨y, le_of_lt a_1 ⟩: {p // p≤ N}) (⟨N, le_of_eq rfl⟩ : {p // p≤ N}) f.symm a_1,
  have z : ⊤ = (⟨N , le_of_eq rfl⟩ : {p // p ≤ N}) := rfl,
  have v : (order_iso.symm f) ⟨y, le_of_lt a_1 ⟩ < ⊤ :=
  begin
    rw (order_isom_preserves_top (f.symm)).symm,
    apply order_isom_preserves_lt (⟨y, _⟩ : {p //p ≤ N}) ⊤ (f.symm),
    finish
  end,
  have q : (order_iso.symm f) ⟨y, le_of_lt a_1 ⟩ = ⊥ := a.elim_right _ v,
  have q' : (⟨y, le_of_lt a_1 ⟩ : {p // p ≤ N}) = ⊥ := begin
    rw (order_iso.apply_symm_apply f (⊥ : {p // p ≤ N})).symm,
    rw order_isom_preserves_bot f.symm,
    rw (order_iso.apply_symm_apply f (⟨y, _⟩  : {p // p ≤ N})).symm,
    rw q
  end,
  exact subtype.ext.elim_left q'
end

variables (S₁ S₂ : submodule R M)

lemma intersection_with_simple_is_whole_or_trivial :
 is_simple R S₁ →
 S₁ ⊓ S₂ = ⊥ ∨ (S₁ ⊓ S₂ : submodule R M) = S₁ :=
begin
  intros,
  apply inf_with_minimal_bot_or_idem,
  exact @simple_is_minimal R _ M S₁ a
end

lemma intersection_with_simple_is_simple_or_trivial :
 is_simple R S₁ →
 S₁ ⊓ S₂ = ⊥ ∨ is_simple R (S₁ ⊓ S₂ : submodule R M) :=
begin
  intros,
  cases intersection_with_simple_is_whole_or_trivial _ _ _ a,
    finish,
  apply or.inr,
  rw h,
  finish
end


-- Representación decimal
-- ======================

import data.nat.digits
import data.list.range

lemma list.map_with_index_core_eq_1
  {α β : Type*}
  (l : list α)
  (f : ℕ → α → β) (n : ℕ)
  : l.map_with_index_core f n = l.map_with_index (λ i a, f (i + n) a) :=
begin
  induction l with hd tl hl generalizing f n,
  { simp [list.map_with_index, list.map_with_index_core] },
  { rw [list.map_with_index],
    simp [list.map_with_index_core, hl, add_left_comm, add_assoc, add_comm] }
end

@[simp]
lemma list.map_uncurry_zip_eq_zip_with_1
  {α β γ : Type*}
  (f : α → β → γ)
  (l : list α)
  (l' : list β)
  : list.map (function.uncurry f) (l.zip l') = list.zip_with f l l' :=
begin
  induction l with hd tl hl generalizing l',
  { simp },
  { cases l' with hd' tl',
    { simp },
    { simp [hl] } }
end

lemma list.zip_with_map_left_1
  {α β γ δ : Type*}
  (f : α → β → γ)
  (g : δ → α)
  (l : list δ)
  (l' : list β)
  : list.zip_with f (l.map g) l' = list.zip_with (f ∘ g) l l' :=
begin
  induction l with hd tl hl generalizing l',
  { simp },
  { cases l' with hd' tl',
    { simp },
    { simp [hl] } }
end

lemma list.zip_with_map_right_1
  {α β γ δ : Type*}
  (f : α → β → γ)
  (l : list α)
  (g : δ → β)
  (l' : list δ)
  : list.zip_with f l (l'.map g) = list.zip_with (λ x, f x ∘ g) l l' :=
begin
  induction l with hd tl hl generalizing l',
  { simp },
  { cases l' with hd' tl',
    { simp },
    { simp [hl] } }
end

lemma list.map_with_index_eq_enum_map_uncurry
  {α β : Type*}
  (l : list α)
  (f : ℕ → α → β)
  : l.map_with_index f = l.enum.map (function.uncurry f) :=
begin
  induction l with hd tl hl generalizing f,
  { simp [list.map_with_index, list.map_with_index_core, list.enum_eq_zip_range] },
  { rw [list.map_with_index, list.map_with_index_core, list.map_with_index_core_eq_1, hl],
    simp [list.enum_eq_zip_range, list.range_succ_eq_map, list.zip_with_map_left_1] }
end

@[simp]
lemma list.sum_zip_with_distrib_left_1
  {α β : Type*}
  (f : α → β → ℕ)
  (n : ℕ)
  (l : list α)
  (l' : list β)
  : (list.zip_with (λ x y, n * f x y) l l').sum = n * (l.zip_with f l').sum :=
begin
  induction l with hd tl hl generalizing f n l',
  { simp },
  { cases l' with hd' tl',
    { simp, },
    { simp [hl, mul_add] } }
end

lemma aux
  (b : ℕ)
  (l : list ℕ)
  : (list.zip_with ((λ (i a : ℕ), a * b ^ i) ∘ nat.succ) (list.range l.length) l).sum =
     b * (list.zip_with (λ i a, a * b ^ i) (list.range l.length) l).sum :=
begin
  suffices : list.zip_with (((λ (i a : ℕ), a * b ^ i) ∘ nat.succ)) (list.range l.length) l =
      list.zip_with (λ i a, b * (a * b ^ i)) (list.range l.length) l,
    { simp [this] },
  congr,
  ext,
  simp [pow_succ],
  ring
end

lemma mwe
  (b n: ℕ)
  : list.sum ((nat.digits b n).map_with_index (λ i a, a * b ^ i)) = n :=
begin
  conv {
      to_rhs,
      rw ← nat.of_digits_digits b n,
    },
  rw [list.map_with_index_eq_enum_map_uncurry, list.enum_eq_zip_range,
      list.map_uncurry_zip_eq_zip_with_1, nat.of_digits_eq_foldr b],
  induction b.digits n with hd tl hl,
  { simp },
  { simp [list.range_succ_eq_map, list.zip_with_map_left_1, aux, hl] }
end

-- Referencia
-- ==========

-- Yakov Pechersky "How to work on base representations and lists?"
-- https://bit.ly/3r8RPCj


/-
Copyright (c) 2017 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl, Mario Carneiro
-/
import data.set.countable
import logic.encodable.lattice
import order.disjointed

/-!
# Measurable spaces and measurable functions

> THIS FILE IS SYNCHRONIZED WITH MATHLIB4.
> Any changes to this file require a corresponding PR to mathlib4.

This file defines measurable spaces and measurable functions.

A measurable space is a set equipped with a σ-algebra, a collection of
subsets closed under complementation and countable union. A function
between measurable spaces is measurable if the preimage of each
measurable subset is measurable.

σ-algebras on a fixed set `α` form a complete lattice. Here we order
σ-algebras by writing `m₁ ≤ m₂` if every set which is `m₁`-measurable is
also `m₂`-measurable (that is, `m₁` is a subset of `m₂`). In particular, any
collection of subsets of `α` generates a smallest σ-algebra which
contains all of them.

Do not add measurability lemmas (which could be tagged with
@[measurability]) to this file, since the measurability tactic is downstream
from here. Use `measure_theory.measurable_space` instead.

## References

* <https://en.wikipedia.org/wiki/Measurable_space>
* <https://en.wikipedia.org/wiki/Sigma-algebra>
* <https://en.wikipedia.org/wiki/Dynkin_system>

## Tags

measurable space, σ-algebra, measurable function
-/

open set encodable function equiv
open_locale classical

variables {α β γ δ δ' : Type*} {ι : Sort*} {s t u : set α}

/-- A measurable space is a space equipped with a σ-algebra. -/
structure measurable_space (α : Type*) :=
(measurable_set' : set α → Prop)
(measurable_set_empty : measurable_set' ∅)
(measurable_set_compl : ∀ s, measurable_set' s → measurable_set' sᶜ)
(measurable_set_Union : ∀ f : ℕ → set α, (∀ i, measurable_set' (f i)) → measurable_set' (⋃ i, f i))

attribute [class] measurable_space

instance [h : measurable_space α] : measurable_space αᵒᵈ := h

section

/-- `measurable_set s` means that `s` is measurable (in the ambient measure space on `α`) -/
def measurable_set [measurable_space α] : set α → Prop := ‹measurable_space α›.measurable_set'

localized "notation (name := measurable_set_of)
  `measurable_set[` m `]` := @measurable_set hole! m" in measure_theory

@[simp] lemma measurable_set.empty [measurable_space α] : measurable_set (∅ : set α) :=
‹measurable_space α›.measurable_set_empty

variable {m : measurable_space α}

include m

lemma measurable_set.compl : measurable_set s → measurable_set sᶜ :=
‹measurable_space α›.measurable_set_compl s

lemma measurable_set.of_compl (h : measurable_set sᶜ) : measurable_set s :=
compl_compl s ▸ h.compl

@[simp] lemma measurable_set.compl_iff : measurable_set sᶜ ↔ measurable_set s :=
⟨measurable_set.of_compl, measurable_set.compl⟩

@[simp] lemma measurable_set.univ : measurable_set (univ : set α) :=
by simpa using (@measurable_set.empty α _).compl

@[nontriviality] lemma subsingleton.measurable_set [subsingleton α] {s : set α} :
  measurable_set s :=
subsingleton.set_cases measurable_set.empty measurable_set.univ s

lemma measurable_set.congr {s t : set α} (hs : measurable_set s) (h : s = t) :
  measurable_set t :=
by rwa ← h

lemma measurable_set.bUnion_decode₂ [encodable β] ⦃f : β → set α⦄ (h : ∀ b, measurable_set (f b))
  (n : ℕ) : measurable_set (⋃ b ∈ decode₂ β n, f b) :=
encodable.Union_decode₂_cases measurable_set.empty h

lemma measurable_set.Union [countable ι] ⦃f : ι → set α⦄ (h : ∀ b, measurable_set (f b)) :
  measurable_set (⋃ b, f b) :=
begin
  casesI nonempty_encodable (plift ι),
  rw [←Union_plift_down, ←encodable.Union_decode₂],
  exact ‹measurable_space α›.measurable_set_Union _ (measurable_set.bUnion_decode₂ $ λ _, h _),
end

lemma measurable_set.bUnion {f : β → set α} {s : set β} (hs : s.countable)
  (h : ∀ b ∈ s, measurable_set (f b)) : measurable_set (⋃ b ∈ s, f b) :=
begin
  rw bUnion_eq_Union,
  haveI := hs.to_encodable,
  exact measurable_set.Union (by simpa using h)
end

lemma set.finite.measurable_set_bUnion {f : β → set α} {s : set β} (hs : s.finite)
  (h : ∀ b ∈ s, measurable_set (f b)) :
  measurable_set (⋃ b ∈ s, f b) :=
measurable_set.bUnion hs.countable h

lemma finset.measurable_set_bUnion {f : β → set α} (s : finset β)
  (h : ∀ b ∈ s, measurable_set (f b)) :
  measurable_set (⋃ b ∈ s, f b) :=
s.finite_to_set.measurable_set_bUnion h

lemma measurable_set.sUnion {s : set (set α)} (hs : s.countable) (h : ∀ t ∈ s, measurable_set t) :
  measurable_set (⋃₀ s) :=
by { rw sUnion_eq_bUnion, exact measurable_set.bUnion hs h }

lemma set.finite.measurable_set_sUnion {s : set (set α)} (hs : s.finite)
  (h : ∀ t ∈ s, measurable_set t) :
  measurable_set (⋃₀ s) :=
measurable_set.sUnion hs.countable h

lemma measurable_set.Inter [countable ι] {f : ι → set α} (h : ∀ b, measurable_set (f b)) :
  measurable_set (⋂ b, f b) :=
measurable_set.compl_iff.1 $
by { rw compl_Inter, exact measurable_set.Union (λ b, (h b).compl) }

lemma measurable_set.bInter {f : β → set α} {s : set β} (hs : s.countable)
  (h : ∀ b ∈ s, measurable_set (f b)) : measurable_set (⋂ b ∈ s, f b) :=
measurable_set.compl_iff.1 $
by { rw compl_Inter₂, exact measurable_set.bUnion hs (λ b hb, (h b hb).compl) }

lemma set.finite.measurable_set_bInter {f : β → set α} {s : set β} (hs : s.finite)
  (h : ∀ b ∈ s, measurable_set (f b)) : measurable_set (⋂ b ∈ s, f b) :=
measurable_set.bInter hs.countable h

lemma finset.measurable_set_bInter {f : β → set α} (s : finset β)
  (h : ∀ b ∈ s, measurable_set (f b)) : measurable_set (⋂ b ∈ s, f b) :=
s.finite_to_set.measurable_set_bInter h

lemma measurable_set.sInter {s : set (set α)} (hs : s.countable) (h : ∀ t ∈ s, measurable_set t) :
  measurable_set (⋂₀ s) :=
by { rw sInter_eq_bInter, exact measurable_set.bInter hs h }

lemma set.finite.measurable_set_sInter {s : set (set α)} (hs : s.finite)
  (h : ∀ t ∈ s, measurable_set t) : measurable_set (⋂₀ s) :=
measurable_set.sInter hs.countable h

@[simp] lemma measurable_set.union {s₁ s₂ : set α} (h₁ : measurable_set s₁)
  (h₂ : measurable_set s₂) :
  measurable_set (s₁ ∪ s₂) :=
by { rw union_eq_Union, exact measurable_set.Union (bool.forall_bool.2 ⟨h₂, h₁⟩) }

@[simp] lemma measurable_set.inter {s₁ s₂ : set α} (h₁ : measurable_set s₁)
  (h₂ : measurable_set s₂) :
  measurable_set (s₁ ∩ s₂) :=
by { rw inter_eq_compl_compl_union_compl, exact (h₁.compl.union h₂.compl).compl }

@[simp] lemma measurable_set.diff {s₁ s₂ : set α} (h₁ : measurable_set s₁)
  (h₂ : measurable_set s₂) :
  measurable_set (s₁ \ s₂) :=
h₁.inter h₂.compl

@[simp] lemma measurable_set.symm_diff {s₁ s₂ : set α}
  (h₁ : measurable_set s₁) (h₂ : measurable_set s₂) :
  measurable_set (s₁ ∆ s₂) :=
(h₁.diff h₂).union (h₂.diff h₁)

@[simp] lemma measurable_set.ite {t s₁ s₂ : set α} (ht : measurable_set t) (h₁ : measurable_set s₁)
  (h₂ : measurable_set s₂) :
  measurable_set (t.ite s₁ s₂) :=
(h₁.inter ht).union (h₂.diff ht)

lemma measurable_set.ite' {s t : set α} {p : Prop}
  (hs : p → measurable_set s) (ht : ¬ p → measurable_set t) :
  measurable_set (ite p s t) :=
by { split_ifs, exacts [hs h, ht h], }

@[simp] lemma measurable_set.cond {s₁ s₂ : set α} (h₁ : measurable_set s₁) (h₂ : measurable_set s₂)
  {i : bool} : measurable_set (cond i s₁ s₂) :=
by { cases i, exacts [h₂, h₁] }

@[simp] lemma measurable_set.disjointed {f : ℕ → set α} (h : ∀ i, measurable_set (f i)) (n) :
  measurable_set (disjointed f n) :=
disjointed_rec (λ t i ht, measurable_set.diff ht $ h _) (h n)

@[simp] lemma measurable_set.const (p : Prop) : measurable_set {a : α | p} :=
by { by_cases p; simp [h, measurable_set.empty]; apply measurable_set.univ }

/-- Every set has a measurable superset. Declare this as local instance as needed. -/
lemma nonempty_measurable_superset (s : set α) : nonempty { t // s ⊆ t ∧ measurable_set t} :=
⟨⟨univ, subset_univ s, measurable_set.univ⟩⟩

end

open_locale measure_theory

@[ext] lemma measurable_space.ext : ∀ {m₁ m₂ : measurable_space α},
  (∀ s : set α, measurable_set[m₁] s ↔ measurable_set[m₂] s) → m₁ = m₂
| ⟨s₁, _, _, _⟩ ⟨s₂, _, _, _⟩ h :=
  have s₁ = s₂, from funext $ assume x, propext $ h x,
  by subst this

@[ext] lemma measurable_space.ext_iff {m₁ m₂ : measurable_space α} :
  m₁ = m₂ ↔ (∀ s : set α, measurable_set[m₁] s ↔ measurable_set[m₂] s) :=
⟨by { unfreezingI {rintro rfl}, intro s, refl }, measurable_space.ext⟩

/-- A typeclass mixin for `measurable_space`s such that each singleton is measurable. -/
class measurable_singleton_class (α : Type*) [measurable_space α] : Prop :=
(measurable_set_singleton : ∀ x, measurable_set ({x} : set α))

export measurable_singleton_class (measurable_set_singleton)

attribute [simp] measurable_set_singleton

section measurable_singleton_class

variables [measurable_space α] [measurable_singleton_class α]

lemma measurable_set_eq {a : α} : measurable_set {x | x = a} :=
measurable_set_singleton a

lemma measurable_set.insert {s : set α} (hs : measurable_set s) (a : α) :
  measurable_set (insert a s) :=
(measurable_set_singleton a).union hs

@[simp] lemma measurable_set_insert {a : α} {s : set α} :
  measurable_set (insert a s) ↔ measurable_set s :=
⟨λ h, if ha : a ∈ s then by rwa ← insert_eq_of_mem ha
  else insert_diff_self_of_not_mem ha ▸ h.diff (measurable_set_singleton _),
  λ h, h.insert a⟩

lemma set.subsingleton.measurable_set {s : set α} (hs : s.subsingleton) : measurable_set s :=
hs.induction_on measurable_set.empty measurable_set_singleton

lemma set.finite.measurable_set {s : set α} (hs : s.finite) : measurable_set s :=
finite.induction_on hs measurable_set.empty $ λ a s ha hsf hsm, hsm.insert _

protected lemma finset.measurable_set (s : finset α) : measurable_set (↑s : set α) :=
s.finite_to_set.measurable_set

lemma set.countable.measurable_set {s : set α} (hs : s.countable) : measurable_set s :=
begin
  rw [← bUnion_of_singleton s],
  exact measurable_set.bUnion hs (λ b hb, measurable_set_singleton b)
end

end measurable_singleton_class

namespace measurable_space

section complete_lattice

instance : has_le (measurable_space α) :=
{ le          := λ m₁ m₂, ∀ s, measurable_set[m₁] s → measurable_set[m₂] s }

lemma le_def {α} {a b : measurable_space α} :
  a ≤ b ↔ a.measurable_set' ≤ b.measurable_set' := iff.rfl

instance : partial_order (measurable_space α) :=
{ lt := λ m₁ m₂, m₁ ≤ m₂ ∧ ¬m₂ ≤ m₁,
  .. measurable_space.has_le,
  .. partial_order.lift (@measurable_set α) (λ m₁ m₂ h, ext $ λ s, h ▸ iff.rfl) }

/-- The smallest σ-algebra containing a collection `s` of basic sets -/
inductive generate_measurable (s : set (set α)) : set α → Prop
| basic : ∀ u ∈ s, generate_measurable u
| empty : generate_measurable ∅
| compl : ∀ s, generate_measurable s → generate_measurable sᶜ
| union : ∀ f : ℕ → set α, (∀ n, generate_measurable (f n)) → generate_measurable (⋃ i, f i)

/-- Construct the smallest measure space containing a collection of basic sets -/
def generate_from (s : set (set α)) : measurable_space α :=
{ measurable_set'      := generate_measurable s,
  measurable_set_empty := generate_measurable.empty,
  measurable_set_compl := generate_measurable.compl,
  measurable_set_Union := generate_measurable.union }

lemma measurable_set_generate_from {s : set (set α)} {t : set α} (ht : t ∈ s) :
  @measurable_set _ (generate_from s) t :=
generate_measurable.basic t ht

@[elab_as_eliminator]
lemma generate_from_induction (p : set α → Prop) (C : set (set α))
  (hC : ∀ t ∈ C, p t) (h_empty : p ∅) (h_compl : ∀ t, p t → p tᶜ)
  (h_Union : ∀ f : ℕ → set α, (∀ n, p (f n)) → p (⋃ i, f i))
  {s : set α} (hs : measurable_set[generate_from C] s) :
  p s :=
by { induction hs, exacts [hC _ hs_H, h_empty, h_compl _ hs_ih, h_Union hs_f hs_ih], }

lemma generate_from_le {s : set (set α)} {m : measurable_space α}
  (h : ∀ t ∈ s, measurable_set[m] t) : generate_from s ≤ m :=
assume t (ht : generate_measurable s t), ht.rec_on h
  (measurable_set_empty m)
  (assume s _ hs, measurable_set_compl m s hs)
  (assume f _ hf, measurable_set_Union m f hf)

lemma generate_from_le_iff {s : set (set α)} (m : measurable_space α) :
  generate_from s ≤ m ↔ s ⊆ {t | measurable_set[m] t} :=
iff.intro
  (assume h u hu, h _ $ measurable_set_generate_from hu)
  (assume h, generate_from_le h)

@[simp] lemma generate_from_measurable_set [measurable_space α] :
  generate_from {s : set α | measurable_set s} = ‹_› :=
le_antisymm (generate_from_le $ λ _, id) $ λ s, measurable_set_generate_from

/-- If `g` is a collection of subsets of `α` such that the `σ`-algebra generated from `g` contains
the same sets as `g`, then `g` was already a `σ`-algebra. -/
protected def mk_of_closure (g : set (set α)) (hg : {t | measurable_set[generate_from g] t} = g) :
  measurable_space α :=
{ measurable_set'      := λ s, s ∈ g,
  measurable_set_empty := hg ▸ measurable_set_empty _,
  measurable_set_compl := hg ▸ measurable_set_compl _,
  measurable_set_Union := hg ▸ measurable_set_Union _ }

lemma mk_of_closure_sets {s : set (set α)}
  {hs : {t | measurable_set[generate_from s] t} = s} :
  measurable_space.mk_of_closure s hs = generate_from s :=
measurable_space.ext $ assume t, show t ∈ s ↔ _, by { conv_lhs { rw [← hs] }, refl }

/-- We get a Galois insertion between `σ`-algebras on `α` and `set (set α)` by using `generate_from`
  on one side and the collection of measurable sets on the other side. -/
def gi_generate_from : galois_insertion (@generate_from α) (λ m, {t | @measurable_set α m t}) :=
{ gc        := assume s, generate_from_le_iff,
  le_l_u    := assume m s, measurable_set_generate_from,
  choice    :=
    λ g hg, measurable_space.mk_of_closure g $ le_antisymm hg $ (generate_from_le_iff _).1 le_rfl,
  choice_eq := assume g hg, mk_of_closure_sets }

instance : complete_lattice (measurable_space α) :=
gi_generate_from.lift_complete_lattice

instance : inhabited (measurable_space α) := ⟨⊤⟩

@[mono] lemma generate_from_mono {s t : set (set α)} (h : s ⊆ t) :
  generate_from s ≤ generate_from t :=
gi_generate_from.gc.monotone_l h

lemma generate_from_sup_generate_from {s t : set (set α)} :
  generate_from s ⊔ generate_from t = generate_from (s ∪ t) :=
(@gi_generate_from α).gc.l_sup.symm

@[simp] lemma generate_from_insert_univ (S : set (set α)) :
  generate_from (insert set.univ S) = generate_from S :=
begin
  refine le_antisymm _ (generate_from_mono (set.subset_insert _ _)),
  rw generate_from_le_iff,
  intros t ht,
  cases ht,
  { rw ht,
    exact measurable_set.univ, },
  { exact measurable_set_generate_from ht, },
end

@[simp] lemma generate_from_insert_empty (S : set (set α)) :
  generate_from (insert ∅ S) = generate_from S :=
begin
  refine le_antisymm _ (generate_from_mono (set.subset_insert _ _)),
  rw generate_from_le_iff,
  intros t ht,
  cases ht,
  { rw ht,
    exact @measurable_set.empty _ (generate_from S), },
  { exact measurable_set_generate_from ht, },
end

@[simp] lemma generate_from_singleton_empty : generate_from {∅} = (⊥ : measurable_space α) :=
by { rw [eq_bot_iff, generate_from_le_iff], simp, }

@[simp] lemma generate_from_singleton_univ : generate_from {set.univ} = (⊥ : measurable_space α) :=
by { rw [eq_bot_iff, generate_from_le_iff], simp, }

lemma measurable_set_bot_iff {s : set α} : @measurable_set α ⊥ s ↔ (s = ∅ ∨ s = univ) :=
let b : measurable_space α :=
{ measurable_set'      := λ s, s = ∅ ∨ s = univ,
  measurable_set_empty := or.inl rfl,
  measurable_set_compl := by simp [or_imp_distrib] {contextual := tt},
  measurable_set_Union := assume f hf, classical.by_cases
    (assume h : ∃i, f i = univ,
      let ⟨i, hi⟩ := h in
      or.inr $ eq_univ_of_univ_subset $ hi ▸ le_supr f i)
    (assume h : ¬ ∃i, f i = univ,
      or.inl $ eq_empty_of_subset_empty $ Union_subset $ assume i,
        (hf i).elim (by simp {contextual := tt}) (assume hi, false.elim $ h ⟨i, hi⟩)) } in
have b = ⊥, from bot_unique $ assume s hs,
  hs.elim (λ s, s.symm ▸ @measurable_set_empty _ ⊥) (λ s, s.symm ▸ @measurable_set.univ _ ⊥),
this ▸ iff.rfl

@[simp] theorem measurable_set_top {s : set α} : @measurable_set _ ⊤ s := trivial

@[simp] theorem measurable_set_inf {m₁ m₂ : measurable_space α} {s : set α} :
  @measurable_set _ (m₁ ⊓ m₂) s ↔ @measurable_set _ m₁ s ∧ @measurable_set _ m₂ s :=
iff.rfl

@[simp] theorem measurable_set_Inf {ms : set (measurable_space α)} {s : set α} :
  @measurable_set _ (Inf ms) s ↔ ∀ m ∈ ms, @measurable_set _ m s :=
show s ∈ (⋂₀ _) ↔ _, by simp

@[simp] theorem measurable_set_infi {ι} {m : ι → measurable_space α} {s : set α} :
  @measurable_set _ (infi m) s ↔ ∀ i, @measurable_set _ (m i) s :=
by rw [infi, measurable_set_Inf, forall_range_iff]

theorem measurable_set_sup {m₁ m₂ : measurable_space α} {s : set α} :
  measurable_set[m₁ ⊔ m₂] s ↔ generate_measurable (measurable_set[m₁] ∪ measurable_set[m₂]) s :=
iff.refl _

theorem measurable_set_Sup {ms : set (measurable_space α)} {s : set α} :
  measurable_set[Sup ms] s ↔
    generate_measurable {s : set α | ∃ m ∈ ms, measurable_set[m] s} s :=
begin
  change @measurable_set' _ (generate_from $ ⋃₀ _) _ ↔ _,
  simp [generate_from, ← set_of_exists]
end

theorem measurable_set_supr {ι} {m : ι → measurable_space α} {s : set α} :
  @measurable_set _ (supr m) s ↔
    generate_measurable {s : set α | ∃ i, measurable_set[m i] s} s :=
by simp only [supr, measurable_set_Sup, exists_range_iff]

lemma measurable_space_supr_eq (m : ι → measurable_space α) :
  (⨆ n, m n) = generate_from {s | ∃ n, measurable_set[m n] s} :=
by { ext s, rw measurable_set_supr, refl, }

end complete_lattice

end measurable_space

section measurable_functions
open measurable_space

/-- A function `f` between measurable spaces is measurable if the preimage of every
  measurable set is measurable. -/
def measurable [measurable_space α] [measurable_space β] (f : α → β) : Prop :=
∀ ⦃t : set β⦄, measurable_set t → measurable_set (f ⁻¹' t)

localized "notation (name := measurable_of)
  `measurable[` m `]` := @measurable hole! hole! m hole!" in measure_theory

lemma measurable_id {ma : measurable_space α} : measurable (@id α) := λ t, id

lemma measurable_id' {ma : measurable_space α} : measurable (λ a : α, a) := measurable_id

lemma measurable.comp {mα : measurable_space α} {mβ : measurable_space β}
  {mγ : measurable_space γ} {g : β → γ} {f : α → β} (hg : measurable g) (hf : measurable f) :
  measurable (g ∘ f) :=
λ t ht, hf (hg ht)

@[simp] lemma measurable_const {ma : measurable_space α} {mb : measurable_space β} {a : α} :
  measurable (λ b : β, a) :=
assume s hs, measurable_set.const (a ∈ s)

lemma measurable.le {α} {m m0 : measurable_space α} {mb : measurable_space β} (hm : m ≤ m0)
  {f : α → β}
  (hf : measurable[m] f) : measurable[m0] f :=
λ s hs, hm _ (hf hs)

lemma measurable_space.top.measurable {α β : Type*} [measurable_space β] (f : α → β) :
  @measurable α β ⊤ _ f :=
λ s hs, measurable_space.measurable_set_top

end measurable_functions


import data.list data.subtype data.set classical
open subtype list prod prod.ops nat eq.ops

definition no_dup {V : Type} : list V → Prop
| [] := true
| (x :: xs) := ¬ x ∈ xs ∧ no_dup xs

definition last {V : Type} [V_inhabited : inhabited V] : list V → V
| [] := arbitrary V
| [x] := x
| (x :: xs) := last xs

definition all_but_last {V : Type} : list V → list V
| [] := []
| [x] := []
| (x :: xs) := x :: all_but_last xs

lemma all_but_last_concat {V : Type} (xs : list V) (x : V) : all_but_last (concat x xs) = xs := sorry
lemma last_concat {V : Type} [V_inhabited : inhabited V] (xs : list V) (x : V) : last (concat x xs) = x := sorry
lemma head_concat {V : Type} [V_inhabited : inhabited V] (xs : list V) (x : V) : xs ≠ [] → head (concat x xs) = head xs := sorry
lemma length_concat {V : Type} (xs : list V) (x : V) : length (concat x xs) = length xs + 1 := sorry

lemma concat_nnil {V : Type} (xs : list V) (x : V) : concat x xs ≠ nil := sorry
lemma concat_nnil_gt1 {V : Type} (xs : list V) (x : V) : xs ≠ nil → length (concat x xs) > 1 := sorry

theorem prop_demorgan : ∀ {A B : Prop}, ¬ (A ∧ B) → ¬ A ∨ ¬ B :=
  take (A B : Prop),
  take notAandB : ¬ (A ∧ B),
  or.elim (em A)
          (take a : A,
           or.elim (em B)
                   (take b : B, absurd (and.intro a b) notAandB)
                   (take nb : ¬ B, or.inr nb))
          (take na : ¬ A, or.inl na)

lemma reverse_last_head {V : Type} [V_inhabited : inhabited V] (xs : list V) : last (reverse xs) = head xs:= sorry
lemma reverse_head_last {V : Type} [V_inhabited : inhabited V] (xs : list V) : head (reverse xs) = last xs := sorry

definition edge (V : Type) := V × V
definition graph (V : Type) := edge V → Prop
definition undirected {V : Type} (g : graph V) := ∀ (u v : V), g (u,v) → g (v,u)

namespace path

variables {V : Type} [V_decidable_eq : decidable_eq V] [V_inhabited : inhabited V]
include V_decidable_eq V_inhabited

/- [KS]
A path in a graph G = (V, E) is a series of nodes (v1, v2, …, vn) where for any i ∈ ℕ with 1 ≤ i < n,
there is an edge from vi to vi+1.
-/

definition path_pred (g : graph V) (xs : list V) := ∀ (i : ℕ), i < pred (length xs) → g (nth xs i,nth xs (i + 1))
definition path (g : graph V) := { xs : list V | path_pred g xs }

/- [KS]
A simple path is a path with no repeated nodes.
-/

definition simple_path_pred (g : graph V) (xs : list V) := path_pred g xs ∧ no_dup xs
definition simple_path (g : graph V) := { xs : list V | simple_path_pred g xs }

/- [KS]
A cycle is a path that starts and ends at the same node.
#DHS his definitions are inconsistent at the null path
-/

definition cycle_pred (g : graph V) (xs : list V) := path_pred g xs ∧ head xs = last xs ∧ length xs > 1
definition cycle (g : graph V) := { xs : list V | cycle_pred g xs }

/- [KS]
A simple cycle is a cycle that does not contain any duplicate nodes (except for the very last node) or
duplicate edges.
-/

definition simple_cycle_pred (g : graph V) (xs : list V) := cycle_pred g xs ∧ no_dup (all_but_last xs)
definition simple_cycle (g : graph V) := { xs : list V | simple_cycle_pred g xs }

/- [KS]
Let G be an undirected graph. Two nodes u and v are called connected iff there is a path from u to v
in G. If u and v are connected, we denote this by writing u ↔ v. If u and v are not connected, we denote
this by writing u ↮ v.
-/

variables (g : graph V)

variables {g_symmetric : ∀ (u v : V), g (u,v) → g (v,u)}

definition connected (u v : V) := ∃ xs, path_pred g xs ∧ head xs = u ∧ last xs = v
lemma connected_simple {u v : V} : connected g u v → ∃ xs, simple_path_pred g xs ∧ head xs = u ∧ last xs = v := sorry

local notation u ↔ v := connected g u v

/- [KS]
Theorem: Let G = (V, E) be an undirected graph. Then:
(1) If v ∈ V, then v ↔ v.
(2) If u, v ∈ V and u ↔ v, then v ↔ u.
(3) If u, v, w ∈ V, then if u ↔ v and v ↔ w, then u ↔ w
Proof: We prove each part independently.
To prove (1), note that for any v ∈ V, the trivial path (v) is a path from v to itself. Thus v ↔ v.
To prove (2), consider any u, v ∈ V where u ↔ v. Then there must be some path (u, x1, x2, …, xn, v).
Since G is an undirected graph, this means v, xn, …, x1, u is a path from v to u. Thus v ↔ u.
To prove (3), consider any u, v, w ∈ V where u ↔ v and v ↔ w. Then there must be paths u, x1, x2,
…, xn, v and v, y1, y2, …, ym, w. Consequently, (u, x1, …, xn, v, y1, …, ym, w) is a path from u to w.
Thus u ↔ w.
-/

lemma not_lt_zero : ∀ n, ¬ n < 0 := sorry
definition reverse_index (xs : list V) (i : ℕ) := length xs - 1 - i
lemma reverse_length : ∀ (xs : list V), length (reverse xs) = length xs := sorry
lemma reverse_index_lt (xs : list V) {i : ℕ} : reverse_index xs i < length xs → i < length xs := sorry
lemma index_lt_reverse (xs : list V) {i : ℕ} : i < length xs → reverse_index xs i < length xs := sorry
lemma reverse_index_succ (xs : list V) (i : ℕ) : reverse_index xs (i+1) + 1 = reverse_index xs i := sorry
lemma nth_reverse : ∀ (xs : list V) {i : ℕ}, i < length xs → nth (reverse xs) i = nth xs (reverse_index xs i) := sorry
lemma reverse_index_idempotent (xs : list V) (i : ℕ) : reverse_index xs (reverse_index xs i) = i := sorry

theorem connected_refl : ∀ (v : V), v ↔ v :=
  -- To prove (1), note that for any v ∈ V,
  take v,
  -- the trivial path (v) is a path from v to itself.
  have v_path_v : path_pred g [v], from
    take (i : ℕ) (i_lt_0 : i < 0),
    absurd i_lt_0 (not_lt_zero i),
  -- Thus v ↔ v.
  show v ↔ v, from exists.intro _ (and.intro v_path_v (and.intro rfl rfl))

-- [DHS] this proof is a textbook on what kinds of obviousness we need to support
theorem connected_symm : ∀ {u v : V}, u ↔ v → v ↔ u :=
  -- To prove (2), consider any u, v ∈ V where u ↔ v.
  take u v,
  assume u_conn_v : u ↔ v,
  -- Then there must be some path (u, x1, x2, …, xn, v).
  obtain (xs : list V) (H : path_pred g xs ∧ head xs = u ∧ last xs = v), from u_conn_v,
  have path_xs : path_pred g xs, from and.elim_left H,
  have head_xs_u : head xs = u, from and.elim_left (and.elim_right H),
  have last_xs_v : last xs = v, from and.elim_right (and.elim_right H),
  -- Since G is an undirected graph, this means v, xn, …, x1, u is a path from v to u.
  have path_reverse_xs : path_pred g (reverse xs), from
    take (i : ℕ) (i_lt_length_m1 : i < length (reverse xs) - 1),
    show g (nth (reverse xs) i, nth (reverse xs) (i + 1)), from

    have r_Si_lt : reverse_index xs (i+1) < length xs, from sorry,
    have r_i_lt : reverse_index xs i < length xs, from sorry,
    have r_Si_lt_pred : reverse_index xs (i+1) < pred (length xs), from sorry,
    have g_fwd : g (nth xs (reverse_index xs (i+1)), nth xs (reverse_index xs i)), from
      reverse_index_succ xs i ▸ path_xs (reverse_index xs (i+1)) r_Si_lt_pred,

    have nth_ident_i : nth xs (reverse_index xs i) = nth (reverse xs) i, from (nth_reverse xs (reverse_index_lt xs r_i_lt))⁻¹,
    have nth_ident_ip1 : nth xs (reverse_index xs (i+1)) = nth (reverse xs) (i+1), from (nth_reverse xs (reverse_index_lt xs r_Si_lt))⁻¹,

    have g_bwd : g (nth (reverse xs) (i+1), nth (reverse xs) i), from nth_ident_i ▸ nth_ident_ip1 ▸ g_fwd,
    g_symmetric _ _ g_bwd,
     -- Thus v ↔ u.
  show v ↔ u, from exists.intro (reverse xs)
                                (and.intro path_reverse_xs
                                  (and.intro ((reverse_head_last xs)⁻¹ ▸ last_xs_v) (!reverse_last_head⁻¹ ▸ head_xs_u)))

lemma nth_append_first (xs ys : list V) (i : ℕ) : i < length xs → nth (xs ++ ys) i = nth xs i := sorry
lemma nth_append_second (xs ys : list V) (i : ℕ) : i ≥ length xs → nth (xs ++ ys) i = nth ys (i - length xs) := sorry
lemma lt_or_ge (i j : ℕ) : i < j ∨ i ≥ j := sorry

lemma nth_concat_lt (xs : list V) (x : V) (i : ℕ) : i < length xs → nth (concat x xs) i = nth xs i := sorry
lemma nth_concat_eq (xs : list V) (x : V) (i : ℕ) : i = length xs → nth (concat x xs) i = x := sorry

theorem connected_trans : ∀ {u v w : V}, u ↔ v → v ↔ w → u ↔ w :=
  take (u v w : V),
  assume (u_conn_v : u ↔ v) (v_conn_w : v ↔ w),

  obtain (xs : list V) (Huv : path_pred g xs ∧ head xs = u ∧ last xs = v), from u_conn_v,
  have path_xs : path_pred g xs, from and.elim_left Huv,
  have head_xs_u : head xs = u, from and.elim_left (and.elim_right Huv),
  have last_xs_v : last xs = v, from and.elim_right (and.elim_right Huv),

  obtain (ys : list V) (Hvw : path_pred g ys ∧ head ys = v ∧ last ys = w), from v_conn_w,
  have path_ys : path_pred g ys, from and.elim_left Hvw,
  have head_ys_u : head ys = v, from and.elim_left (and.elim_right Hvw),
  have last_ys_v : last ys = w, from and.elim_right (and.elim_right Hvw),

  /- [DHS]
     Lots of tricky list-surgery here.
     - If [i < pred (length xs)], then [g (i,i+1)] follows because of [xs].
     - If [i = pred (length xs)], then [g (i,i+1)] follows because of [ys], where we use that [xs ++ tail ys = (belast xs) ++ ys]
     - If [i > pred (length xs)], then [g (i,i+1)] follows because of [ys]
   -/

  -- this assertion needs that [head ys = last xs]
  have path_zs_forall : ∀ ys, path_pred g ys → path_pred g (xs ++ tail ys), from
    list.rec
      (take (path_nil : path_pred g []) (i : ℕ) (i_lt_len_app : i < pred (length (xs ++ tail nil))),
       have i_lt_len : i < pred (length xs), from (append_nil_right xs) ▸ i_lt_len_app,
       have g_xs : g (nth xs i, nth xs (i+1)), from path_xs i i_lt_len,
       show g (nth (xs ++ []) i, nth (xs ++ []) (i+1)), from (append_nil_right xs)⁻¹ ▸ g_xs)
      (take (y : V) (ys : list V) (IHys : path_pred g ys → path_pred g (xs ++ tail ys)),
       take (path_ys : path_pred g (y :: ys)) (i : ℕ) (i_lt_len_app : i < pred (length (xs ++ ys))),
       sorry),
  sorry

open set binary eq.ops

definition set_minus [reducible] {T : Type} (A B : set T) :=   λ x, x ∈ A ∧ ¬ x ∈ B
notation a - b := set_minus a b
theorem union_com : ∀ {T : Type}, commutative (@union T) := sorry
theorem inter_com : ∀ {T : Type}, commutative (@inter T) := sorry

definition connected_component (vs : set V) := ∀ ⦃u : V⦄, u ∈ vs → ∀ {v : V}, (v ∈ vs → u ↔ v) ∧ (¬ v ∈ vs → ¬ (u ↔ v))

/- [KS]
Theorem: Let G be an undirected graph and let C1 and C2 be connected components of G. If C1 ≠ C2,
then C1 ∩ C2 = Ø.
Proof: By contradiction. Suppose that C1 and C2 are connected components of some undirected
graph G, that C1 ≠ C2, but that C1 ∩ C2 ≠ Ø. Since C1 ∩ C2 ≠ Ø, there must be some node v such that
v ∈ C1 and v ∈ C2. Furthermore, since C1 ≠ C2, there must be some node u that either u ∈ C1 or
u ∈ C2, but not both. Without loss of generality, assume that u ∈ C1 and u ∉ C2.
By the definition of a connected component, since u ∈ C1 and v ∈ C1, we know u ↔ v. Similarly, by
the definition of a connected component, since v ∈ C2 and u ∉ C2, we know that u ↮ v, contradicting
our previous assertion. We have reached a contradiction, so our assumption must have been wrong.
Thus C1 ∩ C2 = Ø, as required.
-/

-- #TODO need to handle unpacking/coercions here...tricky!

lemma inter_nonempty_imp_elem_in_both : ∀ {C1 C2 : set V}, C1 ∩ C2 ≠ ∅ → ∃ v, v ∈ C1 ∧ v ∈ C2 := sorry
lemma inter_empty_imp_not_elem_in_both : ∀ {C1 C2 : set V}, C1 ∩ C2 = ∅ → ∀ {u:V}, u ∈ C1 → ¬ u ∈ C2 := sorry

lemma connected_components_disjoint_helper : ∀ {C1 C2 : set V}, connected_component g C1 → connected_component g C2 → (C1 ∩ C2 ≠ ∅) → ¬ (∃ u:V, u ∈ C1 - C2) :=
  take (C1 C2 : set V),
  assume (CC1 : connected_component g C1) (CC2 : connected_component g C2) (C1_overlap_C2 : C1 ∩ C2 ≠ ∅) (exists_u_in_diff : ∃ u, u ∈ C1 - C2),
  obtain (u : V) (u_in_diff : u ∈ C1 - C2), from exists_u_in_diff,
  have exists_v_in_both : ∃ v, v ∈ C1 ∩ C2, from inter_nonempty_imp_elem_in_both C1_overlap_C2,
  obtain (v : V) (v_in_both : v ∈ C1 ∩ C2), from exists_v_in_both,
  have v_conn_u : v ↔ u, from and.elim_left (CC1 (and.elim_left v_in_both)) (and.elim_left u_in_diff),
  have v_nconn_u : ¬ (v ↔ u), from and.elim_right (CC2 (and.elim_right v_in_both)) (and.elim_right u_in_diff),
  show false, from v_nconn_u v_conn_u

theorem connected_components_disjoint : ∀ {C1 C2 : set V}, connected_component g C1 → connected_component g C2 → C1 ≠ C2 → C1 ∩ C2 = ∅ :=
  take (C1 C2 : set V),
  assume (CC1 : connected_component g C1) (CC2 : connected_component g C2) (C1_neq_C2 : C1 ≠ C2),
  by_contradiction
  (assume C1_ndisj_C2 : C1 ∩ C2 ≠ ∅,
   show false, from
   have u_in_one : (∃ u:V, u ∈ C1 - C2) ∨ (∃ u:V, u ∈ C2 - C1), from sorry,
   or.elim u_in_one
           (take (exists_u : ∃ u, u ∈ C1 - C2), connected_components_disjoint_helper g CC1 CC2 C1_ndisj_C2 exists_u)
           (take (exists_u : ∃ u, u ∈ C2 - C1), connected_components_disjoint_helper g CC2 CC1 ((inter_com C1 C2) ▸ C1_ndisj_C2) exists_u))

/- [DHS]#DESIGN
1. Troublesome WLOG
2. Lots of painful obviousness (e.g. inter_nonempty_imp_elem_in_both)
-/

/- [KS]
Theorem: Let G = (V, E) be an undirected graph. Then for any v ∈ V, there is a connected component
C such that v ∈ C.
Proof: Let G = (V, E) be any undirected graph and let v ∈ V be an arbitrary node in the graph. Consider
the set C = { u ∈ V | u ↔ v }. We will prove C is a connected component containing v.
First, we prove that v ∈ C. To see this, note that by construction, v ∈ C iff v ↔ v. As proven earlier,
v ↔ v is always true. Consequently, v ∈ C.
Next, we prove that C is a connected component. This proof proceeds in two steps: first, we prove
that for any u1, u2 ∈ C, that u1 ↔ u2; second, we prove that for any u1 ∈ C and u2 ∈ V – C, that u1 ↮ u2.
To prove that for any u1, u2 ∈ C, that u1 ↔ u2, consider any u1, u2 ∈ C. By construction, this means
that u1 ↔ v and u2 ↔ v. As proven earlier, since u2 ↔ v, we know that v ↔ u2. Also as proven earlier,
since u1 ↔ v and v ↔ u2, this means that u1 ↔ u2.
Finally, to prove that for any u1 ∈ C and u2 ∈ V – C, that u1 ↮ u2, consider any u1 ∈ C and u2 ∈ V – C.
Assume for the sake of contradiction that u1 ↔ u2. Since u1 ∈ C, we know that u1 ↔ v. Since u1↔ u2,
we know u2 ↔ u1. Therefore, since u2 ↔ u1 and u1 ↔ v, we have that u2 ↔ v. Thus by definition of
C, this means that u2 ∈ C, contradicting the fact that u2 ∈ V – C. We have reached a contradiction, so
our assumption must have been wrong. Thus u1 ↮ u2.
Thus C is a connected component containing v. Since our choice of v and G were arbitrary, any node
in any graph belongs to at least one connected component.
-/

-- Theorem: Let G = (V, E) be an undirected graph. Then for any v ∈ V, there is a connected component C such that v ∈ C.
theorem every_node_in_connected_component : ∀ (v : V), ∃ (C : set V), connected_component g C ∧ v ∈ C :=
  -- Proof: Let G = (V, E) be any undirected graph and let v ∈ V be an arbitrary node in the graph.
  assume (v : V),
  -- Consider the set C = { u ∈ V | u ↔ v }.
  let C := { u : V | u ↔ v} in
  -- We will prove C is a connected component containing v.
  show connected_component g C ∧ v ∈ C, from
  -- First, we prove that v ∈ C.
  have v_in_C : v ∈ C, from
    -- To see this, note that by construction, v ∈ C iff v ↔ v.
    show v ↔ v, from
    -- As proven earlier, v ↔ v is always true. Consequently, v ∈ C.
    connected_refl g v,
  -- Next, we prove that C is a connected component.
  have C_CC : connected_component g C, from
    -- This proof proceeds in two steps: first, we prove that for any u1, u2 ∈ C, that u1 ↔ u2; second, we prove that for any u1 ∈ C and u2 ∈ V – C, that u1 ↮ u2.
    show (∀ (u1 u2 : T), u1 ∈ C → u2 ∈ C → u1 ↔ u2) ∧ (∀ (u1 u2 : T), u1 ∈ C → ¬ u2 ∈ C → ¬ u1 ↔ u2), from
    -- To prove that for any u1, u2 ∈ C, that u1 ↔ u2,
    have all_connected : ∀ (u1 u2 : T), u1 ∈ C → u2 ∈ C → u1 ↔ u2, from
      -- consider any u1, u2 ∈ C.
      assume (u1 u2 : T) (u1_in_C : u1 ∈ C) (u2_in_C : u2 ∈ C),
      -- By construction, this means that u1 ↔ v and u2 ↔ v.
      have u1_conn_v : u1 ↔ v, from u1_in_C,
      have u2_conn_v : u2 ↔ v, from u2_in_C,
       -- As proven earlier, since u2 ↔ v, we know that v ↔ u2.
       have v_conn_u2 : v ↔ u2, from connected_symm g g_symmetric u2_conn_v,
       -- Also as proven earlier, since u1 ↔ v and v ↔ u2, this means that u1 ↔ u2.
       show u1 ↔ u2, from connected_trans g u1_conn_v v_conn_u2,
     -- Finally, to prove that for any u1 ∈ C and u2 ∈ V – C, that u1 ↮ u2,
     have otherwise_not_connected : ∀ (u1 u2 : T), u1 ∈ C → ¬ u2 ∈ C → ¬ u1 ↔ u2, from
       -- consider any u1 ∈ C and u2 ∈ V – C.
       assume (u1 u2 : T) (u1_in_C : u1 ∈ C) (u2_nin_C : ¬ u2 ∈ C),
       -- Assume for the sake of contradiction that u1 ↔ u2.
       show ¬ (u1 ↔ u2), from
       assume u1_conn_u2 : u1 ↔ u2,
       show false, from
       -- Since u1 ∈ C, we know that u1 ↔ v.
       have u1_conn_v : u1 ↔ v, from u1_in_C,
       -- Since u1 ↔ u2, we know u2 ↔ u1.
       have u2_conn_u1 : u2 ↔ u1, from connected_symm g g_symmetric u1_conn_u2,
       -- Therefore, since u2 ↔ u1 and u1 ↔ v, we have that u2 ↔ v.
       have u2_conn_v : u2 ↔ v, from connected_trans g u2_conn_u1 u1_conn_v,
       -- Thus by definition of C, this means that u2 ∈ C,
       have u2_in_C : u2 ∈ C, from u2_conn_v,
       -- contradicting the fact that u2 ∈ V – C.
       show false, from absurd u2_in_C u2_nin_C,
       -- We have reached a contradiction, so our assumption must have been wrong. Thus u1 ↮ u2.
    -- Thus C is a connected component containing v. Since our choice of v and G were arbitrary, any node
    -- in any graph belongs to at least one connected component.
    show ∃ (C : set V), connected_component g C ∧ v ∈ C, from exists.intro C (and.intro CC v_in_C)

/- [KS]
Theorem: Every node in an undirected graph belongs to exactly one connected component.
Proof: <no formal proof>
-/

theorem connected_components_cover : ∀ (v : V), ∃! (C : set V), connected_component g C ∧ v ∈ C :=
  take (v : V),
  exists.elim (@every_node_in_connected_component _ _ _ g g_symmetric v)
  (
    take (C : set V) (HC : connected_component g C ∧ v ∈ C),
    have C_unique : ∀ (D : set V), connected_component g D ∧ v ∈ D → D = C, from
      take (D : set V) (HD : connected_component g D ∧ v ∈ D),
      by_contradiction
      (
        take D_neq_C : D ≠ C,
        have D_disj_C : D ∩ C = ∅, from connected_components_disjoint g (and.elim_left HD) (and.elim_left HC) D_neq_C,
        inter_empty_imp_not_elem_in_both D_disj_C (and.elim_right HD) (and.elim_right HC)
      ),
    exists_unique.intro _ HC C_unique
  )

-- k-connectivity

-- Trees

/- [KS]
An undirected graph G is called minimally connected iff G is connected, but the removal of any edge
from G leaves G disconnected.

A graph is called acyclic iff it contains no simple cycles.
-/

definition graph_connected := ∀ (u v : V), connected g u v

definition add_edge (e : edge V) : graph V := λ (f : edge V), if e.1 = f.1 ∧ e.2 = f.2 ∨ e.1 = f.2 ∧ e.2 = f.1 then true else g f
definition remove_edge (e : edge V) : graph V := λ (f : edge V), if e.1 = f.1 ∧ e.2 = f.2 ∨ e.1 = f.2 ∧ e.2 = f.1 then false else g f
definition remove_add (e : edge V) : remove_edge (add_edge g e) e = g := sorry

lemma add_edge_contains (e : edge V) : add_edge g e e := sorry
lemma add_edge_monotone {e : edge V} : g e → ∀ (f : edge V), (add_edge g f) e := sorry
lemma edge_imp_path {e : edge V} : g e → e.1 ↔ e.2 := sorry

definition minimally_connected := graph_connected g ∧ ∀ (e : edge V), g e → ¬ graph_connected (remove_edge g e)

definition acyclic := ¬ ∃ (xs : list V), simple_cycle_pred g xs
definition maximally_acyclic := acyclic g ∧ ∀ (e : edge V), ¬ g e → ∃ (xs : list V), simple_cycle_pred (add_edge g e) xs

lemma double_negation : ∀ {P : Prop}, ¬ ¬ P → P := sorry

definition get_edge (xs : list V) (i : ℕ) : edge V := (nth xs i, nth xs (i+1))
lemma path_edge_in_graph (xs : list V) : path_pred g xs → ∀ (i : ℕ), i < pred (length xs) → g (get_edge xs i) := sorry

/- [KS]
Theorem: Let G = (V, E) be any graph containing a simple cycle C. Let u, v ∈ V be nodes in G. If
u ↔ v, then after deleting any single edge in C from graph G, it is still the case that u ↔ v.
-/

theorem simple_cycle_not_fragile :
  ∀ {xs : list V}, simple_cycle_pred g xs →
    ∀ (u v : V), u ↔ v →
      ∀ {i : ℕ}, i < pred (length xs) →
        connected (remove_edge g (get_edge xs i)) u v := sorry

lemma graph_connected_w_simple_cycle_imp_not_fragile :
  graph_connected g →
    ∀ {xs : list V}, simple_cycle_pred g xs →
    ∀ {i : ℕ}, i < pred (length xs) →
    graph_connected (remove_edge g (get_edge xs i)) := sorry

theorem minimally_connected_imp_connected_and_acyclic : minimally_connected g → graph_connected g ∧ acyclic g :=
  and.rec
    (assume (g_connected : graph_connected g) (g_fragile : ∀ (e : edge V), g e → ¬ graph_connected (remove_edge g e)),
    -- Proof: By contradiction; assume that G is minimally-connected, but that it is not connected or that it is not acyclic.
    by_contradiction
      (assume not__connected_and_acyclic : ¬ (graph_connected g ∧ acyclic g),
       have not_connected_or_not_acyclic : ¬ graph_connected g ∨ ¬ acyclic g, from prop_demorgan not__connected_and_acyclic,
       -- It cannot be the case that G is not connected, since by definition any minimally-connected graph must be connected.
       -- So we must have that G is not acyclic, meaning that it contains a simple cycle; call it C.
       or.elim not_connected_or_not_acyclic
         (assume g_not_connected : ¬ graph_connected g, absurd g_connected g_not_connected)
         (assume g_not_acyclic : ¬ acyclic g,
          have g_has_simple_cycle : ∃ (xs : list V), simple_cycle_pred g xs, from double_negation g_not_acyclic,
          obtain (C : list V) (C_simple_cycle : simple_cycle_pred g C), from g_has_simple_cycle,
          -- By our previous corollary, since G is connected and C is a simple cycle, we can delete any edge e ∈ C from G without disconnecting G.
          have can_delete_edge : ∀ (i : ℕ), i < pred (length C) → graph_connected (remove_edge g (get_edge C i)), from
            take (i : ℕ) (i_lt_pred : i < pred (length C)),
            graph_connected_w_simple_cycle_imp_not_fragile g g_connected C_simple_cycle i_lt_pred,
         -- This contradicts the fact that G is minimally-connected.
          have C_path : path_pred g C, from and.elim_left (and.elim_left C_simple_cycle),
          absurd (can_delete_edge 0 sorry) (g_fragile (get_edge C 0) (path_edge_in_graph g C C_path 0 sorry))
      )))
    -- We have reached a contradiction, so our assumption must have been wrong. Thus if G is minimally-connected, then it must be connected and acyclic.

/- [KS]
Theorem: If an undirected graph G is connected and acyclic, then it is maximally acyclic.
Proof: Consider any undirected, connected, acyclic graph G = (V, E). Now, consider any pair of
nodes {u, v} such that {u, v} ∉ E. We will prove that adding the edge {u, v} introduces a simple cycle.
To see this, note that since G is connected, there must be a simple path (u, x1, x2, …, xn, v) from
u to v in G. Since this path is a simple path, none of the nodes x1, x2, …, xn can be equal to either u
or v. Now, consider the graph formed by adding {u, v} to G. We can then complete the previous
simple path into a simple cycle by following this new edge from v to u, giving the simple cycle (u, x1,
x2, …, xn, v, u). Since our choice of edge was arbitrary, this proves that adding any edge to G introduces
a simple cycle. Since G is acyclic, this proves that it is maximally acyclic
-/

theorem connected_and_acyclic_imp_maximally_acyclic : graph_connected g → acyclic g → maximally_acyclic g :=
  -- Proof: Consider any undirected, connected, acyclic graph G = (V, E).
  assume (g_connected : graph_connected g) (g_acyclic : acyclic g),
  have cannot_add_edge : ∀ (e : edge V), ¬ g e → ∃ (xs : list V), simple_cycle_pred (add_edge g e) xs, from
    -- Now, consider any pair of nodes {u, v} such that {u, v} ∉ E. We will prove that adding the edge {u, v} introduces a simple cycle.
    take (e : edge V) (e_nin_g : ¬ g e),
    -- To see this, note that since G is connected, there must be a simple path (u, x1, x2, …, xn, v) from u to v in G.
    obtain (xs : list V) (Hxs : simple_path_pred g xs ∧ head xs = e.1 ∧ last xs = e.2), from connected_simple g (g_connected e.1 e.2),
    have path_g_xs : path_pred g xs, from and.elim_left (and.elim_left Hxs),
    -- Since this path is a simple path, none of the nodes x1, x2, …, xn can be equal to either u or v.
    have no_dup_xs : no_dup xs, from and.elim_right (and.elim_left Hxs),
    -- Now, consider the graph formed by adding {u, v} to G.
    let h : graph V := add_edge g e,
        ys : list V := concat e.1 xs
    in
    -- We can then complete the previous simple path into a simple cycle by following this new edge from v to u, giving the simple cycle (u, x1, x2, …, xn, v, u).
    have h_simple_cycle : simple_cycle_pred h ys, from
      have no_dup_all_but_last : no_dup (all_but_last ys), from (all_but_last_concat xs e.1)⁻¹ ▸ no_dup_xs,
      have path_concat : path_pred h ys, from
        take (i : ℕ) (i_lt_pred_ys : i < pred (length ys)),
        have i_cases : i < pred (length xs) ∨ i = pred (length xs), from sorry,
        or.elim i_cases
          -- TODO this is just bookkeeping, like in [connected_symm]
          -- (nth_concat_lt xs x i_lt_pred_xs) ▸ add_edge_monotone g (path_g_xs i i_lt_pred_xs) e)
          (take i_lt_pred_xs : i < pred (length xs), sorry)
          -- TODO need to show that first node is last and last node is first
          (take i_eq_pred_length_xs : i = pred (length xs), sorry),
      have xs_nnil : xs ≠ [], from sorry, -- I guess [path_pred] needs this condition
      have head_eq_last : head ys = last ys, from
        have head_eq_e1 : head ys = e.1, from (head_concat xs e.1 xs_nnil)⁻¹ ▸ and.elim_left (and.elim_right Hxs),
        have last_eq_e1 : last ys = e.1, from last_concat xs e.1,
        last_eq_e1⁻¹ ▸ head_eq_e1,
      and.intro (and.intro path_concat (and.intro head_eq_last (concat_nnil_gt1 xs e.1 xs_nnil))) no_dup_all_but_last,
    exists.intro _ h_simple_cycle,
  and.intro g_acyclic cannot_add_edge

/- [KS]
Lemma: If G is maximally acyclic, then G is connected.
Proof: By contradiction. Suppose that G = (V, E) is a maximally acyclic graph that is not connected.
Since G is not connected, it must consist of several connected components. Choose any two of these
connected components and call them CC1 and CC2.
Now, consider any nodes u ∈ CC1 and v ∈ CC2. Since u and v are in separate connected components,
note that u ↮ v and the edge {u, v} ∉ E. So consider what happens when we add the edge {u, v} to
the graph. Since G is maximally acyclic, this must introduce a simple cycle; call it C. Since G is
acyclic, this new cycle must use the edge {u, v}. Additionally, note that since {u, v} is an edge in the
new graph, we have that u ↔ v in this new graph.
By our earlier theorem, since in this new graph u ↔ v and C is a simple cycle, if we delete any single
edge from C, it will still be the case that u ↔ v still holds. In particular, this means that if we delete
{u, v} from the new graph (which yields the original graph G), we should have that u ↔ v. But this is
impossible, since we know that u ↮ v in the original graph.
We have reached a contradiction, so our assumption must have been wrong. Thus if G is maximally
acyclic, it must be connected.
-/
check maximally_acyclic
print definition maximally_acyclic
/-
lemma graph_connected_w_simple_cycle_imp_not_fragile :
  graph_connected g →
    ∀ {xs : list V}, simple_cycle_pred g xs →
    ∀ {i : ℕ}, i < pred (length xs) →
    graph_connected (remove_edge g (get_edge xs i)) := sorry
-/

lemma maximally_acyclic_imp_connected : maximally_acyclic g → graph_connected g :=
  -- Proof: By contradiction. Suppose that G = (V, E) is a maximally acyclic graph that is not connected.
  assume (g_maximally_acyclic : maximally_acyclic g),
  by_contradiction
  (
    assume g_not_connected : ¬ graph_connected g,
    -- Since G is not connected, it must consist of several connected components. Choose any two of these connected components and call them CC1 and CC2.
    have two_connected_components : ∃ (C1 C2 : set V), connected_component g C1 ∧ connected_component g C2 ∧ C1 ≠ C2, from sorry,
    obtain (C1 C2 : set V) (H_C1C2 : connected_component g C1 ∧ connected_component g C2 ∧ C1 ≠ C2), from two_connected_components,
    -- Now, consider any nodes u ∈ CC1 and v ∈ CC2.
    -- [DHS] even given the previous axiom, we need to prove that they are non-empty as sets,
    have node_in_C1 : ∃ (u : V), u ∈ C1, from sorry,
    obtain (u : V) (u_in_C1 : u ∈ C1), from node_in_C1,
    have node_in_C2 : ∃ (v : V), v ∈ C2, from sorry,
    obtain (v : V) (v_in_C2 : v ∈ C2), from node_in_C2,
    -- Since u and v are in separate connected components, note that u ↮ v and the edge {u, v} ∉ E.
    have u_nconn_v : ¬ (u ↔ v), from sorry,
    have u_nedge_v : ¬ g (u,v), from sorry,
    -- So consider what happens when we add the edge {u, v} to the graph.
    let h : graph V := add_edge g (u,v) in
    -- Since G is maximally acyclic, this must introduce a simple cycle; call it C.
    have simple_cycle : ∃ (xs : list V), simple_cycle_pred h xs, from and.elim_right g_maximally_acyclic (u,v) u_nedge_v,
    obtain (C : list V) (C_simple_cycle : simple_cycle_pred h C), from simple_cycle,
    -- Since G is acyclic, this new cycle must use the edge {u, v}.
    -- [DHS] tricky...
    have exists_uv_in_C : ∃ (i : ℕ) (i_lt_pred : i < pred (length C)), get_edge C i = (u,v), from sorry,
    obtain (i : ℕ) (i_lt_pred : i < pred (length C)) (uv_in_C : get_edge C i = (u,v)), from exists_uv_in_C,
    -- Additionally, note that since {u, v} is an edge in the new graph, we have that u ↔ v in this new graph.
    have uv_in_h : h (u,v), from add_edge_contains g (u,v),
    have u_conn_v_in_h : connected h u v, from edge_imp_path h uv_in_h,
    -- By our earlier theorem, since in this new graph u ↔ v and C is a simple cycle, if we delete any single edge from C, it will still be the case that u ↔ v still holds.
    have still_connected : connected (remove_edge h (get_edge C i)) u v, from simple_cycle_not_fragile h C_simple_cycle u v u_conn_v_in_h i_lt_pred,
    -- In particular, this means that if we delete {u, v} from the new graph (which yields the original graph G), we should have that u ↔ v.
    have was_always_connected : connected g u v, from (remove_add g (u,v)) ▸ uv_in_C ▸ still_connected,
    -- But this is impossible, since we know that u ↮ v in the original graph.
    show false, from u_nconn_v was_always_connected
  )
  -- We have reached a contradiction, so our assumption must have been wrong. Thus if G is maximally acyclic, it must be connected.

/- [KS]
Theorem: If G is maximally acyclic, then it is minimally connected.
Proof: Let G = (V, E) be any maximally acyclic graph. By the previous lemma, G is connected. We
need to show that if we remove any edge e ∈ E from G, then G becomes disconnected. To do this, we
proceed by contradiction. Suppose that there is an edge {u, v} ∈ E such that if {u, v} is removed
from G, G remains connected. In that case, we must have that after removing {u, v} from G, there is
a simple path between u and v. This means that in the original graph G, there is a simple cycle –
namely, take the simple path from u to v, then follow the edge {u, v} from v back to u. But this is
impossible, since G is maximally acyclic and thus acyclic. We have reached a contradiction, so our
assumption must have been incorrect. Thus G is minimally connected.
-/

theorem maximally_acyclic_imp_minimally_connected : maximally_acyclic g → minimally_connected g :=
  -- Proof: Let G = (V, E) be any maximally acyclic graph.
  assume g_maximally_acyclic : maximally_acyclic g,
  -- By the previous lemma, G is connected.
  have g_connected : graph_connected g, from maximally_acyclic_imp_connected g g_maximally_acyclic,
  -- We need to show that if we remove any edge e ∈ E from G, then G becomes disconnected.
  have cannot_remove : ∀ (e : edge V), g e → ¬ graph_connected (remove_edge g e), from
  -- To do this, we proceed by contradiction.
  by_contradiction
  (
    -- Suppose that there is an edge {u, v} ∈ E such that if {u, v} is removed from G, G remains connected.
    assume not_forall_H : ¬ ∀ (e : edge V), g e → ¬ graph_connected (remove_edge g e),
    have exists_edge : ∃ (e : edge V), g e ∧ graph_connected (remove_edge g e), from sorry,
    obtain (e : edge V) (He : g e ∧ graph_connected (remove_edge g e)), from exists_edge,
    have remove_connected : graph_connected (remove_edge g e), from and.elim_right He,
    -- In that case, we must have that after removing {u, v} from G, there is a simple path between u and v.
    let u := e.1, v := e.2 in
    have u_conn_v : ∃ (xs : list V), simple_path_pred g xs ∧ head xs = u ∧ last xs = v, from sorry, --connected_simple (remove_edge g e) (remove_connected u v),
    obtain (xs : list V) (Hxs : simple_path_pred g xs ∧ head xs = u ∧ last xs = v), from u_conn_v,
    -- This means that in the original graph G, there is a simple cycle – namely, take the simple path from u to v, then follow the edge {u, v} from v back to u.
    let ys := concat u xs in
    have no_dup_all_but_last : no_dup (all_but_last ys), from (all_but_last_concat xs e.1)⁻¹ ▸ (and.elim_right (and.elim_left Hxs)),
    have ys_simple_cycle : simple_cycle_pred g ys, from sorry, -- TODO this step require a bunch of automatable reasoning
    -- But this is impossible, since G is maximally acyclic and thus acyclic.
    sorry
  ),
  -- We have reached a contradiction, so our assumption must have been incorrect. Thus G is minimally connected.
  show minimally_connected g, from and.intro g_connected cannot_remove

/- [KS]
Theorem: Let G be an undirected graph. The following are all equivalent:
1. G is minimally connected.
2. G is connected and acyclic.
3. G is maximally acyclic.
-/

end path


/-
Copyright (c) 2021 Yury G. Kudryashov. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yury G. Kudryashov

! This file was ported from Lean 3 source module number_theory.liouville.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.MeasureTheory.Measure.Lebesgue
import Mathbin.NumberTheory.Liouville.Residual
import Mathbin.NumberTheory.Liouville.LiouvilleWith
import Mathbin.Analysis.PSeries

/-!
# Volume of the set of Liouville numbers

In this file we prove that the set of Liouville numbers with exponent (irrationality measure)
strictly greater than two is a set of Lebesuge measure zero, see
`volume_Union_set_of_liouville_with`.

Since this set is a residual set, we show that the filters `residual` and `volume.ae` are disjoint.
These filters correspond to two common notions of genericity on `ℝ`: residual sets and sets of full
measure. The fact that the filters are disjoint means that two mutually exclusive properties can be
“generic” at the same time (in the sense of different “genericity” filters).

## Tags

Liouville number, Lebesgue measure, residual, generic property
-/

open Filter BigOperators ENNReal Topology NNReal

open Filter Set Metric MeasureTheory Real

theorem setOf_liouvilleWith_subset_aux :
    { x : ℝ | ∃ p > 2, LiouvilleWith p x } ⊆
      ⋃ m : ℤ,
        (fun x : ℝ => x + m) ⁻¹'
          ⋃ n > (0 : ℕ),
            { x : ℝ |
              ∃ᶠ b : ℕ in atTop,
                ∃ a ∈ Finset.Icc (0 : ℤ) b, |x - (a : ℤ) / b| < 1 / b ^ (2 + 1 / n : ℝ) } :=
  by
  rintro x ⟨p, hp, hxp⟩
  rcases exists_nat_one_div_lt (sub_pos.2 hp) with ⟨n, hn⟩
  rw [lt_sub_iff_add_lt'] at hn
  suffices
    ∀ y : ℝ,
      LiouvilleWith p y →
        y ∈ Ico (0 : ℝ) 1 →
          ∃ᶠ b : ℕ in at_top,
            ∃ a ∈ Finset.Icc (0 : ℤ) b, |y - a / b| < 1 / b ^ (2 + 1 / (n + 1 : ℕ) : ℝ)
    by
    simp only [mem_Union, mem_preimage]
    have hx : x + ↑(-⌊x⌋) ∈ Ico (0 : ℝ) 1 := by
      simp only [Int.floor_le, Int.lt_floor_add_one, add_neg_lt_iff_le_add', zero_add, and_self_iff,
        mem_Ico, Int.cast_neg, le_add_neg_iff_add_le]
    refine' ⟨-⌊x⌋, n + 1, n.succ_pos, this _ (hxp.add_int _) hx⟩
  clear hxp x
  intro x hxp hx01
  refine' ((hxp.frequently_lt_rpow_neg hn).and_eventually (eventually_ge_at_top 1)).mono _
  rintro b ⟨⟨a, hne, hlt⟩, hb⟩
  rw [rpow_neg b.cast_nonneg, ← one_div, ← Nat.cast_succ] at hlt
  refine' ⟨a, _, hlt⟩
  replace hb : (1 : ℝ) ≤ b
  exact Nat.one_le_cast.2 hb
  have hb0 : (0 : ℝ) < b := zero_lt_one.trans_le hb
  replace hlt : |x - a / b| < 1 / b
  · refine' hlt.trans_le (one_div_le_one_div_of_le hb0 _)
    calc
      (b : ℝ) = b ^ (1 : ℝ) := (rpow_one _).symm
      _ ≤ b ^ (2 + 1 / (n + 1 : ℕ) : ℝ) := rpow_le_rpow_of_exponent_le hb (one_le_two.trans _)

    simpa using n.cast_add_one_pos.le
  rw [sub_div' _ _ _ hb0.ne', abs_div, abs_of_pos hb0, div_lt_div_right hb0, abs_sub_lt_iff,
    sub_lt_iff_lt_add, sub_lt_iff_lt_add, ← sub_lt_iff_lt_add'] at hlt
  rw [Finset.mem_Icc, ← Int.lt_add_one_iff, ← Int.lt_add_one_iff, ← neg_lt_iff_pos_add, add_comm, ←
    @Int.cast_lt ℝ, ← @Int.cast_lt ℝ]
  push_cast
  refine' ⟨lt_of_le_of_lt _ hlt.1, hlt.2.trans_le _⟩
  · simp only [mul_nonneg hx01.left b.cast_nonneg, neg_le_sub_iff_le_add, le_add_iff_nonneg_left]
  · rw [add_le_add_iff_left]
    calc
      x * b ≤ 1 * b := mul_le_mul_of_nonneg_right hx01.2.le hb0.le
      _ = b := one_mul b

#align set_of_liouville_with_subset_aux setOf_liouvilleWith_subset_aux

/-- The set of numbers satisfying the Liouville condition with some exponent `p > 2` has Lebesgue
measure zero. -/
@[simp]
theorem volume_unionᵢ_setOf_liouvilleWith :
    volume (⋃ (p : ℝ) (hp : 2 < p), { x : ℝ | LiouvilleWith p x }) = 0 :=
  by
  simp only [← set_of_exists]
  refine' measure_mono_null setOf_liouvilleWith_subset_aux _
  rw [measure_Union_null_iff]
  intro m
  rw [measure_preimage_add_right]
  clear m
  refine' (measure_bUnion_null_iff <| to_countable _).2 fun n (hn : 1 ≤ n) => _
  generalize hr : (2 + 1 / n : ℝ) = r
  replace hr : 2 < r
  · simp [← hr, zero_lt_one.trans_le hn]
  clear hn n
  refine' measure_set_of_frequently_eq_zero _
  simp only [set_of_exists, ← Real.dist_eq, ← mem_ball, set_of_mem_eq]
  set B : ℤ → ℕ → Set ℝ := fun a b => ball (a / b) (1 / b ^ r)
  have hB : ∀ a b, volume (B a b) = ↑(2 / b ^ r : ℝ≥0) :=
    by
    intro a b
    rw [Real.volume_ball, mul_one_div, ← NNReal.coe_two, ← NNReal.coe_nat_cast, ← NNReal.coe_rpow, ←
      NNReal.coe_div, ENNReal.ofReal_coe_nnreal]
  have :
    ∀ b : ℕ, volume (⋃ a ∈ Finset.Icc (0 : ℤ) b, B a b) ≤ (2 * (b ^ (1 - r) + b ^ (-r)) : ℝ≥0) :=
    by
    intro b
    calc
      volume (⋃ a ∈ Finset.Icc (0 : ℤ) b, B a b) ≤ ∑ a in Finset.Icc (0 : ℤ) b, volume (B a b) :=
        measure_bUnion_finset_le _ _
      _ = ((b + 1) * (2 / b ^ r) : ℝ≥0) := by
        simp only [hB, Int.card_Icc, Finset.sum_const, nsmul_eq_mul, sub_zero, ← Int.ofNat_succ,
          Int.toNat_coe_nat, ← Nat.cast_succ, ENNReal.coe_mul, ENNReal.coe_nat]
      _ = _ := _

    have : 1 - r ≠ 0 := by linarith
    rw [ENNReal.coe_eq_coe]
    simp [add_mul, div_eq_mul_inv, NNReal.rpow_neg, NNReal.rpow_sub' _ this, mul_add, mul_left_comm]
  refine' ne_top_of_le_ne_top (ENNReal.tsum_coe_ne_top_iff_summable.2 _) (ENNReal.tsum_le_tsum this)
  refine' (Summable.add _ _).mul_left _ <;> simp only [NNReal.summable_rpow] <;> linarith
#align volume_Union_set_of_liouville_with volume_unionᵢ_setOf_liouvilleWith

theorem ae_not_liouvilleWith : ∀ᵐ x, ∀ p > (2 : ℝ), ¬LiouvilleWith p x := by
  simpa only [ae_iff, not_forall, Classical.not_not, set_of_exists] using
    volume_unionᵢ_setOf_liouvilleWith
#align ae_not_liouville_with ae_not_liouvilleWith

theorem ae_not_liouville : ∀ᵐ x, ¬Liouville x :=
  ae_not_liouvilleWith.mono fun x h₁ h₂ => h₁ 3 (by norm_num) (h₂.LiouvilleWith 3)
#align ae_not_liouville ae_not_liouville

/-- The set of Liouville numbers has Lebesgue measure zero. -/
@[simp]
theorem volume_setOf_liouville : volume { x : ℝ | Liouville x } = 0 := by
  simpa only [ae_iff, Classical.not_not] using ae_not_liouville
#align volume_set_of_liouville volume_setOf_liouville

/-- The filters `residual ℝ` and `volume.ae` are disjoint. This means that there exists a residual
set of Lebesgue measure zero (e.g., the set of Liouville numbers). -/
theorem Real.disjoint_residual_ae : Disjoint (residual ℝ) volume.ae :=
  disjoint_of_disjoint_of_mem disjoint_compl_right eventually_residual_liouville ae_not_liouville
#align real.disjoint_residual_ae Real.disjoint_residual_ae