/-
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 measure_theory.measure.outer_measure
import order.filter.countable_Inter
import data.set.accumulate

/-!
# Measure spaces

This file defines measure spaces, the almost-everywhere filter and ae_measurable functions.
See `measure_theory.measure_space` for their properties and for extended documentation.

Given a measurable space `α`, a measure on `α` is a function that sends measurable sets to the
extended nonnegative reals that satisfies the following conditions:
1. `μ ∅ = 0`;
2. `μ` is countably additive. This means that the measure of a countable union of pairwise disjoint
   sets is equal to the measure of the individual sets.

Every measure can be canonically extended to an outer measure, so that it assigns values to
all subsets, not just the measurable subsets. On the other hand, a measure that is countably
additive on measurable sets can be restricted to measurable sets to obtain a measure.
In this file a measure is defined to be an outer measure that is countably additive on
measurable sets, with the additional assumption that the outer measure is the canonical
extension of the restricted measure.

Measures on `α` form a complete lattice, and are closed under scalar multiplication with `ℝ≥0∞`.

## Implementation notes

Given `μ : measure α`, `μ s` is the value of the *outer measure* applied to `s`.
This conveniently allows us to apply the measure to sets without proving that they are measurable.
We get countable subadditivity for all sets, but only countable additivity for measurable sets.

See the documentation of `measure_theory.measure_space` for ways to construct measures and proving
that two measure are equal.

A `measure_space` is a class that is a measurable space with a canonical measure.
The measure is denoted `volume`.

This file does not import `measure_theory.measurable_space`, but only `measurable_space_def`.

## References

* <https://en.wikipedia.org/wiki/Measure_(mathematics)>
* <https://en.wikipedia.org/wiki/Almost_everywhere>

## Tags

measure, almost everywhere, measure space
-/

noncomputable theory

open classical set filter (hiding map) function measurable_space
open_locale classical topological_space big_operators filter ennreal nnreal

variables {α β γ δ ι : Type*}

namespace measure_theory

/-- A measure is defined to be an outer measure that is countably additive on
measurable sets, with the additional assumption that the outer measure is the canonical
extension of the restricted measure. -/
structure measure (α : Type*) [measurable_space α] extends outer_measure α :=
(m_Union ⦃f : ℕ → set α⦄ :
  (∀ i, measurable_set (f i)) → pairwise (disjoint on f) →
  measure_of (⋃ i, f i) = ∑' i, measure_of (f i))
(trimmed : to_outer_measure.trim = to_outer_measure)

/-- Measure projections for a measure space.

For measurable sets this returns the measure assigned by the `measure_of` field in `measure`.
But we can extend this to _all_ sets, but using the outer measure. This gives us monotonicity and
subadditivity for all sets.
-/
instance measure.has_coe_to_fun [measurable_space α] :
  has_coe_to_fun (measure α) (λ _, set α → ℝ≥0∞) :=
⟨λ m, m.to_outer_measure⟩

section

variables [measurable_space α] {μ μ₁ μ₂ : measure α} {s s₁ s₂ t : set α}

namespace measure

/-! ### General facts about measures -/

/-- Obtain a measure by giving a countably additive function that sends `∅` to `0`. -/
def of_measurable (m : Π (s : set α), measurable_set s → ℝ≥0∞)
  (m0 : m ∅ measurable_set.empty = 0)
  (mU : ∀ {{f : ℕ → set α}} (h : ∀ i, measurable_set (f i)), pairwise (disjoint on f) →
    m (⋃ i, f i) (measurable_set.Union h) = ∑' i, m (f i) (h i)) : measure α :=
{ m_Union := λ f hf hd,
  show induced_outer_measure m _ m0 (Union f) =
      ∑' i, induced_outer_measure m _ m0 (f i), begin
    rw [induced_outer_measure_eq m0 mU, mU hf hd],
    congr, funext n, rw induced_outer_measure_eq m0 mU
  end,
  trimmed :=
  show (induced_outer_measure m _ m0).trim = induced_outer_measure m _ m0, begin
    unfold outer_measure.trim,
    congr, funext s hs,
    exact induced_outer_measure_eq m0 mU hs
  end,
  ..induced_outer_measure m _ m0 }

lemma of_measurable_apply {m : Π (s : set α), measurable_set s → ℝ≥0∞}
  {m0 : m ∅ measurable_set.empty = 0}
  {mU : ∀ {{f : ℕ → set α}} (h : ∀ i, measurable_set (f i)), pairwise (disjoint on f) →
    m (⋃ i, f i) (measurable_set.Union h) = ∑' i, m (f i) (h i)}
  (s : set α) (hs : measurable_set s) : of_measurable m m0 mU s = m s hs :=
induced_outer_measure_eq m0 mU hs

lemma to_outer_measure_injective : injective (to_outer_measure : measure α → outer_measure α) :=
λ ⟨m₁, u₁, h₁⟩ ⟨m₂, u₂, h₂⟩ h, by { congr, exact h }

@[ext] lemma ext (h : ∀ s, measurable_set s → μ₁ s = μ₂ s) : μ₁ = μ₂ :=
to_outer_measure_injective $ by rw [← trimmed, outer_measure.trim_congr h, trimmed]

lemma ext_iff : μ₁ = μ₂ ↔ ∀ s, measurable_set s → μ₁ s = μ₂ s :=
⟨by { rintro rfl s hs, refl }, measure.ext⟩

end measure

@[simp] lemma coe_to_outer_measure : ⇑μ.to_outer_measure = μ := rfl

lemma to_outer_measure_apply (s : set α) : μ.to_outer_measure s = μ s := rfl

lemma measure_eq_trim (s : set α) : μ s = μ.to_outer_measure.trim s :=
by rw μ.trimmed; refl

lemma measure_eq_infi (s : set α) : μ s = ⨅ t (st : s ⊆ t) (ht : measurable_set t), μ t :=
by rw [measure_eq_trim, outer_measure.trim_eq_infi]; refl

/-- A variant of `measure_eq_infi` which has a single `infi`. This is useful when applying a
  lemma next that only works for non-empty infima, in which case you can use
  `nonempty_measurable_superset`. -/
lemma measure_eq_infi' (μ : measure α) (s : set α) :
  μ s = ⨅ t : { t // s ⊆ t ∧ measurable_set t}, μ t :=
by simp_rw [infi_subtype, infi_and, subtype.coe_mk, ← measure_eq_infi]

lemma measure_eq_induced_outer_measure :
  μ s = induced_outer_measure (λ s _, μ s) measurable_set.empty μ.empty s :=
measure_eq_trim _

lemma to_outer_measure_eq_induced_outer_measure :
  μ.to_outer_measure = induced_outer_measure (λ s _, μ s) measurable_set.empty μ.empty :=
μ.trimmed.symm

lemma measure_eq_extend (hs : measurable_set s) :
  μ s = extend (λ t (ht : measurable_set t), μ t) s :=
(extend_eq _ hs).symm

@[simp] lemma measure_empty : μ ∅ = 0 := μ.empty

lemma nonempty_of_measure_ne_zero (h : μ s ≠ 0) : s.nonempty :=
ne_empty_iff_nonempty.1 $ λ h', h $ h'.symm ▸ measure_empty

lemma measure_mono (h : s₁ ⊆ s₂) : μ s₁ ≤ μ s₂ := μ.mono h

lemma measure_mono_null (h : s₁ ⊆ s₂) (h₂ : μ s₂ = 0) : μ s₁ = 0 :=
nonpos_iff_eq_zero.1 $ h₂ ▸ measure_mono h

lemma measure_mono_top (h : s₁ ⊆ s₂) (h₁ : μ s₁ = ∞) : μ s₂ = ∞ :=
top_unique $ h₁ ▸ measure_mono h

/-- For every set there exists a measurable superset of the same measure. -/
lemma exists_measurable_superset (μ : measure α) (s : set α) :
  ∃ t, s ⊆ t ∧ measurable_set t ∧ μ t = μ s :=
by simpa only [← measure_eq_trim] using μ.to_outer_measure.exists_measurable_superset_eq_trim s

/-- For every set `s` and a countable collection of measures `μ i` there exists a measurable
superset `t ⊇ s` such that each measure `μ i` takes the same value on `s` and `t`. -/
lemma exists_measurable_superset_forall_eq {ι} [encodable ι] (μ : ι → measure α) (s : set α) :
  ∃ t, s ⊆ t ∧ measurable_set t ∧ ∀ i, μ i t = μ i s :=
by simpa only [← measure_eq_trim]
  using outer_measure.exists_measurable_superset_forall_eq_trim (λ i, (μ i).to_outer_measure) s

lemma exists_measurable_superset_of_null (h : μ s = 0) :
  ∃ t, s ⊆ t ∧ measurable_set t ∧ μ t = 0 :=
h ▸ exists_measurable_superset μ s

lemma exists_measurable_superset_iff_measure_eq_zero :
  (∃ t, s ⊆ t ∧ measurable_set t ∧ μ t = 0) ↔ μ s = 0 :=
⟨λ ⟨t, hst, _, ht⟩, measure_mono_null hst ht, exists_measurable_superset_of_null⟩

theorem measure_Union_le [encodable β] (s : β → set α) : μ (⋃ i, s i) ≤ ∑' i, μ (s i) :=
μ.to_outer_measure.Union _

lemma measure_bUnion_le {s : set β} (hs : countable s) (f : β → set α) :
  μ (⋃ b ∈ s, f b) ≤ ∑' p : s, μ (f p) :=
begin
  haveI := hs.to_encodable,
  rw [bUnion_eq_Union],
  apply measure_Union_le
end

lemma measure_bUnion_finset_le (s : finset β) (f : β → set α) :
  μ (⋃ b ∈ s, f b) ≤ ∑ p in s, μ (f p) :=
begin
  rw [← finset.sum_attach, finset.attach_eq_univ, ← tsum_fintype],
  exact measure_bUnion_le s.countable_to_set f
end

lemma measure_Union_fintype_le [fintype β] (f : β → set α) :
  μ (⋃ b, f b) ≤ ∑ p, μ (f p) :=
by { convert measure_bUnion_finset_le finset.univ f, simp }

lemma measure_bUnion_lt_top {s : set β} {f : β → set α} (hs : finite s)
  (hfin : ∀ i ∈ s, μ (f i) ≠ ∞) : μ (⋃ i ∈ s, f i) < ∞ :=
begin
  convert (measure_bUnion_finset_le hs.to_finset f).trans_lt _,
  { ext, rw [finite.mem_to_finset] },
  apply ennreal.sum_lt_top, simpa only [finite.mem_to_finset]
end

lemma measure_Union_null [encodable β] {s : β → set α} :
  (∀ i, μ (s i) = 0) → μ (⋃ i, s i) = 0 :=
μ.to_outer_measure.Union_null

@[simp] lemma measure_Union_null_iff [encodable ι] {s : ι → set α} :
  μ (⋃ i, s i) = 0 ↔ ∀ i, μ (s i) = 0 :=
⟨λ h i, measure_mono_null (subset_Union _ _) h, measure_Union_null⟩

lemma measure_bUnion_null_iff {s : set ι} (hs : countable s) {t : ι → set α} :
  μ (⋃ i ∈ s, t i) = 0 ↔ ∀ i ∈ s, μ (t i) = 0 :=
by { haveI := hs.to_encodable, rw [bUnion_eq_Union, measure_Union_null_iff, set_coe.forall], refl }

lemma measure_sUnion_null_iff {S : set (set α)} (hS : countable S) :
  μ (⋃₀ S) = 0 ↔ ∀ s ∈ S, μ s = 0 :=
by rw [sUnion_eq_bUnion, measure_bUnion_null_iff hS]

theorem measure_union_le (s₁ s₂ : set α) : μ (s₁ ∪ s₂) ≤ μ s₁ + μ s₂ :=
μ.to_outer_measure.union _ _

lemma measure_union_null : μ s₁ = 0 → μ s₂ = 0 → μ (s₁ ∪ s₂) = 0 :=
μ.to_outer_measure.union_null

lemma measure_union_null_iff : μ (s₁ ∪ s₂) = 0 ↔ μ s₁ = 0 ∧ μ s₂ = 0:=
⟨λ h, ⟨measure_mono_null (subset_union_left _ _) h, measure_mono_null (subset_union_right _ _) h⟩,
  λ h, measure_union_null h.1 h.2⟩

lemma measure_union_lt_top (hs : μ s < ∞) (ht : μ t < ∞) : μ (s ∪ t) < ∞ :=
(measure_union_le s t).trans_lt (ennreal.add_lt_top.mpr ⟨hs, ht⟩)

lemma measure_union_lt_top_iff : μ (s ∪ t) < ∞ ↔ μ s < ∞ ∧ μ t < ∞ :=
begin
  refine ⟨λ h, ⟨_, _⟩, λ h, measure_union_lt_top h.1 h.2⟩,
  { exact (measure_mono (set.subset_union_left s t)).trans_lt h, },
  { exact (measure_mono (set.subset_union_right s t)).trans_lt h, },
end

lemma measure_union_ne_top (hs : μ s ≠ ∞) (ht : μ t ≠ ∞) : μ (s ∪ t) ≠ ∞ :=
((measure_union_le s t).trans_lt (lt_top_iff_ne_top.mpr (ennreal.add_ne_top.mpr ⟨hs, ht⟩))).ne

lemma exists_measure_pos_of_not_measure_Union_null [encodable β] {s : β → set α}
  (hs : μ (⋃ n, s n) ≠ 0) : ∃ n, 0 < μ (s n) :=
begin
  by_contra, push_neg at h,
  simp_rw nonpos_iff_eq_zero at h,
  exact hs (measure_Union_null h),
end

lemma measure_inter_lt_top_of_left_ne_top (hs_finite : μ s ≠ ∞) : μ (s ∩ t) < ∞ :=
(measure_mono (set.inter_subset_left s t)).trans_lt hs_finite.lt_top

lemma measure_inter_lt_top_of_right_ne_top (ht_finite : μ t ≠ ∞) : μ (s ∩ t) < ∞ :=
inter_comm t s ▸ measure_inter_lt_top_of_left_ne_top ht_finite

lemma measure_inter_null_of_null_right (S : set α) {T : set α} (h : μ T = 0) : μ (S ∩ T) = 0 :=
measure_mono_null (inter_subset_right S T) h

lemma measure_inter_null_of_null_left {S : set α} (T : set α) (h : μ S = 0) : μ (S ∩ T) = 0 :=
measure_mono_null (inter_subset_left S T) h

/-! ### The almost everywhere filter -/

/-- The “almost everywhere” filter of co-null sets. -/
def measure.ae {α} {m : measurable_space α} (μ : measure α) : filter α :=
{ sets := {s | μ sᶜ = 0},
  univ_sets := by simp,
  inter_sets := λ s t hs ht, by simp only [compl_inter, mem_set_of_eq];
    exact measure_union_null hs ht,
  sets_of_superset := λ s t hs hst, measure_mono_null (set.compl_subset_compl.2 hst) hs }

notation `∀ᵐ` binders ` ∂` μ `, ` r:(scoped P, filter.eventually P (measure.ae μ)) := r
notation `∃ᵐ` binders ` ∂` μ `, ` r:(scoped P, filter.frequently P (measure.ae μ)) := r
notation f ` =ᵐ[`:50 μ:50 `] `:0 g:50 := f =ᶠ[measure.ae μ] g
notation f ` ≤ᵐ[`:50 μ:50 `] `:0 g:50 := f ≤ᶠ[measure.ae μ] g

lemma mem_ae_iff {s : set α} : s ∈ μ.ae ↔ μ sᶜ = 0 := iff.rfl

lemma ae_iff {p : α → Prop} : (∀ᵐ a ∂ μ, p a) ↔ μ { a | ¬ p a } = 0 := iff.rfl

lemma compl_mem_ae_iff {s : set α} : sᶜ ∈ μ.ae ↔ μ s = 0 := by simp only [mem_ae_iff, compl_compl]

lemma frequently_ae_iff {p : α → Prop} : (∃ᵐ a ∂μ, p a) ↔ μ {a | p a} ≠ 0 :=
not_congr compl_mem_ae_iff

lemma frequently_ae_mem_iff {s : set α} : (∃ᵐ a ∂μ, a ∈ s) ↔ μ s ≠ 0 :=
not_congr compl_mem_ae_iff

lemma measure_zero_iff_ae_nmem {s : set α} : μ s = 0 ↔ ∀ᵐ a ∂ μ, a ∉ s :=
compl_mem_ae_iff.symm

lemma ae_of_all {p : α → Prop} (μ : measure α) : (∀ a, p a) → ∀ᵐ a ∂ μ, p a :=
eventually_of_forall

--instance ae_is_measurably_generated : is_measurably_generated μ.ae :=
--⟨λ s hs, let ⟨t, hst, htm, htμ⟩ := exists_measurable_superset_of_null hs in
--  ⟨tᶜ, compl_mem_ae_iff.2 htμ, htm.compl, compl_subset_comm.1 hst⟩⟩

instance : countable_Inter_filter μ.ae :=
⟨begin
  intros S hSc hS,
  simp only [mem_ae_iff, compl_sInter, sUnion_image, bUnion_eq_Union] at hS ⊢,
  haveI := hSc.to_encodable,
  exact measure_Union_null (subtype.forall.2 hS)
end⟩

lemma ae_imp_iff {p : α → Prop} {q : Prop} : (∀ᵐ x ∂μ, q → p x) ↔ (q → ∀ᵐ x ∂μ, p x) :=
filter.eventually_imp_distrib_left

lemma ae_all_iff [encodable ι] {p : α → ι → Prop} :
  (∀ᵐ a ∂ μ, ∀ i, p a i) ↔ (∀ i, ∀ᵐ a ∂ μ, p a i) :=
eventually_countable_forall

lemma ae_ball_iff {S : set ι} (hS : countable S) {p : Π (x : α) (i ∈ S), Prop} :
  (∀ᵐ x ∂ μ, ∀ i ∈ S, p x i ‹_›) ↔ ∀ i ∈ S, ∀ᵐ x ∂ μ, p x i ‹_› :=
eventually_countable_ball hS

lemma ae_eq_refl (f : α → δ) : f =ᵐ[μ] f := eventually_eq.rfl

lemma ae_eq_symm {f g : α → δ} (h : f =ᵐ[μ] g) : g =ᵐ[μ] f :=
h.symm

lemma ae_eq_trans {f g h: α → δ} (h₁ : f =ᵐ[μ] g) (h₂ : g =ᵐ[μ] h) :
  f =ᵐ[μ] h :=
h₁.trans h₂

lemma ae_le_of_ae_lt {f g : α → ℝ≥0∞} (h : ∀ᵐ x ∂μ, f x < g x) : f ≤ᵐ[μ] g :=
begin
  rw [filter.eventually_le, ae_iff],
  rw ae_iff at h,
  refine measure_mono_null (λ x hx, _) h,
  exact not_lt.2 (le_of_lt (not_le.1 hx)),
end

@[simp] lemma ae_eq_empty : s =ᵐ[μ] (∅ : set α) ↔ μ s = 0 :=
eventually_eq_empty.trans $ by simp [ae_iff]

lemma ae_le_set : s ≤ᵐ[μ] t ↔ μ (s \ t) = 0 :=
calc s ≤ᵐ[μ] t ↔ ∀ᵐ x ∂μ, x ∈ s → x ∈ t : iff.rfl
           ... ↔ μ (s \ t) = 0          : by simp [ae_iff]; refl

@[simp] lemma union_ae_eq_right : (s ∪ t : set α) =ᵐ[μ] t ↔ μ (s \ t) = 0 :=
by simp [eventually_le_antisymm_iff, ae_le_set, union_diff_right,
  diff_eq_empty.2 (set.subset_union_right _ _)]

lemma diff_ae_eq_self : (s \ t : set α) =ᵐ[μ] s ↔ μ (s ∩ t) = 0 :=
by simp [eventually_le_antisymm_iff, ae_le_set, diff_diff_right,
  diff_diff, diff_eq_empty.2 (set.subset_union_right _ _)]

lemma ae_eq_set {s t : set α} :
  s =ᵐ[μ] t ↔ μ (s \ t) = 0 ∧ μ (t \ s) = 0 :=
by simp [eventually_le_antisymm_iff, ae_le_set]

@[to_additive]
lemma _root_.set.mul_indicator_ae_eq_one {M : Type*} [has_one M] {f : α → M} {s : set α}
  (h : s.mul_indicator f =ᵐ[μ] 1) : μ (s ∩ function.mul_support f) = 0 :=
begin
  rw [filter.eventually_eq, ae_iff] at h,
  convert h,
  ext a,
  rw ← set.mul_indicator_eq_one_iff,
  refl
end

/-- If `s ⊆ t` modulo a set of measure `0`, then `μ s ≤ μ t`. -/
@[mono] lemma measure_mono_ae (H : s ≤ᵐ[μ] t) : μ s ≤ μ t :=
calc μ s ≤ μ (s ∪ t)       : measure_mono $ subset_union_left s t
     ... = μ (t ∪ s \ t)   : by rw [union_diff_self, set.union_comm]
     ... ≤ μ t + μ (s \ t) : measure_union_le _ _
     ... = μ t             : by rw [ae_le_set.1 H, add_zero]

alias measure_mono_ae ← filter.eventually_le.measure_le

/-- If two sets are equal modulo a set of measure zero, then `μ s = μ t`. -/
lemma measure_congr (H : s =ᵐ[μ] t) : μ s = μ t :=
le_antisymm H.le.measure_le H.symm.le.measure_le

/-- A measurable set `t ⊇ s` such that `μ t = μ s`. It even satisifies `μ (t ∩ u) = μ (s ∩ u)` for
any measurable set `u`, see `measure_to_measurable_inter`. If `s` is a null measurable set, then
we also have `t =ᵐ[μ] s`, see `null_measurable_set.to_measurable_ae_eq`. -/
def to_measurable (μ : measure α) (s : set α) : set α :=
if h : ∃ t ⊇ s, measurable_set t ∧ t =ᵐ[μ] s then h.some
else (exists_measurable_superset μ s).some

lemma subset_to_measurable (μ : measure α) (s : set α) : s ⊆ to_measurable μ s :=
begin
  rw to_measurable, split_ifs with hs,
  exacts [hs.some_spec.fst, (exists_measurable_superset μ s).some_spec.1]
end

lemma ae_le_to_measurable : s ≤ᵐ[μ] to_measurable μ s := (subset_to_measurable _ _).eventually_le

@[simp] lemma measurable_set_to_measurable (μ : measure α) (s : set α) :
  measurable_set (to_measurable μ s) :=
begin
  rw to_measurable, split_ifs with hs,
  exacts [hs.some_spec.snd.1, (exists_measurable_superset μ s).some_spec.2.1]
end

@[simp] lemma measure_to_measurable (s : set α) : μ (to_measurable μ s) = μ s :=
begin
  rw to_measurable, split_ifs with hs,
  exacts [measure_congr hs.some_spec.snd.2, (exists_measurable_superset μ s).some_spec.2.2]
end

/-- A measure space is a measurable space equipped with a
  measure, referred to as `volume`. -/
class measure_space (α : Type*) extends measurable_space α :=
(volume : measure α)

export measure_space (volume)

/-- `volume` is the canonical  measure on `α`. -/
add_decl_doc volume

section measure_space

notation `∀ᵐ` binders `, ` r:(scoped P, filter.eventually P
  (measure_theory.measure.ae measure_theory.measure_space.volume)) := r

notation `∃ᵐ` binders `, ` r:(scoped P, filter.frequently P
  (measure_theory.measure.ae measure_theory.measure_space.volume)) := r

/-- The tactic `exact volume`, to be used in optional (`auto_param`) arguments. -/
meta def volume_tac : tactic unit := `[exact measure_theory.measure_space.volume]

end measure_space

end

end measure_theory

section
open measure_theory

/-!
# Almost everywhere measurable functions

A function is almost everywhere measurable if it coincides almost everywhere with a measurable
function. We define this property, called `ae_measurable f μ`. It's properties are discussed in
`measure_theory.measure_space`.
-/

variables {m : measurable_space α} [measurable_space β]
  {f g : α → β} {μ ν : measure α}

/-- A function is almost everywhere measurable if it coincides almost everywhere with a measurable
function. -/
def ae_measurable {m : measurable_space α} (f : α → β) (μ : measure α . measure_theory.volume_tac) :
  Prop :=
∃ g : α → β, measurable g ∧ f =ᵐ[μ] g

lemma measurable.ae_measurable (h : measurable f) : ae_measurable f μ :=
⟨f, h, ae_eq_refl f⟩

namespace ae_measurable

/-- Given an almost everywhere measurable function `f`, associate to it a measurable function
that coincides with it almost everywhere. `f` is explicit in the definition to make sure that
it shows in pretty-printing. -/
def mk (f : α → β) (h : ae_measurable f μ) : α → β := classical.some h

lemma measurable_mk (h : ae_measurable f μ) : measurable (h.mk f) :=
(classical.some_spec h).1

lemma ae_eq_mk (h : ae_measurable f μ) : f =ᵐ[μ] (h.mk f) :=
(classical.some_spec h).2

lemma congr (hf : ae_measurable f μ) (h : f =ᵐ[μ] g) : ae_measurable g μ :=
⟨hf.mk f, hf.measurable_mk, h.symm.trans hf.ae_eq_mk⟩

end ae_measurable

lemma ae_measurable_congr (h : f =ᵐ[μ] g) :
  ae_measurable f μ ↔ ae_measurable g μ :=
⟨λ hf, ae_measurable.congr hf h, λ hg, ae_measurable.congr hg h.symm⟩

@[simp] lemma ae_measurable_const {b : β} : ae_measurable (λ a : α, b) μ :=
measurable_const.ae_measurable

lemma ae_measurable_id : ae_measurable id μ := measurable_id.ae_measurable

lemma ae_measurable_id' : ae_measurable (λ x, x) μ := measurable_id.ae_measurable

lemma measurable.comp_ae_measurable [measurable_space δ] {f : α → δ} {g : δ → β}
  (hg : measurable g) (hf : ae_measurable f μ) : ae_measurable (g ∘ f) μ :=
⟨g ∘ hf.mk f, hg.comp hf.measurable_mk, eventually_eq.fun_comp hf.ae_eq_mk _⟩

end


import quant

open proof
open proof.sort proof.term
open rules
open quantRules

def u1 := atom 1
def u2 := atom 2
def x := (const 60 u1)
def f1 := const 61 (arrow u1 u1)
def t1  := const 62 u1
def t2 := const 63 u2
def p1 := const 64 (arrow u1 boolsort)

def myquant := qforall 60 (f1 • x) -- this binds the variable
def myquant2 := qforall 60 x -- this binds the variable

noncomputable lemma testInst1 : thHolds myquant → thHolds (f1 • t1) :=
assume s0 : thHolds myquant,
show thHolds (f1 • t1), from instForall t1 s0

-- does not go through since t2 has different type from x
noncomputable lemma testInst2 : thHolds myquant → thHolds (f1 • t2) :=
assume s0 : thHolds myquant,
show thHolds (f1 • t2), from instForall t2 s0


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

! This file was ported from Lean 3 source module data.finset.finsupp
! leanprover-community/mathlib commit f16e7a22e11fc09c71f25446ac1db23a24e8a0bd
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Algebra.BigOperators.Finsupp
import Mathbin.Data.Finset.Pointwise
import Mathbin.Data.Finsupp.Indicator
import Mathbin.Data.Fintype.BigOperators

/-!
# Finitely supported product of finsets

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

This file defines the finitely supported product of finsets as a `finset (ι →₀ α)`.

## Main declarations

* `finset.finsupp`: Finitely supported product of finsets. `s.finset t` is the product of the `t i`
  over all `i ∈ s`.
* `finsupp.pi`: `f.pi` is the finset of `finsupp`s whose `i`-th value lies in `f i`. This is the
  special case of `finset.finsupp` where we take the product of the `f i` over the support of `f`.

## Implementation notes

We make heavy use of the fact that `0 : finset α` is `{0}`. This scalar actions convention turns out
to be precisely what we want here too.
-/

noncomputable section

open Finsupp

open BigOperators Classical Pointwise

variable {ι α : Type _} [Zero α] {s : Finset ι} {f : ι →₀ α}

namespace Finset

#print Finset.finsupp /-
/-- Finitely supported product of finsets. -/
protected def finsupp (s : Finset ι) (t : ι → Finset α) : Finset (ι →₀ α) :=
  (s.pi t).map ⟨indicator s, indicator_injective s⟩
#align finset.finsupp Finset.finsupp
-/

#print Finset.mem_finsupp_iff /-
theorem mem_finsupp_iff {t : ι → Finset α} : f ∈ s.Finsupp t ↔ f.support ⊆ s ∧ ∀ i ∈ s, f i ∈ t i :=
  by
  refine' mem_map.trans ⟨_, _⟩
  · rintro ⟨f, hf, rfl⟩
    refine' ⟨support_indicator_subset _ _, fun i hi => _⟩
    convert mem_pi.1 hf i hi
    exact indicator_of_mem hi _
  · refine' fun h => ⟨fun i _ => f i, mem_pi.2 h.2, _⟩
    ext i
    exact ite_eq_left_iff.2 fun hi => (not_mem_support_iff.1 fun H => hi <| h.1 H).symm
#align finset.mem_finsupp_iff Finset.mem_finsupp_iff
-/

/- warning: finset.mem_finsupp_iff_of_support_subset -> Finset.mem_finsupp_iff_of_support_subset is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : Type.{u2}} [_inst_1 : Zero.{u2} α] {s : Finset.{u1} ι} {f : Finsupp.{u1, u2} ι α _inst_1} {t : Finsupp.{u1, u2} ι (Finset.{u2} α) (Finset.zero.{u2} α _inst_1)}, (HasSubset.Subset.{u1} (Finset.{u1} ι) (Finset.hasSubset.{u1} ι) (Finsupp.support.{u1, u2} ι (Finset.{u2} α) (Finset.zero.{u2} α _inst_1) t) s) -> (Iff (Membership.Mem.{max u1 u2, max u1 u2} (Finsupp.{u1, u2} ι α _inst_1) (Finset.{max u1 u2} (Finsupp.{u1, u2} ι α _inst_1)) (Finset.hasMem.{max u1 u2} (Finsupp.{u1, u2} ι α _inst_1)) f (Finset.finsupp.{u1, u2} ι α _inst_1 s (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (Finsupp.{u1, u2} ι (Finset.{u2} α) (Finset.zero.{u2} α _inst_1)) (fun (_x : Finsupp.{u1, u2} ι (Finset.{u2} α) (Finset.zero.{u2} α _inst_1)) => ι -> (Finset.{u2} α)) (Finsupp.coeFun.{u1, u2} ι (Finset.{u2} α) (Finset.zero.{u2} α _inst_1)) t))) (forall (i : ι), Membership.Mem.{u2, u2} α (Finset.{u2} α) (Finset.hasMem.{u2} α) (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (Finsupp.{u1, u2} ι α _inst_1) (fun (_x : Finsupp.{u1, u2} ι α _inst_1) => ι -> α) (Finsupp.coeFun.{u1, u2} ι α _inst_1) f i) (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (Finsupp.{u1, u2} ι (Finset.{u2} α) (Finset.zero.{u2} α _inst_1)) (fun (_x : Finsupp.{u1, u2} ι (Finset.{u2} α) (Finset.zero.{u2} α _inst_1)) => ι -> (Finset.{u2} α)) (Finsupp.coeFun.{u1, u2} ι (Finset.{u2} α) (Finset.zero.{u2} α _inst_1)) t i)))
but is expected to have type
  forall {ι : Type.{u2}} {α : Type.{u1}} [_inst_1 : Zero.{u1} α] {s : Finset.{u2} ι} {f : Finsupp.{u2, u1} ι α _inst_1} {t : Finsupp.{u2, u1} ι (Finset.{u1} α) (Finset.zero.{u1} α _inst_1)}, (HasSubset.Subset.{u2} (Finset.{u2} ι) (Finset.instHasSubsetFinset.{u2} ι) (Finsupp.support.{u2, u1} ι (Finset.{u1} α) (Finset.zero.{u1} α _inst_1) t) s) -> (Iff (Membership.mem.{max u2 u1, max u2 u1} (Finsupp.{u2, u1} ι α _inst_1) (Finset.{max u1 u2} (Finsupp.{u2, u1} ι α _inst_1)) (Finset.instMembershipFinset.{max u2 u1} (Finsupp.{u2, u1} ι α _inst_1)) f (Finset.finsupp.{u2, u1} ι α _inst_1 s (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Finsupp.{u2, u1} ι (Finset.{u1} α) (Finset.zero.{u1} α _inst_1)) ι (fun (_x : ι) => (fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : ι) => Finset.{u1} α) _x) (Finsupp.funLike.{u2, u1} ι (Finset.{u1} α) (Finset.zero.{u1} α _inst_1)) t))) (forall (i : ι), Membership.mem.{u1, u1} ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : ι) => α) i) ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : ι) => Finset.{u1} α) i) (Finset.instMembershipFinset.{u1} α) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Finsupp.{u2, u1} ι α _inst_1) ι (fun (_x : ι) => (fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : ι) => α) _x) (Finsupp.funLike.{u2, u1} ι α _inst_1) f i) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Finsupp.{u2, u1} ι (Finset.{u1} α) (Finset.zero.{u1} α _inst_1)) ι (fun (_x : ι) => (fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : ι) => Finset.{u1} α) _x) (Finsupp.funLike.{u2, u1} ι (Finset.{u1} α) (Finset.zero.{u1} α _inst_1)) t i)))
Case conversion may be inaccurate. Consider using '#align finset.mem_finsupp_iff_of_support_subset Finset.mem_finsupp_iff_of_support_subsetₓ'. -/
/-- When `t` is supported on `s`, `f ∈ s.finsupp t` precisely means that `f` is pointwise in `t`. -/
@[simp]
theorem mem_finsupp_iff_of_support_subset {t : ι →₀ Finset α} (ht : t.support ⊆ s) :
    f ∈ s.Finsupp t ↔ ∀ i, f i ∈ t i :=
  by
  refine'
    mem_finsupp_iff.trans
      (forall_and_distrib.symm.trans <|
        forall_congr' fun i =>
          ⟨fun h => _, fun h =>
            ⟨fun hi => ht <| mem_support_iff.2 fun H => mem_support_iff.1 hi _, fun _ => h⟩⟩)
  · by_cases hi : i ∈ s
    · exact h.2 hi
    · rw [not_mem_support_iff.1 (mt h.1 hi), not_mem_support_iff.1 fun H => hi <| ht H]
      exact zero_mem_zero
  · rwa [H, mem_zero] at h
#align finset.mem_finsupp_iff_of_support_subset Finset.mem_finsupp_iff_of_support_subset

/- warning: finset.card_finsupp -> Finset.card_finsupp is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : Type.{u2}} [_inst_1 : Zero.{u2} α] (s : Finset.{u1} ι) (t : ι -> (Finset.{u2} α)), Eq.{1} Nat (Finset.card.{max u1 u2} (Finsupp.{u1, u2} ι α _inst_1) (Finset.finsupp.{u1, u2} ι α _inst_1 s t)) (Finset.prod.{0, u1} Nat ι Nat.commMonoid s (fun (i : ι) => Finset.card.{u2} α (t i)))
but is expected to have type
  forall {ι : Type.{u2}} {α : Type.{u1}} [_inst_1 : Zero.{u1} α] (s : Finset.{u2} ι) (t : ι -> (Finset.{u1} α)), Eq.{1} Nat (Finset.card.{max u2 u1} (Finsupp.{u2, u1} ι α _inst_1) (Finset.finsupp.{u2, u1} ι α _inst_1 s t)) (Finset.prod.{0, u2} Nat ι Nat.commMonoid s (fun (i : ι) => Finset.card.{u1} α (t i)))
Case conversion may be inaccurate. Consider using '#align finset.card_finsupp Finset.card_finsuppₓ'. -/
@[simp]
theorem card_finsupp (s : Finset ι) (t : ι → Finset α) :
    (s.Finsupp t).card = ∏ i in s, (t i).card :=
  (card_map _).trans <| card_pi _ _
#align finset.card_finsupp Finset.card_finsupp

end Finset

open Finset

namespace Finsupp

#print Finsupp.pi /-
/-- Given a finitely supported function `f : ι →₀ finset α`, one can define the finset
`f.pi` of all finitely supported functions whose value at `i` is in `f i` for all `i`. -/
def pi (f : ι →₀ Finset α) : Finset (ι →₀ α) :=
  f.support.Finsupp f
#align finsupp.pi Finsupp.pi
-/

/- warning: finsupp.mem_pi -> Finsupp.mem_pi is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : Type.{u2}} [_inst_1 : Zero.{u2} α] {f : Finsupp.{u1, u2} ι (Finset.{u2} α) (Finset.zero.{u2} α _inst_1)} {g : Finsupp.{u1, u2} ι α _inst_1}, Iff (Membership.Mem.{max u1 u2, max u1 u2} (Finsupp.{u1, u2} ι α _inst_1) (Finset.{max u1 u2} (Finsupp.{u1, u2} ι α _inst_1)) (Finset.hasMem.{max u1 u2} (Finsupp.{u1, u2} ι α _inst_1)) g (Finsupp.pi.{u1, u2} ι α _inst_1 f)) (forall (i : ι), Membership.Mem.{u2, u2} α (Finset.{u2} α) (Finset.hasMem.{u2} α) (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (Finsupp.{u1, u2} ι α _inst_1) (fun (_x : Finsupp.{u1, u2} ι α _inst_1) => ι -> α) (Finsupp.coeFun.{u1, u2} ι α _inst_1) g i) (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (Finsupp.{u1, u2} ι (Finset.{u2} α) (Finset.zero.{u2} α _inst_1)) (fun (_x : Finsupp.{u1, u2} ι (Finset.{u2} α) (Finset.zero.{u2} α _inst_1)) => ι -> (Finset.{u2} α)) (Finsupp.coeFun.{u1, u2} ι (Finset.{u2} α) (Finset.zero.{u2} α _inst_1)) f i))
but is expected to have type
  forall {ι : Type.{u2}} {α : Type.{u1}} [_inst_1 : Zero.{u1} α] {f : Finsupp.{u2, u1} ι (Finset.{u1} α) (Finset.zero.{u1} α _inst_1)} {g : Finsupp.{u2, u1} ι α _inst_1}, Iff (Membership.mem.{max u2 u1, max u2 u1} (Finsupp.{u2, u1} ι α _inst_1) (Finset.{max u1 u2} (Finsupp.{u2, u1} ι α _inst_1)) (Finset.instMembershipFinset.{max u2 u1} (Finsupp.{u2, u1} ι α _inst_1)) g (Finsupp.pi.{u2, u1} ι α _inst_1 f)) (forall (i : ι), Membership.mem.{u1, u1} ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : ι) => α) i) ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : ι) => Finset.{u1} α) i) (Finset.instMembershipFinset.{u1} α) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Finsupp.{u2, u1} ι α _inst_1) ι (fun (_x : ι) => (fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : ι) => α) _x) (Finsupp.funLike.{u2, u1} ι α _inst_1) g i) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Finsupp.{u2, u1} ι (Finset.{u1} α) (Finset.zero.{u1} α _inst_1)) ι (fun (_x : ι) => (fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : ι) => Finset.{u1} α) _x) (Finsupp.funLike.{u2, u1} ι (Finset.{u1} α) (Finset.zero.{u1} α _inst_1)) f i))
Case conversion may be inaccurate. Consider using '#align finsupp.mem_pi Finsupp.mem_piₓ'. -/
@[simp]
theorem mem_pi {f : ι →₀ Finset α} {g : ι →₀ α} : g ∈ f.pi ↔ ∀ i, g i ∈ f i :=
  mem_finsupp_iff_of_support_subset <| Subset.refl _
#align finsupp.mem_pi Finsupp.mem_pi

/- warning: finsupp.card_pi -> Finsupp.card_pi is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : Type.{u2}} [_inst_1 : Zero.{u2} α] (f : Finsupp.{u1, u2} ι (Finset.{u2} α) (Finset.zero.{u2} α _inst_1)), Eq.{1} Nat (Finset.card.{max u1 u2} (Finsupp.{u1, u2} ι α _inst_1) (Finsupp.pi.{u1, u2} ι α _inst_1 f)) (Finsupp.prod.{u1, u2, 0} ι (Finset.{u2} α) Nat (Finset.zero.{u2} α _inst_1) Nat.commMonoid f (fun (i : ι) => (fun (a : Type) (b : Type.{u2}) [self : HasLiftT.{1, succ u2} a b] => self.0) Nat ((Finset.{u2} α) -> Nat) (HasLiftT.mk.{1, succ u2} Nat ((Finset.{u2} α) -> Nat) (CoeTCₓ.coe.{1, succ u2} Nat ((Finset.{u2} α) -> Nat) (Nat.castCoe.{u2} ((Finset.{u2} α) -> Nat) (Pi.hasNatCast.{u2, 0} (Finset.{u2} α) (fun (ᾰ : Finset.{u2} α) => Nat) (fun (a : Finset.{u2} α) => AddMonoidWithOne.toNatCast.{0} Nat (AddCommMonoidWithOne.toAddMonoidWithOne.{0} Nat (NonAssocSemiring.toAddCommMonoidWithOne.{0} Nat (Semiring.toNonAssocSemiring.{0} Nat Nat.semiring)))))))) (Finset.card.{u2} α (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (Finsupp.{u1, u2} ι (Finset.{u2} α) (Finset.zero.{u2} α _inst_1)) (fun (_x : Finsupp.{u1, u2} ι (Finset.{u2} α) (Finset.zero.{u2} α _inst_1)) => ι -> (Finset.{u2} α)) (Finsupp.coeFun.{u1, u2} ι (Finset.{u2} α) (Finset.zero.{u2} α _inst_1)) f i))))
but is expected to have type
  forall {ι : Type.{u2}} {α : Type.{u1}} [_inst_1 : Zero.{u1} α] (f : Finsupp.{u2, u1} ι (Finset.{u1} α) (Finset.zero.{u1} α _inst_1)), Eq.{1} Nat (Finset.card.{max u2 u1} (Finsupp.{u2, u1} ι α _inst_1) (Finsupp.pi.{u2, u1} ι α _inst_1 f)) (Finsupp.prod.{u2, u1, 0} ι (Finset.{u1} α) Nat (Finset.zero.{u1} α _inst_1) Nat.commMonoid f (fun (i : ι) => Nat.cast.{u1} ((Finset.{u1} α) -> Nat) (Pi.natCast.{u1, 0} (Finset.{u1} α) (fun (a._@.Mathlib.Algebra.BigOperators.Finsupp._hyg.437 : Finset.{u1} α) => Nat) (fun (a : Finset.{u1} α) => instNatCastNat)) (Finset.card.{u1} α (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Finsupp.{u2, u1} ι (Finset.{u1} α) (Finset.zero.{u1} α _inst_1)) ι (fun (_x : ι) => (fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : ι) => Finset.{u1} α) _x) (Finsupp.funLike.{u2, u1} ι (Finset.{u1} α) (Finset.zero.{u1} α _inst_1)) f i))))
Case conversion may be inaccurate. Consider using '#align finsupp.card_pi Finsupp.card_piₓ'. -/
@[simp]
theorem card_pi (f : ι →₀ Finset α) : f.pi.card = f.Prod fun i => (f i).card :=
  by
  rw [pi, card_finsupp]
  exact Finset.prod_congr rfl fun i _ => by simp only [Pi.nat_apply, Nat.cast_id]
#align finsupp.card_pi Finsupp.card_pi

end Finsupp


/-
Copyright (c) 2019 Jean Lo. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jean Lo, Yaël Dillies, Moritz Doll

! This file was ported from Lean 3 source module analysis.seminorm
! leanprover-community/mathlib commit 832a8ba8f10f11fea99367c469ff802e69a5b8ec
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Data.Real.Pointwise
import Mathbin.Analysis.Convex.Function
import Mathbin.Analysis.LocallyConvex.Basic
import Mathbin.Analysis.Normed.Group.AddTorsor

/-!
# Seminorms

This file defines seminorms.

A seminorm is a function to the reals which is positive-semidefinite, absolutely homogeneous, and
subadditive. They are closely related to convex sets and a topological vector space is locally
convex if and only if its topology is induced by a family of seminorms.

## Main declarations

For a module over a normed ring:
* `seminorm`: A function to the reals that is positive-semidefinite, absolutely homogeneous, and
  subadditive.
* `norm_seminorm 𝕜 E`: The norm on `E` as a seminorm.

## References

* [H. H. Schaefer, *Topological Vector Spaces*][schaefer1966]

## Tags

seminorm, locally convex, LCTVS
-/

open NormedField Set

open BigOperators NNReal Pointwise Topology

variable {R R' 𝕜 𝕜₂ 𝕜₃ 𝕝 E E₂ E₃ F G ι : Type _}

/-- A seminorm on a module over a normed ring is a function to the reals that is positive
semidefinite, positive homogeneous, and subadditive. -/
structure Seminorm (𝕜 : Type _) (E : Type _) [SeminormedRing 𝕜] [AddGroup E] [SMul 𝕜 E] extends
  AddGroupSeminorm E where
  smul' : ∀ (a : 𝕜) (x : E), to_fun (a • x) = ‖a‖ * to_fun x
#align seminorm Seminorm

attribute [nolint doc_blame] Seminorm.toAddGroupSeminorm

/-- `seminorm_class F 𝕜 E` states that `F` is a type of seminorms on the `𝕜`-module E.

You should extend this class when you extend `seminorm`. -/
class SeminormClass (F : Type _) (𝕜 E : outParam <| Type _) [SeminormedRing 𝕜] [AddGroup E]
  [SMul 𝕜 E] extends AddGroupSeminormClass F E ℝ where
  map_smul_eq_mul (f : F) (a : 𝕜) (x : E) : f (a • x) = ‖a‖ * f x
#align seminorm_class SeminormClass

export SeminormClass (map_smul_eq_mul)

-- `𝕜` is an `out_param`, so this is a false positive.
attribute [nolint dangerous_instance] SeminormClass.toAddGroupSeminormClass

section Of

/-- Alternative constructor for a `seminorm` on an `add_comm_group E` that is a module over a
`semi_norm_ring 𝕜`. -/
def Seminorm.of [SeminormedRing 𝕜] [AddCommGroup E] [Module 𝕜 E] (f : E → ℝ)
    (add_le : ∀ x y : E, f (x + y) ≤ f x + f y) (smul : ∀ (a : 𝕜) (x : E), f (a • x) = ‖a‖ * f x) :
    Seminorm 𝕜 E where
  toFun := f
  map_zero' := by rw [← zero_smul 𝕜 (0 : E), smul, norm_zero, MulZeroClass.zero_mul]
  add_le' := add_le
  smul' := smul
  neg' x := by rw [← neg_one_smul 𝕜, smul, norm_neg, ← smul, one_smul]
#align seminorm.of Seminorm.of

/-- Alternative constructor for a `seminorm` over a normed field `𝕜` that only assumes `f 0 = 0`
and an inequality for the scalar multiplication. -/
def Seminorm.ofSmulLe [NormedField 𝕜] [AddCommGroup E] [Module 𝕜 E] (f : E → ℝ) (map_zero : f 0 = 0)
    (add_le : ∀ x y, f (x + y) ≤ f x + f y) (smul_le : ∀ (r : 𝕜) (x), f (r • x) ≤ ‖r‖ * f x) :
    Seminorm 𝕜 E :=
  Seminorm.of f add_le fun r x =>
    by
    refine' le_antisymm (smul_le r x) _
    by_cases r = 0
    · simp [h, map_zero]
    rw [← mul_le_mul_left (inv_pos.mpr (norm_pos_iff.mpr h))]
    rw [inv_mul_cancel_left₀ (norm_ne_zero_iff.mpr h)]
    specialize smul_le r⁻¹ (r • x)
    rw [norm_inv] at smul_le
    convert smul_le
    simp [h]
#align seminorm.of_smul_le Seminorm.ofSmulLe

end Of

namespace Seminorm

section SeminormedRing

variable [SeminormedRing 𝕜]

section AddGroup

variable [AddGroup E]

section SMul

variable [SMul 𝕜 E]

instance seminormClass : SeminormClass (Seminorm 𝕜 E) 𝕜 E
    where
  coe f := f.toFun
  coe_injective' f g h := by cases f <;> cases g <;> congr
  map_zero f := f.map_zero'
  map_add_le_add f := f.add_le'
  map_neg_eq_map f := f.neg'
  map_smul_eq_mul f := f.smul'
#align seminorm.seminorm_class Seminorm.seminormClass

/-- Helper instance for when there's too many metavariables to apply `fun_like.has_coe_to_fun`. -/
instance : CoeFun (Seminorm 𝕜 E) fun _ => E → ℝ :=
  FunLike.hasCoeToFun

@[ext]
theorem ext {p q : Seminorm 𝕜 E} (h : ∀ x, (p : E → ℝ) x = q x) : p = q :=
  FunLike.ext p q h
#align seminorm.ext Seminorm.ext

instance : Zero (Seminorm 𝕜 E) :=
  ⟨{ AddGroupSeminorm.hasZero.zero with smul' := fun _ _ => (MulZeroClass.mul_zero _).symm }⟩

@[simp]
theorem coe_zero : ⇑(0 : Seminorm 𝕜 E) = 0 :=
  rfl
#align seminorm.coe_zero Seminorm.coe_zero

@[simp]
theorem zero_apply (x : E) : (0 : Seminorm 𝕜 E) x = 0 :=
  rfl
#align seminorm.zero_apply Seminorm.zero_apply

instance : Inhabited (Seminorm 𝕜 E) :=
  ⟨0⟩

variable (p : Seminorm 𝕜 E) (c : 𝕜) (x y : E) (r : ℝ)

/-- Any action on `ℝ` which factors through `ℝ≥0` applies to a seminorm. -/
instance [SMul R ℝ] [SMul R ℝ≥0] [IsScalarTower R ℝ≥0 ℝ] : SMul R (Seminorm 𝕜 E)
    where smul r p :=
    { r • p.toAddGroupSeminorm with
      toFun := fun x => r • p x
      smul' := fun _ _ =>
        by
        simp only [← smul_one_smul ℝ≥0 r (_ : ℝ), NNReal.smul_def, smul_eq_mul]
        rw [map_smul_eq_mul, mul_left_comm] }

instance [SMul R ℝ] [SMul R ℝ≥0] [IsScalarTower R ℝ≥0 ℝ] [SMul R' ℝ] [SMul R' ℝ≥0]
    [IsScalarTower R' ℝ≥0 ℝ] [SMul R R'] [IsScalarTower R R' ℝ] : IsScalarTower R R' (Seminorm 𝕜 E)
    where smul_assoc r a p := ext fun x => smul_assoc r a (p x)

theorem coe_smul [SMul R ℝ] [SMul R ℝ≥0] [IsScalarTower R ℝ≥0 ℝ] (r : R) (p : Seminorm 𝕜 E) :
    ⇑(r • p) = r • p :=
  rfl
#align seminorm.coe_smul Seminorm.coe_smul

@[simp]
theorem smul_apply [SMul R ℝ] [SMul R ℝ≥0] [IsScalarTower R ℝ≥0 ℝ] (r : R) (p : Seminorm 𝕜 E)
    (x : E) : (r • p) x = r • p x :=
  rfl
#align seminorm.smul_apply Seminorm.smul_apply

instance : Add (Seminorm 𝕜 E)
    where add p q :=
    {
      p.toAddGroupSeminorm +
        q.toAddGroupSeminorm with
      toFun := fun x => p x + q x
      smul' := fun a x => by simp only [map_smul_eq_mul, map_smul_eq_mul, mul_add] }

theorem coe_add (p q : Seminorm 𝕜 E) : ⇑(p + q) = p + q :=
  rfl
#align seminorm.coe_add Seminorm.coe_add

@[simp]
theorem add_apply (p q : Seminorm 𝕜 E) (x : E) : (p + q) x = p x + q x :=
  rfl
#align seminorm.add_apply Seminorm.add_apply

instance : AddMonoid (Seminorm 𝕜 E) :=
  FunLike.coe_injective.AddMonoid _ rfl coe_add fun p n => coe_smul n p

instance : OrderedCancelAddCommMonoid (Seminorm 𝕜 E) :=
  FunLike.coe_injective.OrderedCancelAddCommMonoid _ rfl coe_add fun p n => coe_smul n p

instance [Monoid R] [MulAction R ℝ] [SMul R ℝ≥0] [IsScalarTower R ℝ≥0 ℝ] :
    MulAction R (Seminorm 𝕜 E) :=
  FunLike.coe_injective.MulAction _ coe_smul

variable (𝕜 E)

/-- `coe_fn` as an `add_monoid_hom`. Helper definition for showing that `seminorm 𝕜 E` is
a module. -/
@[simps]
def coeFnAddMonoidHom : AddMonoidHom (Seminorm 𝕜 E) (E → ℝ) :=
  ⟨coeFn, coe_zero, coe_add⟩
#align seminorm.coe_fn_add_monoid_hom Seminorm.coeFnAddMonoidHom

theorem coeFnAddMonoidHom_injective : Function.Injective (coeFnAddMonoidHom 𝕜 E) :=
  show @Function.Injective (Seminorm 𝕜 E) (E → ℝ) coeFn from FunLike.coe_injective
#align seminorm.coe_fn_add_monoid_hom_injective Seminorm.coeFnAddMonoidHom_injective

variable {𝕜 E}

instance [Monoid R] [DistribMulAction R ℝ] [SMul R ℝ≥0] [IsScalarTower R ℝ≥0 ℝ] :
    DistribMulAction R (Seminorm 𝕜 E) :=
  (coeFnAddMonoidHom_injective 𝕜 E).DistribMulAction _ coe_smul

instance [Semiring R] [Module R ℝ] [SMul R ℝ≥0] [IsScalarTower R ℝ≥0 ℝ] : Module R (Seminorm 𝕜 E) :=
  (coeFnAddMonoidHom_injective 𝕜 E).Module R _ coe_smul

instance : Sup (Seminorm 𝕜 E)
    where sup p q :=
    {
      p.toAddGroupSeminorm ⊔ q.toAddGroupSeminorm with
      toFun := p ⊔ q
      smul' := fun x v =>
        (congr_arg₂ max (map_smul_eq_mul p x v) (map_smul_eq_mul q x v)).trans <|
          (mul_max_of_nonneg _ _ <| norm_nonneg x).symm }

@[simp]
theorem coe_sup (p q : Seminorm 𝕜 E) : ⇑(p ⊔ q) = p ⊔ q :=
  rfl
#align seminorm.coe_sup Seminorm.coe_sup

theorem sup_apply (p q : Seminorm 𝕜 E) (x : E) : (p ⊔ q) x = p x ⊔ q x :=
  rfl
#align seminorm.sup_apply Seminorm.sup_apply

theorem smul_sup [SMul R ℝ] [SMul R ℝ≥0] [IsScalarTower R ℝ≥0 ℝ] (r : R) (p q : Seminorm 𝕜 E) :
    r • (p ⊔ q) = r • p ⊔ r • q :=
  have real.smul_max : ∀ x y : ℝ, r • max x y = max (r • x) (r • y) := fun x y => by
    simpa only [← smul_eq_mul, ← NNReal.smul_def, smul_one_smul ℝ≥0 r (_ : ℝ)] using
      mul_max_of_nonneg x y (r • 1 : ℝ≥0).Prop
  ext fun x => real.smul_max _ _
#align seminorm.smul_sup Seminorm.smul_sup

instance : PartialOrder (Seminorm 𝕜 E) :=
  PartialOrder.lift _ FunLike.coe_injective

theorem le_def (p q : Seminorm 𝕜 E) : p ≤ q ↔ (p : E → ℝ) ≤ q :=
  Iff.rfl
#align seminorm.le_def Seminorm.le_def

theorem lt_def (p q : Seminorm 𝕜 E) : p < q ↔ (p : E → ℝ) < q :=
  Iff.rfl
#align seminorm.lt_def Seminorm.lt_def

instance : SemilatticeSup (Seminorm 𝕜 E) :=
  Function.Injective.semilatticeSup _ FunLike.coe_injective coe_sup

end SMul

end AddGroup

section Module

variable [SeminormedRing 𝕜₂] [SeminormedRing 𝕜₃]

variable {σ₁₂ : 𝕜 →+* 𝕜₂} [RingHomIsometric σ₁₂]

variable {σ₂₃ : 𝕜₂ →+* 𝕜₃} [RingHomIsometric σ₂₃]

variable {σ₁₃ : 𝕜 →+* 𝕜₃} [RingHomIsometric σ₁₃]

variable [AddCommGroup E] [AddCommGroup E₂] [AddCommGroup E₃]

variable [AddCommGroup F] [AddCommGroup G]

variable [Module 𝕜 E] [Module 𝕜₂ E₂] [Module 𝕜₃ E₃] [Module 𝕜 F] [Module 𝕜 G]

variable [SMul R ℝ] [SMul R ℝ≥0] [IsScalarTower R ℝ≥0 ℝ]

/-- Composition of a seminorm with a linear map is a seminorm. -/
def comp (p : Seminorm 𝕜₂ E₂) (f : E →ₛₗ[σ₁₂] E₂) : Seminorm 𝕜 E :=
  {
    p.toAddGroupSeminorm.comp
      f.toAddMonoidHom with
    toFun := fun x => p (f x)
    smul' := fun _ _ => by rw [map_smulₛₗ, map_smul_eq_mul, RingHomIsometric.is_iso] }
#align seminorm.comp Seminorm.comp

theorem coe_comp (p : Seminorm 𝕜₂ E₂) (f : E →ₛₗ[σ₁₂] E₂) : ⇑(p.comp f) = p ∘ f :=
  rfl
#align seminorm.coe_comp Seminorm.coe_comp

@[simp]
theorem comp_apply (p : Seminorm 𝕜₂ E₂) (f : E →ₛₗ[σ₁₂] E₂) (x : E) : (p.comp f) x = p (f x) :=
  rfl
#align seminorm.comp_apply Seminorm.comp_apply

@[simp]
theorem comp_id (p : Seminorm 𝕜 E) : p.comp LinearMap.id = p :=
  ext fun _ => rfl
#align seminorm.comp_id Seminorm.comp_id

@[simp]
theorem comp_zero (p : Seminorm 𝕜₂ E₂) : p.comp (0 : E →ₛₗ[σ₁₂] E₂) = 0 :=
  ext fun _ => map_zero p
#align seminorm.comp_zero Seminorm.comp_zero

@[simp]
theorem zero_comp (f : E →ₛₗ[σ₁₂] E₂) : (0 : Seminorm 𝕜₂ E₂).comp f = 0 :=
  ext fun _ => rfl
#align seminorm.zero_comp Seminorm.zero_comp

theorem comp_comp [RingHomCompTriple σ₁₂ σ₂₃ σ₁₃] (p : Seminorm 𝕜₃ E₃) (g : E₂ →ₛₗ[σ₂₃] E₃)
    (f : E →ₛₗ[σ₁₂] E₂) : p.comp (g.comp f) = (p.comp g).comp f :=
  ext fun _ => rfl
#align seminorm.comp_comp Seminorm.comp_comp

theorem add_comp (p q : Seminorm 𝕜₂ E₂) (f : E →ₛₗ[σ₁₂] E₂) :
    (p + q).comp f = p.comp f + q.comp f :=
  ext fun _ => rfl
#align seminorm.add_comp Seminorm.add_comp

theorem comp_add_le (p : Seminorm 𝕜₂ E₂) (f g : E →ₛₗ[σ₁₂] E₂) :
    p.comp (f + g) ≤ p.comp f + p.comp g := fun _ => map_add_le_add p _ _
#align seminorm.comp_add_le Seminorm.comp_add_le

theorem smul_comp (p : Seminorm 𝕜₂ E₂) (f : E →ₛₗ[σ₁₂] E₂) (c : R) :
    (c • p).comp f = c • p.comp f :=
  ext fun _ => rfl
#align seminorm.smul_comp Seminorm.smul_comp

theorem comp_mono {p q : Seminorm 𝕜₂ E₂} (f : E →ₛₗ[σ₁₂] E₂) (hp : p ≤ q) : p.comp f ≤ q.comp f :=
  fun _ => hp _
#align seminorm.comp_mono Seminorm.comp_mono

/-- The composition as an `add_monoid_hom`. -/
@[simps]
def pullback (f : E →ₛₗ[σ₁₂] E₂) : Seminorm 𝕜₂ E₂ →+ Seminorm 𝕜 E :=
  ⟨fun p => p.comp f, zero_comp f, fun p q => add_comp p q f⟩
#align seminorm.pullback Seminorm.pullback

instance : OrderBot (Seminorm 𝕜 E) :=
  ⟨0, map_nonneg⟩

@[simp]
theorem coe_bot : ⇑(⊥ : Seminorm 𝕜 E) = 0 :=
  rfl
#align seminorm.coe_bot Seminorm.coe_bot

theorem bot_eq_zero : (⊥ : Seminorm 𝕜 E) = 0 :=
  rfl
#align seminorm.bot_eq_zero Seminorm.bot_eq_zero

theorem smul_le_smul {p q : Seminorm 𝕜 E} {a b : ℝ≥0} (hpq : p ≤ q) (hab : a ≤ b) : a • p ≤ b • q :=
  by
  simp_rw [le_def, Pi.le_def, coe_smul]
  intro x
  simp_rw [Pi.smul_apply, NNReal.smul_def, smul_eq_mul]
  exact mul_le_mul hab (hpq x) (map_nonneg p x) (NNReal.coe_nonneg b)
#align seminorm.smul_le_smul Seminorm.smul_le_smul

theorem finset_sup_apply (p : ι → Seminorm 𝕜 E) (s : Finset ι) (x : E) :
    s.sup p x = ↑(s.sup fun i => ⟨p i x, map_nonneg (p i) x⟩ : ℝ≥0) :=
  by
  induction' s using Finset.cons_induction_on with a s ha ih
  ·
    rw [Finset.sup_empty, Finset.sup_empty, coe_bot, _root_.bot_eq_zero, Pi.zero_apply,
      Nonneg.coe_zero]
  ·
    rw [Finset.sup_cons, Finset.sup_cons, coe_sup, sup_eq_max, Pi.sup_apply, sup_eq_max,
      NNReal.coe_max, Subtype.coe_mk, ih]
#align seminorm.finset_sup_apply Seminorm.finset_sup_apply

theorem finset_sup_le_sum (p : ι → Seminorm 𝕜 E) (s : Finset ι) : s.sup p ≤ ∑ i in s, p i := by
  classical
    refine' finset.sup_le_iff.mpr _
    intro i hi
    rw [Finset.sum_eq_sum_diff_singleton_add hi, le_add_iff_nonneg_left]
    exact bot_le
#align seminorm.finset_sup_le_sum Seminorm.finset_sup_le_sum

theorem finset_sup_apply_le {p : ι → Seminorm 𝕜 E} {s : Finset ι} {x : E} {a : ℝ} (ha : 0 ≤ a)
    (h : ∀ i, i ∈ s → p i x ≤ a) : s.sup p x ≤ a :=
  by
  lift a to ℝ≥0 using ha
  rw [finset_sup_apply, NNReal.coe_le_coe]
  exact Finset.sup_le h
#align seminorm.finset_sup_apply_le Seminorm.finset_sup_apply_le

theorem finset_sup_apply_lt {p : ι → Seminorm 𝕜 E} {s : Finset ι} {x : E} {a : ℝ} (ha : 0 < a)
    (h : ∀ i, i ∈ s → p i x < a) : s.sup p x < a :=
  by
  lift a to ℝ≥0 using ha.le
  rw [finset_sup_apply, NNReal.coe_lt_coe, Finset.sup_lt_iff]
  · exact h
  · exact nnreal.coe_pos.mpr ha
#align seminorm.finset_sup_apply_lt Seminorm.finset_sup_apply_lt

theorem norm_sub_map_le_sub (p : Seminorm 𝕜 E) (x y : E) : ‖p x - p y‖ ≤ p (x - y) :=
  abs_sub_map_le_sub p x y
#align seminorm.norm_sub_map_le_sub Seminorm.norm_sub_map_le_sub

end Module

end SeminormedRing

section SeminormedCommRing

variable [SeminormedRing 𝕜] [SeminormedCommRing 𝕜₂]

variable {σ₁₂ : 𝕜 →+* 𝕜₂} [RingHomIsometric σ₁₂]

variable [AddCommGroup E] [AddCommGroup E₂] [Module 𝕜 E] [Module 𝕜₂ E₂]

theorem comp_smul (p : Seminorm 𝕜₂ E₂) (f : E →ₛₗ[σ₁₂] E₂) (c : 𝕜₂) :
    p.comp (c • f) = ‖c‖₊ • p.comp f :=
  ext fun _ => by
    rw [comp_apply, smul_apply, LinearMap.smul_apply, map_smul_eq_mul, NNReal.smul_def, coe_nnnorm,
      smul_eq_mul, comp_apply]
#align seminorm.comp_smul Seminorm.comp_smul

theorem comp_smul_apply (p : Seminorm 𝕜₂ E₂) (f : E →ₛₗ[σ₁₂] E₂) (c : 𝕜₂) (x : E) :
    p.comp (c • f) x = ‖c‖ * p (f x) :=
  map_smul_eq_mul p _ _
#align seminorm.comp_smul_apply Seminorm.comp_smul_apply

end SeminormedCommRing

section NormedField

variable [NormedField 𝕜] [AddCommGroup E] [Module 𝕜 E] {p q : Seminorm 𝕜 E} {x : E}

/-- Auxiliary lemma to show that the infimum of seminorms is well-defined. -/
theorem bddBelow_range_add : BddBelow (range fun u => p u + q (x - u)) :=
  ⟨0, by
    rintro _ ⟨x, rfl⟩
    dsimp
    positivity⟩
#align seminorm.bdd_below_range_add Seminorm.bddBelow_range_add

noncomputable instance : Inf (Seminorm 𝕜 E)
    where inf p q :=
    {
      p.toAddGroupSeminorm ⊓
        q.toAddGroupSeminorm with
      toFun := fun x => ⨅ u : E, p u + q (x - u)
      smul' := by
        intro a x
        obtain rfl | ha := eq_or_ne a 0
        · rw [norm_zero, MulZeroClass.zero_mul, zero_smul]
          refine'
            cinfᵢ_eq_of_forall_ge_of_forall_gt_exists_lt (fun i => by positivity) fun x hx =>
              ⟨0, by rwa [map_zero, sub_zero, map_zero, add_zero]⟩
        simp_rw [Real.mul_infᵢ_of_nonneg (norm_nonneg a), mul_add, ← map_smul_eq_mul p, ←
          map_smul_eq_mul q, smul_sub]
        refine'
          Function.Surjective.infᵢ_congr ((· • ·) a⁻¹ : E → E)
            (fun u => ⟨a • u, inv_smul_smul₀ ha u⟩) fun u => _
        rw [smul_inv_smul₀ ha] }

@[simp]
theorem inf_apply (p q : Seminorm 𝕜 E) (x : E) : (p ⊓ q) x = ⨅ u : E, p u + q (x - u) :=
  rfl
#align seminorm.inf_apply Seminorm.inf_apply

noncomputable instance : Lattice (Seminorm 𝕜 E) :=
  { Seminorm.semilatticeSup with
    inf := (· ⊓ ·)
    inf_le_left := fun p q x =>
      cinfᵢ_le_of_le bddBelow_range_add x <| by simp only [sub_self, map_zero, add_zero]
    inf_le_right := fun p q x =>
      cinfᵢ_le_of_le bddBelow_range_add 0 <| by simp only [sub_self, map_zero, zero_add, sub_zero]
    le_inf := fun a b c hab hac x =>
      le_cinfᵢ fun u => (le_map_add_map_sub a _ _).trans <| add_le_add (hab _) (hac _) }

theorem smul_inf [SMul R ℝ] [SMul R ℝ≥0] [IsScalarTower R ℝ≥0 ℝ] (r : R) (p q : Seminorm 𝕜 E) :
    r • (p ⊓ q) = r • p ⊓ r • q := by
  ext
  simp_rw [smul_apply, inf_apply, smul_apply, ← smul_one_smul ℝ≥0 r (_ : ℝ), NNReal.smul_def,
    smul_eq_mul, Real.mul_infᵢ_of_nonneg (Subtype.prop _), mul_add]
#align seminorm.smul_inf Seminorm.smul_inf

section Classical

open Classical

/- ./././Mathport/Syntax/Translate/Tactic/Builtin.lean:73:14: unsupported tactic `congrm #[[expr «expr⨆ , »((i), _)]] -/
/- ./././Mathport/Syntax/Translate/Tactic/Builtin.lean:73:14: unsupported tactic `congrm #[[expr «expr⨆ , »((i), _)]] -/
/- ./././Mathport/Syntax/Translate/Tactic/Builtin.lean:73:14: unsupported tactic `congrm #[[expr «expr⨆ , »((i), _)]] -/
/-- We define the supremum of an arbitrary subset of `seminorm 𝕜 E` as follows:
* if `s` is `bdd_above` *as a set of functions `E → ℝ`* (that is, if `s` is pointwise bounded
above), we take the pointwise supremum of all elements of `s`, and we prove that it is indeed a
seminorm.
* otherwise, we take the zero seminorm `⊥`.

There are two things worth mentionning here:
* First, it is not trivial at first that `s` being bounded above *by a function* implies
being bounded above *as a seminorm*. We show this in `seminorm.bdd_above_iff` by using
that the `Sup s` as defined here is then a bounding seminorm for `s`. So it is important to make
the case disjunction on `bdd_above (coe_fn '' s : set (E → ℝ))` and not `bdd_above s`.
* Since the pointwise `Sup` already gives `0` at points where a family of functions is
not bounded above, one could hope that just using the pointwise `Sup` would work here, without the
need for an additional case disjunction. As discussed on Zulip, this doesn't work because this can
give a function which does *not* satisfy the seminorm axioms (typically sub-additivity).
-/
noncomputable instance : SupSet (Seminorm 𝕜 E)
    where supₛ s :=
    if h : BddAbove (coeFn '' s : Set (E → ℝ)) then
      { toFun := ⨆ p : s, ((p : Seminorm 𝕜 E) : E → ℝ)
        map_zero' := by
          rw [supᵢ_apply, ← @Real.csupᵢ_const_zero s]
          trace
            "./././Mathport/Syntax/Translate/Tactic/Builtin.lean:73:14: unsupported tactic `congrm #[[expr «expr⨆ , »((i), _)]]"
          exact map_zero i.1
        add_le' := fun x y => by
          rcases h with ⟨q, hq⟩
          obtain rfl | h := s.eq_empty_or_nonempty
          · simp [Real.csupᵢ_empty]
          haveI : Nonempty ↥s := h.coe_sort
          simp only [supᵢ_apply]
          refine'
                csupᵢ_le fun i =>
                  ((i : Seminorm 𝕜 E).add_le' x y).trans <|
                    add_le_add (le_csupᵢ ⟨q x, _⟩ i) (le_csupᵢ ⟨q y, _⟩ i) <;>
              rw [mem_upperBounds, forall_range_iff] <;>
            exact fun j => hq (mem_image_of_mem _ j.2) _
        neg' := fun x => by
          simp only [supᵢ_apply]
          trace
            "./././Mathport/Syntax/Translate/Tactic/Builtin.lean:73:14: unsupported tactic `congrm #[[expr «expr⨆ , »((i), _)]]"
          exact i.1.neg' _
        smul' := fun a x => by
          simp only [supᵢ_apply]
          rw [← smul_eq_mul,
            Real.smul_supᵢ_of_nonneg (norm_nonneg a) fun i : s => (i : Seminorm 𝕜 E) x]
          trace
            "./././Mathport/Syntax/Translate/Tactic/Builtin.lean:73:14: unsupported tactic `congrm #[[expr «expr⨆ , »((i), _)]]"
          exact i.1.smul' a x }
    else ⊥

protected theorem coe_supₛ_eq' {s : Set <| Seminorm 𝕜 E}
    (hs : BddAbove (coeFn '' s : Set (E → ℝ))) : coeFn (supₛ s) = ⨆ p : s, p :=
  congr_arg _ (dif_pos hs)
#align seminorm.coe_Sup_eq' Seminorm.coe_supₛ_eq'

protected theorem bddAbove_iff {s : Set <| Seminorm 𝕜 E} :
    BddAbove s ↔ BddAbove (coeFn '' s : Set (E → ℝ)) :=
  ⟨fun ⟨q, hq⟩ => ⟨q, ball_image_of_ball fun p hp => hq hp⟩, fun H =>
    ⟨supₛ s, fun p hp x => by
      rw [Seminorm.coe_supₛ_eq' H, supᵢ_apply]
      rcases H with ⟨q, hq⟩
      exact
        le_csupᵢ ⟨q x, forall_range_iff.mpr fun i : s => hq (mem_image_of_mem _ i.2) x⟩ ⟨p, hp⟩⟩⟩
#align seminorm.bdd_above_iff Seminorm.bddAbove_iff

protected theorem coe_supₛ_eq {s : Set <| Seminorm 𝕜 E} (hs : BddAbove s) :
    coeFn (supₛ s) = ⨆ p : s, p :=
  Seminorm.coe_supₛ_eq' (Seminorm.bddAbove_iff.mp hs)
#align seminorm.coe_Sup_eq Seminorm.coe_supₛ_eq

protected theorem coe_supᵢ_eq {ι : Type _} {p : ι → Seminorm 𝕜 E} (hp : BddAbove (range p)) :
    coeFn (⨆ i, p i) = ⨆ i, p i := by
  rw [← supₛ_range, Seminorm.coe_supₛ_eq hp] <;> exact supᵢ_range' (coeFn : Seminorm 𝕜 E → E → ℝ) p
#align seminorm.coe_supr_eq Seminorm.coe_supᵢ_eq

private theorem seminorm.is_lub_Sup (s : Set (Seminorm 𝕜 E)) (hs₁ : BddAbove s) (hs₂ : s.Nonempty) :
    IsLUB s (supₛ s) :=
  by
  refine' ⟨fun p hp x => _, fun p hp x => _⟩ <;> haveI : Nonempty ↥s := hs₂.coe_sort <;>
    rw [Seminorm.coe_supₛ_eq hs₁, supᵢ_apply]
  · rcases hs₁ with ⟨q, hq⟩
    exact le_csupᵢ ⟨q x, forall_range_iff.mpr fun i : s => hq i.2 x⟩ ⟨p, hp⟩
  · exact csupᵢ_le fun q => hp q.2 x
#align seminorm.seminorm.is_lub_Sup seminorm.seminorm.is_lub_Sup

/-- `seminorm 𝕜 E` is a conditionally complete lattice.

Note that, while `inf`, `sup` and `Sup` have good definitional properties (corresponding to
`seminorm.has_inf`, `seminorm.has_sup` and `seminorm.has_Sup` respectively), `Inf s` is just
defined as the supremum of the lower bounds of `s`, which is not really useful in practice. If you
need to use `Inf` on seminorms, then you should probably provide a more workable definition first,
but this is unlikely to happen so we keep the "bad" definition for now. -/
noncomputable instance : ConditionallyCompleteLattice (Seminorm 𝕜 E) :=
  conditionallyCompleteLatticeOfLatticeOfSupₛ (Seminorm 𝕜 E) Seminorm.isLUB_supₛ

end Classical

end NormedField

/-! ### Seminorm ball -/

section SeminormedRing

variable [SeminormedRing 𝕜]

section AddCommGroup

variable [AddCommGroup E]

section SMul

variable [SMul 𝕜 E] (p : Seminorm 𝕜 E)

/-- The ball of radius `r` at `x` with respect to seminorm `p` is the set of elements `y` with
`p (y - x) < r`. -/
def ball (x : E) (r : ℝ) :=
  { y : E | p (y - x) < r }
#align seminorm.ball Seminorm.ball

/-- The closed ball of radius `r` at `x` with respect to seminorm `p` is the set of elements `y`
with `p (y - x) ≤ r`. -/
def closedBall (x : E) (r : ℝ) :=
  { y : E | p (y - x) ≤ r }
#align seminorm.closed_ball Seminorm.closedBall

variable {x y : E} {r : ℝ}

@[simp]
theorem mem_ball : y ∈ ball p x r ↔ p (y - x) < r :=
  Iff.rfl
#align seminorm.mem_ball Seminorm.mem_ball

@[simp]
theorem mem_closedBall : y ∈ closedBall p x r ↔ p (y - x) ≤ r :=
  Iff.rfl
#align seminorm.mem_closed_ball Seminorm.mem_closedBall

theorem mem_ball_self (hr : 0 < r) : x ∈ ball p x r := by simp [hr]
#align seminorm.mem_ball_self Seminorm.mem_ball_self

theorem mem_closedBall_self (hr : 0 ≤ r) : x ∈ closedBall p x r := by simp [hr]
#align seminorm.mem_closed_ball_self Seminorm.mem_closedBall_self

theorem mem_ball_zero : y ∈ ball p 0 r ↔ p y < r := by rw [mem_ball, sub_zero]
#align seminorm.mem_ball_zero Seminorm.mem_ball_zero

theorem mem_closedBall_zero : y ∈ closedBall p 0 r ↔ p y ≤ r := by rw [mem_closed_ball, sub_zero]
#align seminorm.mem_closed_ball_zero Seminorm.mem_closedBall_zero

theorem ball_zero_eq : ball p 0 r = { y : E | p y < r } :=
  Set.ext fun x => p.mem_ball_zero
#align seminorm.ball_zero_eq Seminorm.ball_zero_eq

theorem closedBall_zero_eq : closedBall p 0 r = { y : E | p y ≤ r } :=
  Set.ext fun x => p.mem_closedBall_zero
#align seminorm.closed_ball_zero_eq Seminorm.closedBall_zero_eq

theorem ball_subset_closedBall (x r) : ball p x r ⊆ closedBall p x r := fun y (hy : _ < _) => hy.le
#align seminorm.ball_subset_closed_ball Seminorm.ball_subset_closedBall

theorem closedBall_eq_bInter_ball (x r) : closedBall p x r = ⋂ ρ > r, ball p x ρ := by
  ext y <;> simp_rw [mem_closed_ball, mem_Inter₂, mem_ball, ← forall_lt_iff_le']
#align seminorm.closed_ball_eq_bInter_ball Seminorm.closedBall_eq_bInter_ball

@[simp]
theorem ball_zero' (x : E) (hr : 0 < r) : ball (0 : Seminorm 𝕜 E) x r = Set.univ :=
  by
  rw [Set.eq_univ_iff_forall, ball]
  simp [hr]
#align seminorm.ball_zero' Seminorm.ball_zero'

@[simp]
theorem closedBall_zero' (x : E) (hr : 0 < r) : closedBall (0 : Seminorm 𝕜 E) x r = Set.univ :=
  eq_univ_of_subset (ball_subset_closedBall _ _ _) (ball_zero' x hr)
#align seminorm.closed_ball_zero' Seminorm.closedBall_zero'

theorem ball_smul (p : Seminorm 𝕜 E) {c : NNReal} (hc : 0 < c) (r : ℝ) (x : E) :
    (c • p).ball x r = p.ball x (r / c) := by
  ext
  rw [mem_ball, mem_ball, smul_apply, NNReal.smul_def, smul_eq_mul, mul_comm,
    lt_div_iff (nnreal.coe_pos.mpr hc)]
#align seminorm.ball_smul Seminorm.ball_smul

theorem closedBall_smul (p : Seminorm 𝕜 E) {c : NNReal} (hc : 0 < c) (r : ℝ) (x : E) :
    (c • p).closedBall x r = p.closedBall x (r / c) :=
  by
  ext
  rw [mem_closed_ball, mem_closed_ball, smul_apply, NNReal.smul_def, smul_eq_mul, mul_comm,
    le_div_iff (nnreal.coe_pos.mpr hc)]
#align seminorm.closed_ball_smul Seminorm.closedBall_smul

theorem ball_sup (p : Seminorm 𝕜 E) (q : Seminorm 𝕜 E) (e : E) (r : ℝ) :
    ball (p ⊔ q) e r = ball p e r ∩ ball q e r := by
  simp_rw [ball, ← Set.setOf_and, coe_sup, Pi.sup_apply, sup_lt_iff]
#align seminorm.ball_sup Seminorm.ball_sup

theorem closedBall_sup (p : Seminorm 𝕜 E) (q : Seminorm 𝕜 E) (e : E) (r : ℝ) :
    closedBall (p ⊔ q) e r = closedBall p e r ∩ closedBall q e r := by
  simp_rw [closed_ball, ← Set.setOf_and, coe_sup, Pi.sup_apply, sup_le_iff]
#align seminorm.closed_ball_sup Seminorm.closedBall_sup

theorem ball_finset_sup' (p : ι → Seminorm 𝕜 E) (s : Finset ι) (H : s.Nonempty) (e : E) (r : ℝ) :
    ball (s.sup' H p) e r = s.inf' H fun i => ball (p i) e r :=
  by
  induction' H using Finset.Nonempty.cons_induction with a a s ha hs ih
  · classical simp
  · rw [Finset.sup'_cons hs, Finset.inf'_cons hs, ball_sup, inf_eq_inter, ih]
#align seminorm.ball_finset_sup' Seminorm.ball_finset_sup'

theorem closedBall_finset_sup' (p : ι → Seminorm 𝕜 E) (s : Finset ι) (H : s.Nonempty) (e : E)
    (r : ℝ) : closedBall (s.sup' H p) e r = s.inf' H fun i => closedBall (p i) e r :=
  by
  induction' H using Finset.Nonempty.cons_induction with a a s ha hs ih
  · classical simp
  · rw [Finset.sup'_cons hs, Finset.inf'_cons hs, closed_ball_sup, inf_eq_inter, ih]
#align seminorm.closed_ball_finset_sup' Seminorm.closedBall_finset_sup'

theorem ball_mono {p : Seminorm 𝕜 E} {r₁ r₂ : ℝ} (h : r₁ ≤ r₂) : p.ball x r₁ ⊆ p.ball x r₂ :=
  fun _ (hx : _ < _) => hx.trans_le h
#align seminorm.ball_mono Seminorm.ball_mono

theorem closedBall_mono {p : Seminorm 𝕜 E} {r₁ r₂ : ℝ} (h : r₁ ≤ r₂) :
    p.closedBall x r₁ ⊆ p.closedBall x r₂ := fun _ (hx : _ ≤ _) => hx.trans h
#align seminorm.closed_ball_mono Seminorm.closedBall_mono

theorem ball_antitone {p q : Seminorm 𝕜 E} (h : q ≤ p) : p.ball x r ⊆ q.ball x r := fun _ =>
  (h _).trans_lt
#align seminorm.ball_antitone Seminorm.ball_antitone

theorem closedBall_antitone {p q : Seminorm 𝕜 E} (h : q ≤ p) :
    p.closedBall x r ⊆ q.closedBall x r := fun _ => (h _).trans
#align seminorm.closed_ball_antitone Seminorm.closedBall_antitone

theorem ball_add_ball_subset (p : Seminorm 𝕜 E) (r₁ r₂ : ℝ) (x₁ x₂ : E) :
    p.ball (x₁ : E) r₁ + p.ball (x₂ : E) r₂ ⊆ p.ball (x₁ + x₂) (r₁ + r₂) :=
  by
  rintro x ⟨y₁, y₂, hy₁, hy₂, rfl⟩
  rw [mem_ball, add_sub_add_comm]
  exact (map_add_le_add p _ _).trans_lt (add_lt_add hy₁ hy₂)
#align seminorm.ball_add_ball_subset Seminorm.ball_add_ball_subset

theorem closedBall_add_closedBall_subset (p : Seminorm 𝕜 E) (r₁ r₂ : ℝ) (x₁ x₂ : E) :
    p.closedBall (x₁ : E) r₁ + p.closedBall (x₂ : E) r₂ ⊆ p.closedBall (x₁ + x₂) (r₁ + r₂) :=
  by
  rintro x ⟨y₁, y₂, hy₁, hy₂, rfl⟩
  rw [mem_closed_ball, add_sub_add_comm]
  exact (map_add_le_add p _ _).trans (add_le_add hy₁ hy₂)
#align seminorm.closed_ball_add_closed_ball_subset Seminorm.closedBall_add_closedBall_subset

theorem sub_mem_ball (p : Seminorm 𝕜 E) (x₁ x₂ y : E) (r : ℝ) :
    x₁ - x₂ ∈ p.ball y r ↔ x₁ ∈ p.ball (x₂ + y) r := by simp_rw [mem_ball, sub_sub]
#align seminorm.sub_mem_ball Seminorm.sub_mem_ball

/-- The image of a ball under addition with a singleton is another ball. -/
theorem vadd_ball (p : Seminorm 𝕜 E) : x +ᵥ p.ball y r = p.ball (x +ᵥ y) r :=
  letI := AddGroupSeminorm.toSeminormedAddCommGroup p.to_add_group_seminorm
  Metric.vadd_ball x y r
#align seminorm.vadd_ball Seminorm.vadd_ball

/-- The image of a closed ball under addition with a singleton is another closed ball. -/
theorem vadd_closedBall (p : Seminorm 𝕜 E) : x +ᵥ p.closedBall y r = p.closedBall (x +ᵥ y) r :=
  letI := AddGroupSeminorm.toSeminormedAddCommGroup p.to_add_group_seminorm
  Metric.vadd_closedBall x y r
#align seminorm.vadd_closed_ball Seminorm.vadd_closedBall

end SMul

section Module

variable [Module 𝕜 E]

variable [SeminormedRing 𝕜₂] [AddCommGroup E₂] [Module 𝕜₂ E₂]

variable {σ₁₂ : 𝕜 →+* 𝕜₂} [RingHomIsometric σ₁₂]

theorem ball_comp (p : Seminorm 𝕜₂ E₂) (f : E →ₛₗ[σ₁₂] E₂) (x : E) (r : ℝ) :
    (p.comp f).ball x r = f ⁻¹' p.ball (f x) r :=
  by
  ext
  simp_rw [ball, mem_preimage, comp_apply, Set.mem_setOf_eq, map_sub]
#align seminorm.ball_comp Seminorm.ball_comp

theorem closedBall_comp (p : Seminorm 𝕜₂ E₂) (f : E →ₛₗ[σ₁₂] E₂) (x : E) (r : ℝ) :
    (p.comp f).closedBall x r = f ⁻¹' p.closedBall (f x) r :=
  by
  ext
  simp_rw [closed_ball, mem_preimage, comp_apply, Set.mem_setOf_eq, map_sub]
#align seminorm.closed_ball_comp Seminorm.closedBall_comp

variable (p : Seminorm 𝕜 E)

theorem preimage_metric_ball {r : ℝ} : p ⁻¹' Metric.ball 0 r = { x | p x < r } :=
  by
  ext x
  simp only [mem_set_of, mem_preimage, mem_ball_zero_iff, Real.norm_of_nonneg (map_nonneg p _)]
#align seminorm.preimage_metric_ball Seminorm.preimage_metric_ball

theorem preimage_metric_closedBall {r : ℝ} : p ⁻¹' Metric.closedBall 0 r = { x | p x ≤ r } :=
  by
  ext x
  simp only [mem_set_of, mem_preimage, mem_closedBall_zero_iff,
    Real.norm_of_nonneg (map_nonneg p _)]
#align seminorm.preimage_metric_closed_ball Seminorm.preimage_metric_closedBall

theorem ball_zero_eq_preimage_ball {r : ℝ} : p.ball 0 r = p ⁻¹' Metric.ball 0 r := by
  rw [ball_zero_eq, preimage_metric_ball]
#align seminorm.ball_zero_eq_preimage_ball Seminorm.ball_zero_eq_preimage_ball

theorem closedBall_zero_eq_preimage_closedBall {r : ℝ} :
    p.closedBall 0 r = p ⁻¹' Metric.closedBall 0 r := by
  rw [closed_ball_zero_eq, preimage_metric_closed_ball]
#align seminorm.closed_ball_zero_eq_preimage_closed_ball Seminorm.closedBall_zero_eq_preimage_closedBall

@[simp]
theorem ball_bot {r : ℝ} (x : E) (hr : 0 < r) : ball (⊥ : Seminorm 𝕜 E) x r = Set.univ :=
  ball_zero' x hr
#align seminorm.ball_bot Seminorm.ball_bot

@[simp]
theorem closedBall_bot {r : ℝ} (x : E) (hr : 0 < r) :
    closedBall (⊥ : Seminorm 𝕜 E) x r = Set.univ :=
  closedBall_zero' x hr
#align seminorm.closed_ball_bot Seminorm.closedBall_bot

/-- Seminorm-balls at the origin are balanced. -/
theorem balanced_ball_zero (r : ℝ) : Balanced 𝕜 (ball p 0 r) :=
  by
  rintro a ha x ⟨y, hy, hx⟩
  rw [mem_ball_zero, ← hx, map_smul_eq_mul]
  calc
    _ ≤ p y := mul_le_of_le_one_left (map_nonneg p _) ha
    _ < r := by rwa [mem_ball_zero] at hy

#align seminorm.balanced_ball_zero Seminorm.balanced_ball_zero

/-- Closed seminorm-balls at the origin are balanced. -/
theorem balanced_closedBall_zero (r : ℝ) : Balanced 𝕜 (closedBall p 0 r) :=
  by
  rintro a ha x ⟨y, hy, hx⟩
  rw [mem_closed_ball_zero, ← hx, map_smul_eq_mul]
  calc
    _ ≤ p y := mul_le_of_le_one_left (map_nonneg p _) ha
    _ ≤ r := by rwa [mem_closed_ball_zero] at hy

#align seminorm.balanced_closed_ball_zero Seminorm.balanced_closedBall_zero

theorem ball_finset_sup_eq_interᵢ (p : ι → Seminorm 𝕜 E) (s : Finset ι) (x : E) {r : ℝ}
    (hr : 0 < r) : ball (s.sup p) x r = ⋂ i ∈ s, ball (p i) x r :=
  by
  lift r to NNReal using hr.le
  simp_rw [ball, Inter_set_of, finset_sup_apply, NNReal.coe_lt_coe,
    Finset.sup_lt_iff (show ⊥ < r from hr), ← NNReal.coe_lt_coe, Subtype.coe_mk]
#align seminorm.ball_finset_sup_eq_Inter Seminorm.ball_finset_sup_eq_interᵢ

theorem closedBall_finset_sup_eq_interᵢ (p : ι → Seminorm 𝕜 E) (s : Finset ι) (x : E) {r : ℝ}
    (hr : 0 ≤ r) : closedBall (s.sup p) x r = ⋂ i ∈ s, closedBall (p i) x r :=
  by
  lift r to NNReal using hr
  simp_rw [closed_ball, Inter_set_of, finset_sup_apply, NNReal.coe_le_coe, Finset.sup_le_iff, ←
    NNReal.coe_le_coe, Subtype.coe_mk]
#align seminorm.closed_ball_finset_sup_eq_Inter Seminorm.closedBall_finset_sup_eq_interᵢ

theorem ball_finset_sup (p : ι → Seminorm 𝕜 E) (s : Finset ι) (x : E) {r : ℝ} (hr : 0 < r) :
    ball (s.sup p) x r = s.inf fun i => ball (p i) x r :=
  by
  rw [Finset.inf_eq_infᵢ]
  exact ball_finset_sup_eq_Inter _ _ _ hr
#align seminorm.ball_finset_sup Seminorm.ball_finset_sup

theorem closedBall_finset_sup (p : ι → Seminorm 𝕜 E) (s : Finset ι) (x : E) {r : ℝ} (hr : 0 ≤ r) :
    closedBall (s.sup p) x r = s.inf fun i => closedBall (p i) x r :=
  by
  rw [Finset.inf_eq_infᵢ]
  exact closed_ball_finset_sup_eq_Inter _ _ _ hr
#align seminorm.closed_ball_finset_sup Seminorm.closedBall_finset_sup

theorem ball_smul_ball (p : Seminorm 𝕜 E) (r₁ r₂ : ℝ) :
    Metric.ball (0 : 𝕜) r₁ • p.ball 0 r₂ ⊆ p.ball 0 (r₁ * r₂) :=
  by
  rw [Set.subset_def]
  intro x hx
  rw [Set.mem_smul] at hx
  rcases hx with ⟨a, y, ha, hy, hx⟩
  rw [← hx, mem_ball_zero, map_smul_eq_mul]
  exact
    mul_lt_mul'' (mem_ball_zero_iff.mp ha) (p.mem_ball_zero.mp hy) (norm_nonneg a) (map_nonneg p y)
#align seminorm.ball_smul_ball Seminorm.ball_smul_ball

theorem closedBall_smul_closedBall (p : Seminorm 𝕜 E) (r₁ r₂ : ℝ) :
    Metric.closedBall (0 : 𝕜) r₁ • p.closedBall 0 r₂ ⊆ p.closedBall 0 (r₁ * r₂) :=
  by
  rw [Set.subset_def]
  intro x hx
  rw [Set.mem_smul] at hx
  rcases hx with ⟨a, y, ha, hy, hx⟩
  rw [← hx, mem_closed_ball_zero, map_smul_eq_mul]
  rw [mem_closedBall_zero_iff] at ha
  exact mul_le_mul ha (p.mem_closed_ball_zero.mp hy) (map_nonneg _ y) ((norm_nonneg a).trans ha)
#align seminorm.closed_ball_smul_closed_ball Seminorm.closedBall_smul_closedBall

@[simp]
theorem ball_eq_emptyset (p : Seminorm 𝕜 E) {x : E} {r : ℝ} (hr : r ≤ 0) : p.ball x r = ∅ :=
  by
  ext
  rw [Seminorm.mem_ball, Set.mem_empty_iff_false, iff_false_iff, not_lt]
  exact hr.trans (map_nonneg p _)
#align seminorm.ball_eq_emptyset Seminorm.ball_eq_emptyset

@[simp]
theorem closedBall_eq_emptyset (p : Seminorm 𝕜 E) {x : E} {r : ℝ} (hr : r < 0) :
    p.closedBall x r = ∅ := by
  ext
  rw [Seminorm.mem_closedBall, Set.mem_empty_iff_false, iff_false_iff, not_le]
  exact hr.trans_le (map_nonneg _ _)
#align seminorm.closed_ball_eq_emptyset Seminorm.closedBall_eq_emptyset

end Module

end AddCommGroup

end SeminormedRing

section NormedField

variable [NormedField 𝕜] [AddCommGroup E] [Module 𝕜 E] (p : Seminorm 𝕜 E) {A B : Set E} {a : 𝕜}
  {r : ℝ} {x : E}

theorem ball_norm_mul_subset {p : Seminorm 𝕜 E} {k : 𝕜} {r : ℝ} :
    p.ball 0 (‖k‖ * r) ⊆ k • p.ball 0 r :=
  by
  rcases eq_or_ne k 0 with (rfl | hk)
  · rw [norm_zero, MulZeroClass.zero_mul, ball_eq_emptyset _ le_rfl]
    exact empty_subset _
  · intro x
    rw [Set.mem_smul_set, Seminorm.mem_ball_zero]
    refine' fun hx => ⟨k⁻¹ • x, _, _⟩
    ·
      rwa [Seminorm.mem_ball_zero, map_smul_eq_mul, norm_inv, ←
        mul_lt_mul_left <| norm_pos_iff.mpr hk, ← mul_assoc, ← div_eq_mul_inv ‖k‖ ‖k‖,
        div_self (ne_of_gt <| norm_pos_iff.mpr hk), one_mul]
    rw [← smul_assoc, smul_eq_mul, ← div_eq_mul_inv, div_self hk, one_smul]
#align seminorm.ball_norm_mul_subset Seminorm.ball_norm_mul_subset

theorem smul_ball_zero {p : Seminorm 𝕜 E} {k : 𝕜} {r : ℝ} (hk : k ≠ 0) :
    k • p.ball 0 r = p.ball 0 (‖k‖ * r) := by
  ext
  rw [mem_smul_set_iff_inv_smul_mem₀ hk, p.mem_ball_zero, p.mem_ball_zero, map_smul_eq_mul,
    norm_inv, ← div_eq_inv_mul, div_lt_iff (norm_pos_iff.2 hk), mul_comm]
#align seminorm.smul_ball_zero Seminorm.smul_ball_zero

theorem smul_closedBall_subset {p : Seminorm 𝕜 E} {k : 𝕜} {r : ℝ} :
    k • p.closedBall 0 r ⊆ p.closedBall 0 (‖k‖ * r) :=
  by
  rintro x ⟨y, hy, h⟩
  rw [Seminorm.mem_closedBall_zero, ← h, map_smul_eq_mul]
  rw [Seminorm.mem_closedBall_zero] at hy
  exact mul_le_mul_of_nonneg_left hy (norm_nonneg _)
#align seminorm.smul_closed_ball_subset Seminorm.smul_closedBall_subset

theorem smul_closedBall_zero {p : Seminorm 𝕜 E} {k : 𝕜} {r : ℝ} (hk : 0 < ‖k‖) :
    k • p.closedBall 0 r = p.closedBall 0 (‖k‖ * r) :=
  by
  refine' subset_antisymm smul_closed_ball_subset _
  intro x
  rw [Set.mem_smul_set, Seminorm.mem_closedBall_zero]
  refine' fun hx => ⟨k⁻¹ • x, _, _⟩
  ·
    rwa [Seminorm.mem_closedBall_zero, map_smul_eq_mul, norm_inv, ← mul_le_mul_left hk, ← mul_assoc,
      ← div_eq_mul_inv ‖k‖ ‖k‖, div_self (ne_of_gt hk), one_mul]
  rw [← smul_assoc, smul_eq_mul, ← div_eq_mul_inv, div_self (norm_pos_iff.mp hk), one_smul]
#align seminorm.smul_closed_ball_zero Seminorm.smul_closedBall_zero

theorem ball_zero_absorbs_ball_zero (p : Seminorm 𝕜 E) {r₁ r₂ : ℝ} (hr₁ : 0 < r₁) :
    Absorbs 𝕜 (p.ball 0 r₁) (p.ball 0 r₂) :=
  by
  rcases exists_pos_lt_mul hr₁ r₂ with ⟨r, hr₀, hr⟩
  refine' ⟨r, hr₀, fun a ha x hx => _⟩
  rw [smul_ball_zero (norm_pos_iff.1 <| hr₀.trans_le ha), p.mem_ball_zero]
  rw [p.mem_ball_zero] at hx
  exact hx.trans (hr.trans_le <| mul_le_mul_of_nonneg_right ha hr₁.le)
#align seminorm.ball_zero_absorbs_ball_zero Seminorm.ball_zero_absorbs_ball_zero

/-- Seminorm-balls at the origin are absorbent. -/
protected theorem absorbent_ball_zero (hr : 0 < r) : Absorbent 𝕜 (ball p (0 : E) r) :=
  absorbent_iff_forall_absorbs_singleton.2 fun x =>
    (p.ball_zero_absorbs_ball_zero hr).mono_right <|
      singleton_subset_iff.2 <| p.mem_ball_zero.2 <| lt_add_one _
#align seminorm.absorbent_ball_zero Seminorm.absorbent_ball_zero

/-- Closed seminorm-balls at the origin are absorbent. -/
protected theorem absorbent_closedBall_zero (hr : 0 < r) : Absorbent 𝕜 (closedBall p (0 : E) r) :=
  (p.absorbent_ball_zero hr).Subset (p.ball_subset_closedBall _ _)
#align seminorm.absorbent_closed_ball_zero Seminorm.absorbent_closedBall_zero

/-- Seminorm-balls containing the origin are absorbent. -/
protected theorem absorbent_ball (hpr : p x < r) : Absorbent 𝕜 (ball p x r) :=
  by
  refine' (p.absorbent_ball_zero <| sub_pos.2 hpr).Subset fun y hy => _
  rw [p.mem_ball_zero] at hy
  exact p.mem_ball.2 ((map_sub_le_add p _ _).trans_lt <| add_lt_of_lt_sub_right hy)
#align seminorm.absorbent_ball Seminorm.absorbent_ball

/-- Seminorm-balls containing the origin are absorbent. -/
protected theorem absorbent_closedBall (hpr : p x < r) : Absorbent 𝕜 (closedBall p x r) :=
  by
  refine' (p.absorbent_closed_ball_zero <| sub_pos.2 hpr).Subset fun y hy => _
  rw [p.mem_closed_ball_zero] at hy
  exact p.mem_closed_ball.2 ((map_sub_le_add p _ _).trans <| add_le_of_le_sub_right hy)
#align seminorm.absorbent_closed_ball Seminorm.absorbent_closedBall

theorem symmetric_ball_zero (r : ℝ) (hx : x ∈ ball p 0 r) : -x ∈ ball p 0 r :=
  balanced_ball_zero p r (-1) (by rw [norm_neg, norm_one]) ⟨x, hx, by rw [neg_smul, one_smul]⟩
#align seminorm.symmetric_ball_zero Seminorm.symmetric_ball_zero

@[simp]
theorem neg_ball (p : Seminorm 𝕜 E) (r : ℝ) (x : E) : -ball p x r = ball p (-x) r :=
  by
  ext
  rw [mem_neg, mem_ball, mem_ball, ← neg_add', sub_neg_eq_add, map_neg_eq_map]
#align seminorm.neg_ball Seminorm.neg_ball

@[simp]
theorem smul_ball_preimage (p : Seminorm 𝕜 E) (y : E) (r : ℝ) (a : 𝕜) (ha : a ≠ 0) :
    (· • ·) a ⁻¹' p.ball y r = p.ball (a⁻¹ • y) (r / ‖a‖) :=
  Set.ext fun _ => by
    rw [mem_preimage, mem_ball, mem_ball, lt_div_iff (norm_pos_iff.mpr ha), mul_comm, ←
      map_smul_eq_mul p, smul_sub, smul_inv_smul₀ ha]
#align seminorm.smul_ball_preimage Seminorm.smul_ball_preimage

end NormedField

section Convex

variable [NormedField 𝕜] [AddCommGroup E] [NormedSpace ℝ 𝕜] [Module 𝕜 E]

section SMul

variable [SMul ℝ E] [IsScalarTower ℝ 𝕜 E] (p : Seminorm 𝕜 E)

/-- A seminorm is convex. Also see `convex_on_norm`. -/
protected theorem convexOn : ConvexOn ℝ univ p :=
  by
  refine' ⟨convex_univ, fun x _ y _ a b ha hb hab => _⟩
  calc
    p (a • x + b • y) ≤ p (a • x) + p (b • y) := map_add_le_add p _ _
    _ = ‖a • (1 : 𝕜)‖ * p x + ‖b • (1 : 𝕜)‖ * p y := by
      rw [← map_smul_eq_mul p, ← map_smul_eq_mul p, smul_one_smul, smul_one_smul]
    _ = a * p x + b * p y := by
      rw [norm_smul, norm_smul, norm_one, mul_one, mul_one, Real.norm_of_nonneg ha,
        Real.norm_of_nonneg hb]

#align seminorm.convex_on Seminorm.convexOn

end SMul

section Module

variable [Module ℝ E] [IsScalarTower ℝ 𝕜 E] (p : Seminorm 𝕜 E) (x : E) (r : ℝ)

/-- Seminorm-balls are convex. -/
theorem convex_ball : Convex ℝ (ball p x r) :=
  by
  convert(p.convex_on.translate_left (-x)).convex_lt r
  ext y
  rw [preimage_univ, sep_univ, p.mem_ball, sub_eq_add_neg]
  rfl
#align seminorm.convex_ball Seminorm.convex_ball

/-- Closed seminorm-balls are convex. -/
theorem convex_closedBall : Convex ℝ (closedBall p x r) :=
  by
  rw [closed_ball_eq_bInter_ball]
  exact convex_interᵢ₂ fun _ _ => convex_ball _ _ _
#align seminorm.convex_closed_ball Seminorm.convex_closedBall

end Module

end Convex

section RestrictScalars

variable (𝕜) {𝕜' : Type _} [NormedField 𝕜] [SeminormedRing 𝕜'] [NormedAlgebra 𝕜 𝕜']
  [NormOneClass 𝕜'] [AddCommGroup E] [Module 𝕜' E] [SMul 𝕜 E] [IsScalarTower 𝕜 𝕜' E]

/-- Reinterpret a seminorm over a field `𝕜'` as a seminorm over a smaller field `𝕜`. This will
typically be used with `is_R_or_C 𝕜'` and `𝕜 = ℝ`. -/
protected def restrictScalars (p : Seminorm 𝕜' E) : Seminorm 𝕜 E :=
  { p with
    smul' := fun a x => by rw [← smul_one_smul 𝕜' a x, p.smul', norm_smul, norm_one, mul_one] }
#align seminorm.restrict_scalars Seminorm.restrictScalars

@[simp]
theorem coe_restrictScalars (p : Seminorm 𝕜' E) : (p.restrictScalars 𝕜 : E → ℝ) = p :=
  rfl
#align seminorm.coe_restrict_scalars Seminorm.coe_restrictScalars

@[simp]
theorem restrictScalars_ball (p : Seminorm 𝕜' E) : (p.restrictScalars 𝕜).ball = p.ball :=
  rfl
#align seminorm.restrict_scalars_ball Seminorm.restrictScalars_ball

@[simp]
theorem restrictScalars_closedBall (p : Seminorm 𝕜' E) :
    (p.restrictScalars 𝕜).closedBall = p.closedBall :=
  rfl
#align seminorm.restrict_scalars_closed_ball Seminorm.restrictScalars_closedBall

end RestrictScalars

/-! ### Continuity criterions for seminorms -/

section Continuity

variable [NontriviallyNormedField 𝕜] [SeminormedRing 𝕝] [AddCommGroup E] [Module 𝕜 E]

variable [Module 𝕝 E]

theorem continuousAt_zero' [TopologicalSpace E] [ContinuousConstSMul 𝕜 E] {p : Seminorm 𝕜 E} {r : ℝ}
    (hr : 0 < r) (hp : p.closedBall 0 r ∈ (𝓝 0 : Filter E)) : ContinuousAt p 0 :=
  by
  refine' metric.nhds_basis_closed_ball.tendsto_right_iff.mpr _
  intro ε hε
  rw [map_zero]
  suffices p.closed_ball 0 ε ∈ (𝓝 0 : Filter E) by
    rwa [Seminorm.closedBall_zero_eq_preimage_closedBall] at this
  rcases exists_norm_lt 𝕜 (div_pos hε hr) with ⟨k, hk0, hkε⟩
  have hk0' := norm_pos_iff.mp hk0
  have := (set_smul_mem_nhds_zero_iff hk0').mpr hp
  refine' Filter.mem_of_superset this (smul_set_subset_iff.mpr fun x hx => _)
  rw [mem_closed_ball_zero, map_smul_eq_mul, ← div_mul_cancel ε hr.ne.symm]
  exact mul_le_mul hkε.le (p.mem_closed_ball_zero.mp hx) (map_nonneg _ _) (div_nonneg hε.le hr.le)
#align seminorm.continuous_at_zero' Seminorm.continuousAt_zero'

theorem continuousAt_zero [TopologicalSpace E] [ContinuousConstSMul 𝕜 E] {p : Seminorm 𝕜 E} {r : ℝ}
    (hr : 0 < r) (hp : p.ball 0 r ∈ (𝓝 0 : Filter E)) : ContinuousAt p 0 :=
  continuousAt_zero' hr (Filter.mem_of_superset hp <| p.ball_subset_closedBall _ _)
#align seminorm.continuous_at_zero Seminorm.continuousAt_zero

protected theorem uniformContinuous_of_continuousAt_zero [UniformSpace E] [UniformAddGroup E]
    {p : Seminorm 𝕝 E} (hp : ContinuousAt p 0) : UniformContinuous p :=
  by
  have hp : Filter.Tendsto p (𝓝 0) (𝓝 0) := map_zero p ▸ hp
  rw [UniformContinuous, uniformity_eq_comap_nhds_zero_swapped,
    Metric.uniformity_eq_comap_nhds_zero, Filter.tendsto_comap_iff]
  exact
    tendsto_of_tendsto_of_tendsto_of_le_of_le tendsto_const_nhds (hp.comp Filter.tendsto_comap)
      (fun xy => dist_nonneg) fun xy => p.norm_sub_map_le_sub _ _
#align seminorm.uniform_continuous_of_continuous_at_zero Seminorm.uniformContinuous_of_continuousAt_zero

protected theorem continuous_of_continuousAt_zero [TopologicalSpace E] [TopologicalAddGroup E]
    {p : Seminorm 𝕝 E} (hp : ContinuousAt p 0) : Continuous p :=
  by
  letI := TopologicalAddGroup.toUniformSpace E
  haveI : UniformAddGroup E := comm_topologicalAddGroup_is_uniform
  exact (Seminorm.uniformContinuous_of_continuousAt_zero hp).Continuous
#align seminorm.continuous_of_continuous_at_zero Seminorm.continuous_of_continuousAt_zero

protected theorem uniformContinuous [UniformSpace E] [UniformAddGroup E] [ContinuousConstSMul 𝕜 E]
    {p : Seminorm 𝕜 E} {r : ℝ} (hr : 0 < r) (hp : p.ball 0 r ∈ (𝓝 0 : Filter E)) :
    UniformContinuous p :=
  Seminorm.uniformContinuous_of_continuousAt_zero (continuousAt_zero hr hp)
#align seminorm.uniform_continuous Seminorm.uniformContinuous

protected theorem uniform_continuous' [UniformSpace E] [UniformAddGroup E] [ContinuousConstSMul 𝕜 E]
    {p : Seminorm 𝕜 E} {r : ℝ} (hr : 0 < r) (hp : p.closedBall 0 r ∈ (𝓝 0 : Filter E)) :
    UniformContinuous p :=
  Seminorm.uniformContinuous_of_continuousAt_zero (continuousAt_zero' hr hp)
#align seminorm.uniform_continuous' Seminorm.uniform_continuous'

protected theorem continuous [TopologicalSpace E] [TopologicalAddGroup E] [ContinuousConstSMul 𝕜 E]
    {p : Seminorm 𝕜 E} {r : ℝ} (hr : 0 < r) (hp : p.ball 0 r ∈ (𝓝 0 : Filter E)) : Continuous p :=
  Seminorm.continuous_of_continuousAt_zero (continuousAt_zero hr hp)
#align seminorm.continuous Seminorm.continuous

protected theorem continuous' [TopologicalSpace E] [TopologicalAddGroup E] [ContinuousConstSMul 𝕜 E]
    {p : Seminorm 𝕜 E} {r : ℝ} (hr : 0 < r) (hp : p.closedBall 0 r ∈ (𝓝 0 : Filter E)) :
    Continuous p :=
  Seminorm.continuous_of_continuousAt_zero (continuousAt_zero' hr hp)
#align seminorm.continuous' Seminorm.continuous'

theorem continuous_of_le [TopologicalSpace E] [TopologicalAddGroup E] [ContinuousConstSMul 𝕜 E]
    {p q : Seminorm 𝕜 E} (hq : Continuous q) (hpq : p ≤ q) : Continuous p :=
  by
  refine'
    Seminorm.continuous one_pos
      (Filter.mem_of_superset (IsOpen.mem_nhds _ <| q.mem_ball_self zero_lt_one)
        (ball_antitone hpq))
  rw [ball_zero_eq]
  exact isOpen_lt hq continuous_const
#align seminorm.continuous_of_le Seminorm.continuous_of_le

end Continuity

end Seminorm

/-! ### The norm as a seminorm -/

section normSeminorm

variable (𝕜) (E) [NormedField 𝕜] [SeminormedAddCommGroup E] [NormedSpace 𝕜 E] {r : ℝ}

/-- The norm of a seminormed group as a seminorm. -/
def normSeminorm : Seminorm 𝕜 E :=
  { normAddGroupSeminorm E with smul' := norm_smul }
#align norm_seminorm normSeminorm

@[simp]
theorem coe_normSeminorm : ⇑(normSeminorm 𝕜 E) = norm :=
  rfl
#align coe_norm_seminorm coe_normSeminorm

@[simp]
theorem ball_normSeminorm : (normSeminorm 𝕜 E).ball = Metric.ball :=
  by
  ext (x r y)
  simp only [Seminorm.mem_ball, Metric.mem_ball, coe_normSeminorm, dist_eq_norm]
#align ball_norm_seminorm ball_normSeminorm

variable {𝕜 E} {x : E}

/-- Balls at the origin are absorbent. -/
theorem absorbent_ball_zero (hr : 0 < r) : Absorbent 𝕜 (Metric.ball (0 : E) r) :=
  by
  rw [← ball_normSeminorm 𝕜]
  exact (normSeminorm _ _).absorbent_ball_zero hr
#align absorbent_ball_zero absorbent_ball_zero

/-- Balls containing the origin are absorbent. -/
theorem absorbent_ball (hx : ‖x‖ < r) : Absorbent 𝕜 (Metric.ball x r) :=
  by
  rw [← ball_normSeminorm 𝕜]
  exact (normSeminorm _ _).absorbent_ball hx
#align absorbent_ball absorbent_ball

/-- Balls at the origin are balanced. -/
theorem balanced_ball_zero : Balanced 𝕜 (Metric.ball (0 : E) r) :=
  by
  rw [← ball_normSeminorm 𝕜]
  exact (normSeminorm _ _).balanced_ball_zero r
#align balanced_ball_zero balanced_ball_zero

end normSeminorm

-- Guard against import creep.
assert_not_exists balanced_core


/-
Copyright (c) 2019 Patrick Massot All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Patrick Massot, Simon Hudon

A tactic pushing negations into an expression
-/

/-
Slight modification by Justin Carel: variation of push_neg that only pushes once.
-/

import logic.basic
import tactic.push_neg
open tactic expr

namespace push_neg_once

-- theorem not_iff_eq (P Q : Prop) : ¬ (P ↔ Q) = (¬ (P → Q) ∨ ¬ (Q → P))
--  :=
-- begin
--   sorry
-- --  rw not_and_distrib,
-- --  (not_and_distrib (iff_def P Q))
-- end

section redef
open push_neg -- we don't want to pollute the namespace outside of this definition

-- this is private in push_neg for some reason, so we have to redefine it here
meta def transform_negation_step (e : expr) :
  tactic (option (expr × expr)) :=
do e ← whnf_reducible e,
   match e with
   | `(¬ %%ne) :=
      (do ne ← whnf_reducible ne,
      match ne with
      -- | `(%%a ↔ %%b)  := do e ← to_expr ``(¬ (%%a → %%b) ∨ ¬ (%%b → %%a)),
      --                       pr ← mk_app ``not_iff_eq [a, b],
      --                       return $ some (e, pr)
      | `(¬ %%a)      := do pr ← mk_app ``not_not_eq [a],
                            return $ some (a, pr)
      | `(%%a ∧ %%b)  := do pr ← mk_app ``not_and_eq [a, b],
                            return (some (`(¬ %%a ∨ ¬ %%b), pr))
      | `(%%a ∨ %%b)  := do pr ← mk_app ``not_or_eq [a, b],
                            return $ some (`(¬ %%a ∧ ¬ %%b), pr)
      | `(%%a ≤ %%b)  := do e ← to_expr ``(%%b < %%a),
                            pr ← mk_app ``not_le_eq [a, b],
                            return $ some (e, pr)
      | `(%%a < %%b)  := do e ← to_expr ``(%%b ≤ %%a),
                            pr ← mk_app ``not_lt_eq [a, b],
                            return $ some (e, pr)
      | `(Exists %%p) := do pr ← mk_app ``not_exists_eq [p],
                            e ← match p with
                                | (lam n bi typ bo) := do
                                    body ← mk_app ``not [bo],
                                    return (pi n bi typ body)
                                | _ := tactic.fail "Unexpected failure negating ∃"
                                end,
                            return $ some (e, pr)
      | (pi n bi d p) := if p.has_var then do
                            pr ← mk_app ``not_forall_eq [lam n bi d p],
                            body ← mk_app ``not [p],
                            e ←  mk_app ``Exists [lam n bi d body],
                            return $ some (e, pr)
                         else do
                            pr ← mk_app ``not_implies_eq [d, p],
                            `(%%_ = %%e') ← infer_type pr,
                            return $ some (e', pr)
      | _             := return none
      end)
    | _        := return none
  end

-- this is private in push_neg for some reason, so we have to redefine it here
meta def transform_negation : expr → tactic (option (expr × expr))
| e :=
do some (e',  pr)  ← transform_negation_step e | return none,
   some (e'', pr') ← transform_negation e' | return $ some (e', pr),
   pr'' ← mk_eq_trans pr pr',
   return $ some (e'', pr'')

end redef

/--
simplify_top_down but without guard against unchanged expressions.
This is necessary, otherwise the user state doesn't update when the proof is by refl.
-/
meta def simplify_top_down' {α} (a : α) (pre : α → expr → tactic (α × expr × expr)) (e : expr) (cfg : simp_config := {}) : tactic (α × expr × expr) :=
ext_simplify_core a cfg simp_lemmas.mk (λ _, failed)
  (λ a _ _ _ e, do (new_a, new_e, pr) ← pre a e, return (new_a, new_e, some pr, tt))
  (λ _ _ _ _ _, failed)
  `eq e

/--
Recursively searches all negations in top down order and pushes the n-th found.
Returns `(e, pr)`, where `e` is the new expression and `pr` is a proof that `old = e`
-/
meta def transform_nth_negation (t : expr) (n : ℕ) : tactic (expr × expr) :=
do (_, e, pr) ← simplify_top_down' (ff, n-1)
                    (λ s e, do
                        pr ← mk_eq_refl e,
                        match s with
                        | (tt, _) := failure  -- already transformed
                        | (ff, 0) := do       -- ready to transform
                            oepr ← transform_negation e,
                            match oepr with
                            | some (e, pr) := return ((tt, 0), e, pr)
                            | none         := return ((ff, 0), e, pr)
                            end
                        | (ff, nat.succ m) := -- encountered less than n-1 negations
                            match e with
                            | `(¬ %%ne) := return ((ff, m), e, pr)
                            | _         := return ((ff, m+1), e, pr)
                            end
                        end)
                    t { eta := ff, single_pass := tt },
   return (e, pr)

meta def push_neg_once_at_hyp (n : ℕ) (h : name) : tactic unit :=
do H ← get_local h,
   t ← infer_type H,
   (e, pr) ← transform_nth_negation t n,
   replace_hyp H e pr,
   skip

meta def push_neg_once_at_goal (n : ℕ) : tactic unit :=
do t ← target,
   (e, pr) ← transform_nth_negation t n,
   replace_target e pr

end push_neg_once

open interactive (parse loc.ns loc.wildcard)
open interactive.types (location)
open lean.parser (small_nat)
open push_neg_once
local postfix `?`:9001 := optional

/--
Variation on push_neg that only pushes the nth negation, once.

Usage:
```
-- push the nth negation at the goal
push_neg_once n
-- push the nth negation at the hypothesis h
push_neg_once n at h
-- push the first negation at the goal and all hypotheses
push_neg_once at *
```
-/
meta def tactic.interactive.push_neg_once : parse small_nat? → parse location → tactic unit
| none l := tactic.interactive.push_neg_once (some 1) l
| (some n) (loc.ns loc_l) :=
  loc_l.mmap' $ λl,
      (match l with
      | some h := do push_neg_once_at_hyp n h,
                     try $ interactive.simp_core { eta := ff } failed tt
                            [simp_arg_type.expr ``(push_neg.not_eq)] []
                            (loc.ns [some h])
      | none   := do push_neg_once_at_goal n,
                     try `[simp only [push_neg.not_eq] { eta := ff }]
      end)
| (some n) loc.wildcard := do
    push_neg_once_at_goal n,
    local_context >>= mmap' (push_neg_once_at_hyp n ∘ local_pp_name),
    try `[simp only [push_neg.not_eq] at * { eta := ff }]

add_tactic_doc
{ name       := "push_neg_once",
  category   := doc_category.tactic,
  decl_names := [`tactic.interactive.push_neg_once],
  tags       := ["logic"] }


/-
Copyright (c) 2019 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl

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

/-!
# Unsigned Hahn decomposition theorem

This file proves the unsigned version of the Hahn decomposition theorem.

## Main statements

* `hahn_decomposition` : Given two finite measures `μ` and `ν`, there exists a measurable set `s`
    such that any measurable set `t` included in `s` satisfies `ν t ≤ μ t`, and any
    measurable set `u` included in the complement of `s` satisfies `μ u ≤ ν u`.

## Tags

Hahn decomposition
-/

open Set Filter

open Classical Topology ENNReal

namespace MeasureTheory

variable {α : Type _} [MeasurableSpace α] {μ ν : Measure α}

/-- **Hahn decomposition theorem** -/
theorem hahn_decomposition [IsFiniteMeasure μ] [IsFiniteMeasure ν] :
    ∃ s,
      MeasurableSet s ∧
        (∀ t, MeasurableSet t → t ⊆ s → ν t ≤ μ t) ∧ ∀ t, MeasurableSet t → t ⊆ sᶜ → μ t ≤ ν t :=
  by
  let d : Set α → ℝ := fun s => ((μ s).toNNReal : ℝ) - (ν s).toNNReal
  let c : Set ℝ := d '' { s | MeasurableSet s }
  let γ : ℝ := Sup c
  have hμ : ∀ s, μ s ≠ ∞ := measure_ne_top μ
  have hν : ∀ s, ν s ≠ ∞ := measure_ne_top ν
  have to_nnreal_μ : ∀ s, ((μ s).toNNReal : ℝ≥0∞) = μ s := fun s => ENNReal.coe_toNNReal <| hμ _
  have to_nnreal_ν : ∀ s, ((ν s).toNNReal : ℝ≥0∞) = ν s := fun s => ENNReal.coe_toNNReal <| hν _
  have d_empty : d ∅ = 0 := by
    change _ - _ = _
    rw [measure_empty, measure_empty, sub_self]
  have d_split : ∀ s t, MeasurableSet s → MeasurableSet t → d s = d (s \ t) + d (s ∩ t) :=
    by
    intro s t hs ht
    simp only [d]
    rw [← measure_inter_add_diff s ht, ← measure_inter_add_diff s ht,
      ENNReal.toNNReal_add (hμ _) (hμ _), ENNReal.toNNReal_add (hν _) (hν _), NNReal.coe_add,
      NNReal.coe_add]
    simp only [sub_eq_add_neg, neg_add]
    abel
  have d_Union :
    ∀ s : ℕ → Set α, Monotone s → tendsto (fun n => d (s n)) at_top (𝓝 (d (⋃ n, s n))) :=
    by
    intro s hm
    refine' tendsto.sub _ _ <;>
      refine' NNReal.tendsto_coe.2 <| (ENNReal.tendsto_toNNReal _).comp <| tendsto_measure_Union hm
    exact hμ _
    exact hν _
  have d_Inter :
    ∀ s : ℕ → Set α,
      (∀ n, MeasurableSet (s n)) →
        (∀ n m, n ≤ m → s m ⊆ s n) → tendsto (fun n => d (s n)) at_top (𝓝 (d (⋂ n, s n))) :=
    by
    intro s hs hm
    refine' tendsto.sub _ _ <;>
      refine'
        NNReal.tendsto_coe.2 <|
          (ENNReal.tendsto_toNNReal <| _).comp <| tendsto_measure_Inter hs hm _
    exacts[hμ _, ⟨0, hμ _⟩, hν _, ⟨0, hν _⟩]
  have bdd_c : BddAbove c := by
    use (μ univ).toNNReal
    rintro r ⟨s, hs, rfl⟩
    refine' le_trans (sub_le_self _ <| NNReal.coe_nonneg _) _
    rw [NNReal.coe_le_coe, ← ENNReal.coe_le_coe, to_nnreal_μ, to_nnreal_μ]
    exact measure_mono (subset_univ _)
  have c_nonempty : c.nonempty := nonempty.image _ ⟨_, MeasurableSet.empty⟩
  have d_le_γ : ∀ s, MeasurableSet s → d s ≤ γ := fun s hs => le_csupₛ bdd_c ⟨s, hs, rfl⟩
  have : ∀ n : ℕ, ∃ s : Set α, MeasurableSet s ∧ γ - (1 / 2) ^ n < d s :=
    by
    intro n
    have : γ - (1 / 2) ^ n < γ := sub_lt_self γ (pow_pos (half_pos zero_lt_one) n)
    rcases exists_lt_of_lt_csupₛ c_nonempty this with ⟨r, ⟨s, hs, rfl⟩, hlt⟩
    exact ⟨s, hs, hlt⟩
  rcases Classical.axiom_of_choice this with ⟨e, he⟩
  change ℕ → Set α at e
  have he₁ : ∀ n, MeasurableSet (e n) := fun n => (he n).1
  have he₂ : ∀ n, γ - (1 / 2) ^ n < d (e n) := fun n => (he n).2
  let f : ℕ → ℕ → Set α := fun n m => (Finset.Ico n (m + 1)).inf e
  have hf : ∀ n m, MeasurableSet (f n m) := by
    intro n m
    simp only [f, Finset.inf_eq_infᵢ]
    exact MeasurableSet.binterᵢ (to_countable _) fun i _ => he₁ _
  have f_subset_f : ∀ {a b c d}, a ≤ b → c ≤ d → f a d ⊆ f b c :=
    by
    intro a b c d hab hcd
    dsimp only [f]
    rw [Finset.inf_eq_infᵢ, Finset.inf_eq_infᵢ]
    exact bInter_subset_bInter_left (Finset.Ico_subset_Ico hab <| Nat.succ_le_succ hcd)
  have f_succ : ∀ n m, n ≤ m → f n (m + 1) = f n m ∩ e (m + 1) :=
    by
    intro n m hnm
    have : n ≤ m + 1 := le_of_lt (Nat.succ_le_succ hnm)
    simp only [f]
    rw [Nat.Ico_succ_right_eq_insert_Ico this, Finset.inf_insert, Set.inter_comm]
    rfl
  have le_d_f : ∀ n m, m ≤ n → γ - 2 * (1 / 2) ^ m + (1 / 2) ^ n ≤ d (f m n) :=
    by
    intro n m h
    refine' Nat.le_induction _ _ n h
    · have := he₂ m
      simp only [f]
      rw [Nat.Ico_succ_singleton, Finset.inf_singleton]
      linarith
    · intro n(hmn : m ≤ n)ih
      have : γ + (γ - 2 * (1 / 2) ^ m + (1 / 2) ^ (n + 1)) ≤ γ + d (f m (n + 1)) := by
        calc
          γ + (γ - 2 * (1 / 2) ^ m + (1 / 2) ^ (n + 1)) ≤
              γ + (γ - 2 * (1 / 2) ^ m + ((1 / 2) ^ n - (1 / 2) ^ (n + 1))) :=
            by
            refine' add_le_add_left (add_le_add_left _ _) γ
            simp only [pow_add, pow_one, le_sub_iff_add_le]
            linarith
          _ = γ - (1 / 2) ^ (n + 1) + (γ - 2 * (1 / 2) ^ m + (1 / 2) ^ n) := by
            simp only [sub_eq_add_neg] <;> abel
          _ ≤ d (e (n + 1)) + d (f m n) := (add_le_add (le_of_lt <| he₂ _) ih)
          _ ≤ d (e (n + 1)) + d (f m n \ e (n + 1)) + d (f m (n + 1)) := by
            rw [f_succ _ _ hmn, d_split (f m n) (e (n + 1)) (hf _ _) (he₁ _), add_assoc]
          _ = d (e (n + 1) ∪ f m n) + d (f m (n + 1)) :=
            by
            rw [d_split (e (n + 1) ∪ f m n) (e (n + 1)), union_diff_left, union_inter_cancel_left]
            abel
            exact (he₁ _).union (hf _ _)
            exact he₁ _
          _ ≤ γ + d (f m (n + 1)) := add_le_add_right (d_le_γ _ <| (he₁ _).union (hf _ _)) _

      exact (add_le_add_iff_left γ).1 this
  let s := ⋃ m, ⋂ n, f m n
  have γ_le_d_s : γ ≤ d s :=
    by
    have hγ : tendsto (fun m : ℕ => γ - 2 * (1 / 2) ^ m) at_top (𝓝 γ) :=
      by
      suffices tendsto (fun m : ℕ => γ - 2 * (1 / 2) ^ m) at_top (𝓝 (γ - 2 * 0)) by
        simpa only [MulZeroClass.mul_zero, tsub_zero]
      exact
        tendsto_const_nhds.sub <|
          tendsto_const_nhds.mul <|
            tendsto_pow_atTop_nhds_0_of_lt_1 (le_of_lt <| half_pos <| zero_lt_one)
              (half_lt_self zero_lt_one)
    have hd : tendsto (fun m => d (⋂ n, f m n)) at_top (𝓝 (d (⋃ m, ⋂ n, f m n))) :=
      by
      refine' d_Union _ _
      exact fun n m hnm =>
        subset_Inter fun i => subset.trans (Inter_subset (f n) i) <| f_subset_f hnm <| le_rfl
    refine' le_of_tendsto_of_tendsto' hγ hd fun m => _
    have : tendsto (fun n => d (f m n)) at_top (𝓝 (d (⋂ n, f m n))) :=
      by
      refine' d_Inter _ _ _
      · intro n
        exact hf _ _
      · intro n m hnm
        exact f_subset_f le_rfl hnm
    refine' ge_of_tendsto this (eventually_at_top.2 ⟨m, fun n hmn => _⟩)
    change γ - 2 * (1 / 2) ^ m ≤ d (f m n)
    refine' le_trans _ (le_d_f _ _ hmn)
    exact le_add_of_le_of_nonneg le_rfl (pow_nonneg (le_of_lt <| half_pos <| zero_lt_one) _)
  have hs : MeasurableSet s := MeasurableSet.unionᵢ fun n => MeasurableSet.interᵢ fun m => hf _ _
  refine' ⟨s, hs, _, _⟩
  · intro t ht hts
    have : 0 ≤ d t :=
      (add_le_add_iff_left γ).1 <|
        calc
          γ + 0 ≤ d s := by rw [add_zero] <;> exact γ_le_d_s
          _ = d (s \ t) + d t := by rw [d_split _ _ hs ht, inter_eq_self_of_subset_right hts]
          _ ≤ γ + d t := add_le_add (d_le_γ _ (hs.diff ht)) le_rfl

    rw [← to_nnreal_μ, ← to_nnreal_ν, ENNReal.coe_le_coe, ← NNReal.coe_le_coe]
    simpa only [d, le_sub_iff_add_le, zero_add] using this
  · intro t ht hts
    have : d t ≤ 0 :=
      (add_le_add_iff_left γ).1 <|
        calc
          γ + d t ≤ d s + d t := add_le_add γ_le_d_s le_rfl
          _ = d (s ∪ t) := by
            rw [d_split _ _ (hs.union ht) ht, union_diff_right, union_inter_cancel_right,
              (subset_compl_iff_disjoint_left.1 hts).sdiff_eq_left]
          _ ≤ γ + 0 := by rw [add_zero] <;> exact d_le_γ _ (hs.union ht)

    rw [← to_nnreal_μ, ← to_nnreal_ν, ENNReal.coe_le_coe, ← NNReal.coe_le_coe]
    simpa only [d, sub_le_iff_le_add, zero_add] using this
#align measure_theory.hahn_decomposition MeasureTheory.hahn_decomposition

end MeasureTheory


theorem Prod.ext' : {p q : α × β} → p.1 = q.1 → p.2 = q.2 → p = q
  | (a, b), (c, d) => by simp_all


/-
Copyright (c) 2021 OpenAI. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kunhao Zheng, Stanislas Polu, David Renshaw, OpenAI GPT-f
-/
import mathzoo.imports.miniF2F

open_locale nat rat real big_operators topological_space

theorem mathd_numbertheory_136
  (n : ℕ)
  (h₀ : 123 * n + 17 = 39500) : n = 321 :=
begin
  linarith,
end