/-
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, Jeremy Avigad, Yury Kudryashov, Patrick Massot
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.order.filter.bases
import Mathlib.data.finset.preimage
import Mathlib.PostPort

universes u_3 u_1 u_4 u_5 u_2 u_6

namespace Mathlib

/-!
# `at_top` and `at_bot` filters on preorded sets, monoids and groups.

In this file we define the filters

* `at_top`: corresponds to `n → +∞`;
* `at_bot`: corresponds to `n → -∞`.

Then we prove many lemmas like “if `f → +∞`, then `f ± c → +∞`”.
-/

namespace filter

/-- `at_top` is the filter representing the limit `→ ∞` on an ordered set.
  It is generated by the collection of up-sets `{b | a ≤ b}`.
  (The preorder need not have a top element for this to be well defined,
  and indeed is trivial when a top element exists.) -/
def at_top {α : Type u_3} [preorder α] : filter α := infi fun (a : α) => principal (set.Ici a)

/-- `at_bot` is the filter representing the limit `→ -∞` on an ordered set.
  It is generated by the collection of down-sets `{b | b ≤ a}`.
  (The preorder need not have a bottom element for this to be well defined,
  and indeed is trivial when a bottom element exists.) -/
def at_bot {α : Type u_3} [preorder α] : filter α := infi fun (a : α) => principal (set.Iic a)

theorem mem_at_top {α : Type u_3} [preorder α] (a : α) : (set_of fun (b : α) => a ≤ b) ∈ at_top :=
  mem_infi_sets a (set.subset.refl (set.Ici a))

theorem Ioi_mem_at_top {α : Type u_3} [preorder α] [no_top_order α] (x : α) : set.Ioi x ∈ at_top :=
  sorry

theorem mem_at_bot {α : Type u_3} [preorder α] (a : α) : (set_of fun (b : α) => b ≤ a) ∈ at_bot :=
  mem_infi_sets a (set.subset.refl (set.Iic a))

theorem Iio_mem_at_bot {α : Type u_3} [preorder α] [no_bot_order α] (x : α) : set.Iio x ∈ at_bot :=
  sorry

theorem at_top_basis {α : Type u_3} [Nonempty α] [semilattice_sup α] :
    has_basis at_top (fun (_x : α) => True) set.Ici :=
  has_basis_infi_principal (directed_of_sup fun (a b : α) => iff.mpr set.Ici_subset_Ici)

theorem at_top_basis' {α : Type u_3} [semilattice_sup α] (a : α) :
    has_basis at_top (fun (x : α) => a ≤ x) set.Ici :=
  sorry

theorem at_bot_basis {α : Type u_3} [Nonempty α] [semilattice_inf α] :
    has_basis at_bot (fun (_x : α) => True) set.Iic :=
  at_top_basis

theorem at_bot_basis' {α : Type u_3} [semilattice_inf α] (a : α) :
    has_basis at_bot (fun (x : α) => x ≤ a) set.Iic :=
  at_top_basis' a

instance at_top_ne_bot {α : Type u_3} [Nonempty α] [semilattice_sup α] : ne_bot at_top :=
  iff.mpr (has_basis.ne_bot_iff at_top_basis) fun (a : α) (_x : True) => set.nonempty_Ici

instance at_bot_ne_bot {α : Type u_3} [Nonempty α] [semilattice_inf α] : ne_bot at_bot :=
  at_top_ne_bot

@[simp] theorem mem_at_top_sets {α : Type u_3} [Nonempty α] [semilattice_sup α] {s : set α} :
    s ∈ at_top ↔ ∃ (a : α), ∀ (b : α), b ≥ a → b ∈ s :=
  iff.trans (has_basis.mem_iff at_top_basis) (exists_congr fun (_x : α) => exists_const True)

@[simp] theorem mem_at_bot_sets {α : Type u_3} [Nonempty α] [semilattice_inf α] {s : set α} :
    s ∈ at_bot ↔ ∃ (a : α), ∀ (b : α), b ≤ a → b ∈ s :=
  mem_at_top_sets

@[simp] theorem eventually_at_top {α : Type u_3} [semilattice_sup α] [Nonempty α] {p : α → Prop} :
    filter.eventually (fun (x : α) => p x) at_top ↔ ∃ (a : α), ∀ (b : α), b ≥ a → p b :=
  mem_at_top_sets

@[simp] theorem eventually_at_bot {α : Type u_3} [semilattice_inf α] [Nonempty α] {p : α → Prop} :
    filter.eventually (fun (x : α) => p x) at_bot ↔ ∃ (a : α), ∀ (b : α), b ≤ a → p b :=
  mem_at_bot_sets

theorem eventually_ge_at_top {α : Type u_3} [preorder α] (a : α) :
    filter.eventually (fun (x : α) => a ≤ x) at_top :=
  mem_at_top a

theorem eventually_le_at_bot {α : Type u_3} [preorder α] (a : α) :
    filter.eventually (fun (x : α) => x ≤ a) at_bot :=
  mem_at_bot a

theorem eventually_gt_at_top {α : Type u_3} [preorder α] [no_top_order α] (a : α) :
    filter.eventually (fun (x : α) => a < x) at_top :=
  Ioi_mem_at_top a

theorem eventually_lt_at_bot {α : Type u_3} [preorder α] [no_bot_order α] (a : α) :
    filter.eventually (fun (x : α) => x < a) at_bot :=
  Iio_mem_at_bot a

theorem at_top_basis_Ioi {α : Type u_3} [Nonempty α] [semilattice_sup α] [no_top_order α] :
    has_basis at_top (fun (_x : α) => True) set.Ioi :=
  sorry

theorem at_top_countable_basis {α : Type u_3} [Nonempty α] [semilattice_sup α] [encodable α] :
    has_countable_basis at_top (fun (_x : α) => True) set.Ici :=
  has_countable_basis.mk (has_basis.mk (has_basis.mem_iff' at_top_basis))
    (set.countable_encodable (set_of fun (_x : α) => True))

theorem at_bot_countable_basis {α : Type u_3} [Nonempty α] [semilattice_inf α] [encodable α] :
    has_countable_basis at_bot (fun (_x : α) => True) set.Iic :=
  has_countable_basis.mk (has_basis.mk (has_basis.mem_iff' at_bot_basis))
    (set.countable_encodable (set_of fun (_x : α) => True))

theorem is_countably_generated_at_top {α : Type u_3} [Nonempty α] [semilattice_sup α]
    [encodable α] : is_countably_generated at_top :=
  has_countable_basis.is_countably_generated at_top_countable_basis

theorem is_countably_generated_at_bot {α : Type u_3} [Nonempty α] [semilattice_inf α]
    [encodable α] : is_countably_generated at_bot :=
  has_countable_basis.is_countably_generated at_bot_countable_basis

theorem order_top.at_top_eq (α : Type u_1) [order_top α] : at_top = pure ⊤ :=
  le_antisymm
    (iff.mpr le_pure_iff (eventually.mono (eventually_ge_at_top ⊤) fun (b : α) => top_unique))
    (le_infi fun (b : α) => iff.mpr le_principal_iff le_top)

theorem order_bot.at_bot_eq (α : Type u_1) [order_bot α] : at_bot = pure ⊥ :=
  order_top.at_top_eq (order_dual α)

theorem subsingleton.at_top_eq (α : Type u_1) [subsingleton α] [preorder α] : at_top = ⊤ := sorry

theorem subsingleton.at_bot_eq (α : Type u_1) [subsingleton α] [preorder α] : at_bot = ⊤ :=
  subsingleton.at_top_eq (order_dual α)

theorem tendsto_at_top_pure {α : Type u_3} {β : Type u_4} [order_top α] (f : α → β) :
    tendsto f at_top (pure (f ⊤)) :=
  Eq.symm (order_top.at_top_eq α) ▸ tendsto_pure_pure f ⊤

theorem tendsto_at_bot_pure {α : Type u_3} {β : Type u_4} [order_bot α] (f : α → β) :
    tendsto f at_bot (pure (f ⊥)) :=
  tendsto_at_top_pure f

theorem eventually.exists_forall_of_at_top {α : Type u_3} [semilattice_sup α] [Nonempty α]
    {p : α → Prop} (h : filter.eventually (fun (x : α) => p x) at_top) :
    ∃ (a : α), ∀ (b : α), b ≥ a → p b :=
  iff.mp eventually_at_top h

theorem eventually.exists_forall_of_at_bot {α : Type u_3} [semilattice_inf α] [Nonempty α]
    {p : α → Prop} (h : filter.eventually (fun (x : α) => p x) at_bot) :
    ∃ (a : α), ∀ (b : α), b ≤ a → p b :=
  iff.mp eventually_at_bot h

theorem frequently_at_top {α : Type u_3} [semilattice_sup α] [Nonempty α] {p : α → Prop} :
    filter.frequently (fun (x : α) => p x) at_top ↔ ∀ (a : α), ∃ (b : α), ∃ (H : b ≥ a), p b :=
  sorry

theorem frequently_at_bot {α : Type u_3} [semilattice_inf α] [Nonempty α] {p : α → Prop} :
    filter.frequently (fun (x : α) => p x) at_bot ↔ ∀ (a : α), ∃ (b : α), ∃ (H : b ≤ a), p b :=
  frequently_at_top

theorem frequently_at_top' {α : Type u_3} [semilattice_sup α] [Nonempty α] [no_top_order α]
    {p : α → Prop} :
    filter.frequently (fun (x : α) => p x) at_top ↔ ∀ (a : α), ∃ (b : α), ∃ (H : b > a), p b :=
  sorry

theorem frequently_at_bot' {α : Type u_3} [semilattice_inf α] [Nonempty α] [no_bot_order α]
    {p : α → Prop} :
    filter.frequently (fun (x : α) => p x) at_bot ↔ ∀ (a : α), ∃ (b : α), ∃ (H : b < a), p b :=
  frequently_at_top'

theorem frequently.forall_exists_of_at_top {α : Type u_3} [semilattice_sup α] [Nonempty α]
    {p : α → Prop} (h : filter.frequently (fun (x : α) => p x) at_top) (a : α) :
    ∃ (b : α), ∃ (H : b ≥ a), p b :=
  iff.mp frequently_at_top h

theorem frequently.forall_exists_of_at_bot {α : Type u_3} [semilattice_inf α] [Nonempty α]
    {p : α → Prop} (h : filter.frequently (fun (x : α) => p x) at_bot) (a : α) :
    ∃ (b : α), ∃ (H : b ≤ a), p b :=
  iff.mp frequently_at_bot h

theorem map_at_top_eq {α : Type u_3} {β : Type u_4} [Nonempty α] [semilattice_sup α] {f : α → β} :
    map f at_top = infi fun (a : α) => principal (f '' set_of fun (a' : α) => a ≤ a') :=
  has_basis.eq_infi (has_basis.map f at_top_basis)

theorem map_at_bot_eq {α : Type u_3} {β : Type u_4} [Nonempty α] [semilattice_inf α] {f : α → β} :
    map f at_bot = infi fun (a : α) => principal (f '' set_of fun (a' : α) => a' ≤ a) :=
  map_at_top_eq

theorem tendsto_at_top {α : Type u_3} {β : Type u_4} [preorder β] {m : α → β} {f : filter α} :
    tendsto m f at_top ↔ ∀ (b : β), filter.eventually (fun (a : α) => b ≤ m a) f :=
  sorry

theorem tendsto_at_bot {α : Type u_3} {β : Type u_4} [preorder β] {m : α → β} {f : filter α} :
    tendsto m f at_bot ↔ ∀ (b : β), filter.eventually (fun (a : α) => m a ≤ b) f :=
  tendsto_at_top

theorem tendsto_at_top_mono' {α : Type u_3} {β : Type u_4} [preorder β] (l : filter α) {f₁ : α → β}
    {f₂ : α → β} (h : eventually_le l f₁ f₂) : tendsto f₁ l at_top → tendsto f₂ l at_top :=
  sorry

theorem tendsto_at_bot_mono' {α : Type u_3} {β : Type u_4} [preorder β] (l : filter α) {f₁ : α → β}
    {f₂ : α → β} (h : eventually_le l f₁ f₂) : tendsto f₂ l at_bot → tendsto f₁ l at_bot :=
  tendsto_at_top_mono' l h

theorem tendsto_at_top_mono {α : Type u_3} {β : Type u_4} [preorder β] {l : filter α} {f : α → β}
    {g : α → β} (h : ∀ (n : α), f n ≤ g n) : tendsto f l at_top → tendsto g l at_top :=
  tendsto_at_top_mono' l (eventually_of_forall h)

theorem tendsto_at_bot_mono {α : Type u_3} {β : Type u_4} [preorder β] {l : filter α} {f : α → β}
    {g : α → β} (h : ∀ (n : α), f n ≤ g n) : tendsto g l at_bot → tendsto f l at_bot :=
  tendsto_at_top_mono h

/-!
### Sequences
-/

theorem inf_map_at_top_ne_bot_iff {α : Type u_3} {β : Type u_4} [semilattice_sup α] [Nonempty α]
    {F : filter β} {u : α → β} :
    ne_bot (F ⊓ map u at_top) ↔
        ∀ (U : set β) (H : U ∈ F) (N : α), ∃ (n : α), ∃ (H : n ≥ N), u n ∈ U :=
  sorry

theorem inf_map_at_bot_ne_bot_iff {α : Type u_3} {β : Type u_4} [semilattice_inf α] [Nonempty α]
    {F : filter β} {u : α → β} :
    ne_bot (F ⊓ map u at_bot) ↔
        ∀ (U : set β) (H : U ∈ F) (N : α), ∃ (n : α), ∃ (H : n ≤ N), u n ∈ U :=
  inf_map_at_top_ne_bot_iff

theorem extraction_of_frequently_at_top' {P : ℕ → Prop}
    (h : ∀ (N : ℕ), ∃ (n : ℕ), ∃ (H : n > N), P n) :
    ∃ (φ : ℕ → ℕ), strict_mono φ ∧ ∀ (n : ℕ), P (φ n) :=
  sorry

theorem extraction_of_frequently_at_top {P : ℕ → Prop}
    (h : filter.frequently (fun (n : ℕ) => P n) at_top) :
    ∃ (φ : ℕ → ℕ), strict_mono φ ∧ ∀ (n : ℕ), P (φ n) :=
  extraction_of_frequently_at_top'
    (eq.mp
      (Eq._oldrec (Eq.refl (filter.frequently (fun (n : ℕ) => P n) at_top))
        (propext frequently_at_top'))
      h)

theorem extraction_of_eventually_at_top {P : ℕ → Prop}
    (h : filter.eventually (fun (n : ℕ) => P n) at_top) :
    ∃ (φ : ℕ → ℕ), strict_mono φ ∧ ∀ (n : ℕ), P (φ n) :=
  extraction_of_frequently_at_top (eventually.frequently h)

theorem exists_le_of_tendsto_at_top {α : Type u_3} {β : Type u_4} [semilattice_sup α] [preorder β]
    {u : α → β} (h : tendsto u at_top at_top) (a : α) (b : β) :
    ∃ (a' : α), ∃ (H : a' ≥ a), b ≤ u a' :=
  sorry

theorem exists_le_of_tendsto_at_bot {α : Type u_3} {β : Type u_4} [semilattice_sup α] [preorder β]
    {u : α → β} (h : tendsto u at_top at_bot) (a : α) (b : β) :
    ∃ (a' : α), ∃ (H : a' ≥ a), u a' ≤ b :=
  exists_le_of_tendsto_at_top h

theorem exists_lt_of_tendsto_at_top {α : Type u_3} {β : Type u_4} [semilattice_sup α] [preorder β]
    [no_top_order β] {u : α → β} (h : tendsto u at_top at_top) (a : α) (b : β) :
    ∃ (a' : α), ∃ (H : a' ≥ a), b < u a' :=
  sorry

theorem exists_lt_of_tendsto_at_bot {α : Type u_3} {β : Type u_4} [semilattice_sup α] [preorder β]
    [no_bot_order β] {u : α → β} (h : tendsto u at_top at_bot) (a : α) (b : β) :
    ∃ (a' : α), ∃ (H : a' ≥ a), u a' < b :=
  exists_lt_of_tendsto_at_top h

/--
If `u` is a sequence which is unbounded above,
then after any point, it reaches a value strictly greater than all previous values.
-/
theorem high_scores {β : Type u_4} [linear_order β] [no_top_order β] {u : ℕ → β}
    (hu : tendsto u at_top at_top) (N : ℕ) :
    ∃ (n : ℕ), ∃ (H : n ≥ N), ∀ (k : ℕ), k < n → u k < u n :=
  sorry

/--
If `u` is a sequence which is unbounded below,
then after any point, it reaches a value strictly smaller than all previous values.
-/
theorem low_scores {β : Type u_4} [linear_order β] [no_bot_order β] {u : ℕ → β}
    (hu : tendsto u at_top at_bot) (N : ℕ) :
    ∃ (n : ℕ), ∃ (H : n ≥ N), ∀ (k : ℕ), k < n → u n < u k :=
  high_scores hu

/--
If `u` is a sequence which is unbounded above,
then it `frequently` reaches a value strictly greater than all previous values.
-/
theorem frequently_high_scores {β : Type u_4} [linear_order β] [no_top_order β] {u : ℕ → β}
    (hu : tendsto u at_top at_top) :
    filter.frequently (fun (n : ℕ) => ∀ (k : ℕ), k < n → u k < u n) at_top :=
  sorry

/--
If `u` is a sequence which is unbounded below,
then it `frequently` reaches a value strictly smaller than all previous values.
-/
theorem frequently_low_scores {β : Type u_4} [linear_order β] [no_bot_order β] {u : ℕ → β}
    (hu : tendsto u at_top at_bot) :
    filter.frequently (fun (n : ℕ) => ∀ (k : ℕ), k < n → u n < u k) at_top :=
  frequently_high_scores hu

theorem strict_mono_subseq_of_tendsto_at_top {β : Type u_1} [linear_order β] [no_top_order β]
    {u : ℕ → β} (hu : tendsto u at_top at_top) :
    ∃ (φ : ℕ → ℕ), strict_mono φ ∧ strict_mono (u ∘ φ) :=
  sorry

theorem strict_mono_subseq_of_id_le {u : ℕ → ℕ} (hu : ∀ (n : ℕ), n ≤ u n) :
    ∃ (φ : ℕ → ℕ), strict_mono φ ∧ strict_mono (u ∘ φ) :=
  strict_mono_subseq_of_tendsto_at_top (tendsto_at_top_mono hu tendsto_id)

theorem strict_mono_tendsto_at_top {φ : ℕ → ℕ} (h : strict_mono φ) : tendsto φ at_top at_top :=
  tendsto_at_top_mono (strict_mono.id_le h) tendsto_id

theorem tendsto_at_top_add_nonneg_left' {α : Type u_3} {β : Type u_4} [ordered_add_comm_monoid β]
    {l : filter α} {f : α → β} {g : α → β} (hf : filter.eventually (fun (x : α) => 0 ≤ f x) l)
    (hg : tendsto g l at_top) : tendsto (fun (x : α) => f x + g x) l at_top :=
  tendsto_at_top_mono' l (eventually.mono hf fun (x : α) => le_add_of_nonneg_left) hg

theorem tendsto_at_bot_add_nonpos_left' {α : Type u_3} {β : Type u_4} [ordered_add_comm_monoid β]
    {l : filter α} {f : α → β} {g : α → β} (hf : filter.eventually (fun (x : α) => f x ≤ 0) l)
    (hg : tendsto g l at_bot) : tendsto (fun (x : α) => f x + g x) l at_bot :=
  tendsto_at_top_add_nonneg_left' hf hg

theorem tendsto_at_top_add_nonneg_left {α : Type u_3} {β : Type u_4} [ordered_add_comm_monoid β]
    {l : filter α} {f : α → β} {g : α → β} (hf : ∀ (x : α), 0 ≤ f x) (hg : tendsto g l at_top) :
    tendsto (fun (x : α) => f x + g x) l at_top :=
  tendsto_at_top_add_nonneg_left' (eventually_of_forall hf) hg

theorem tendsto_at_bot_add_nonpos_left {α : Type u_3} {β : Type u_4} [ordered_add_comm_monoid β]
    {l : filter α} {f : α → β} {g : α → β} (hf : ∀ (x : α), f x ≤ 0) (hg : tendsto g l at_bot) :
    tendsto (fun (x : α) => f x + g x) l at_bot :=
  tendsto_at_top_add_nonneg_left hf hg

theorem tendsto_at_top_add_nonneg_right' {α : Type u_3} {β : Type u_4} [ordered_add_comm_monoid β]
    {l : filter α} {f : α → β} {g : α → β} (hf : tendsto f l at_top)
    (hg : filter.eventually (fun (x : α) => 0 ≤ g x) l) :
    tendsto (fun (x : α) => f x + g x) l at_top :=
  tendsto_at_top_mono' l (monotone_mem_sets (fun (x : α) => le_add_of_nonneg_right) hg) hf

theorem tendsto_at_bot_add_nonpos_right' {α : Type u_3} {β : Type u_4} [ordered_add_comm_monoid β]
    {l : filter α} {f : α → β} {g : α → β} (hf : tendsto f l at_bot)
    (hg : filter.eventually (fun (x : α) => g x ≤ 0) l) :
    tendsto (fun (x : α) => f x + g x) l at_bot :=
  tendsto_at_top_add_nonneg_right' hf hg

theorem tendsto_at_top_add_nonneg_right {α : Type u_3} {β : Type u_4} [ordered_add_comm_monoid β]
    {l : filter α} {f : α → β} {g : α → β} (hf : tendsto f l at_top) (hg : ∀ (x : α), 0 ≤ g x) :
    tendsto (fun (x : α) => f x + g x) l at_top :=
  tendsto_at_top_add_nonneg_right' hf (eventually_of_forall hg)

theorem tendsto_at_bot_add_nonpos_right {α : Type u_3} {β : Type u_4} [ordered_add_comm_monoid β]
    {l : filter α} {f : α → β} {g : α → β} (hf : tendsto f l at_bot) (hg : ∀ (x : α), g x ≤ 0) :
    tendsto (fun (x : α) => f x + g x) l at_bot :=
  tendsto_at_top_add_nonneg_right hf hg

theorem tendsto_at_top_add {α : Type u_3} {β : Type u_4} [ordered_add_comm_monoid β] {l : filter α}
    {f : α → β} {g : α → β} (hf : tendsto f l at_top) (hg : tendsto g l at_top) :
    tendsto (fun (x : α) => f x + g x) l at_top :=
  tendsto_at_top_add_nonneg_left' (iff.mp tendsto_at_top hf 0) hg

theorem tendsto_at_bot_add {α : Type u_3} {β : Type u_4} [ordered_add_comm_monoid β] {l : filter α}
    {f : α → β} {g : α → β} (hf : tendsto f l at_bot) (hg : tendsto g l at_bot) :
    tendsto (fun (x : α) => f x + g x) l at_bot :=
  tendsto_at_top_add hf hg

theorem tendsto.nsmul_at_top {α : Type u_3} {β : Type u_4} [ordered_add_comm_monoid β]
    {l : filter α} {f : α → β} (hf : tendsto f l at_top) {n : ℕ} (hn : 0 < n) :
    tendsto (fun (x : α) => n •ℕ f x) l at_top :=
  sorry

theorem tendsto.nsmul_at_bot {α : Type u_3} {β : Type u_4} [ordered_add_comm_monoid β]
    {l : filter α} {f : α → β} (hf : tendsto f l at_bot) {n : ℕ} (hn : 0 < n) :
    tendsto (fun (x : α) => n •ℕ f x) l at_bot :=
  tendsto.nsmul_at_top hf hn

theorem tendsto_bit0_at_top {β : Type u_4} [ordered_add_comm_monoid β] :
    tendsto bit0 at_top at_top :=
  tendsto_at_top_add tendsto_id tendsto_id

theorem tendsto_bit0_at_bot {β : Type u_4} [ordered_add_comm_monoid β] :
    tendsto bit0 at_bot at_bot :=
  tendsto_at_bot_add tendsto_id tendsto_id

theorem tendsto_at_top_of_add_const_left {α : Type u_3} {β : Type u_4}
    [ordered_cancel_add_comm_monoid β] {l : filter α} {f : α → β} (C : β)
    (hf : tendsto (fun (x : α) => C + f x) l at_top) : tendsto f l at_top :=
  iff.mpr tendsto_at_top
    fun (b : β) =>
      eventually.mono (iff.mp tendsto_at_top hf (C + b)) fun (x : α) => le_of_add_le_add_left

theorem tendsto_at_bot_of_add_const_left {α : Type u_3} {β : Type u_4}
    [ordered_cancel_add_comm_monoid β] {l : filter α} {f : α → β} (C : β)
    (hf : tendsto (fun (x : α) => C + f x) l at_bot) : tendsto f l at_bot :=
  tendsto_at_top_of_add_const_left C hf

theorem tendsto_at_top_of_add_const_right {α : Type u_3} {β : Type u_4}
    [ordered_cancel_add_comm_monoid β] {l : filter α} {f : α → β} (C : β)
    (hf : tendsto (fun (x : α) => f x + C) l at_top) : tendsto f l at_top :=
  iff.mpr tendsto_at_top
    fun (b : β) =>
      eventually.mono (iff.mp tendsto_at_top hf (b + C)) fun (x : α) => le_of_add_le_add_right

theorem tendsto_at_bot_of_add_const_right {α : Type u_3} {β : Type u_4}
    [ordered_cancel_add_comm_monoid β] {l : filter α} {f : α → β} (C : β)
    (hf : tendsto (fun (x : α) => f x + C) l at_bot) : tendsto f l at_bot :=
  tendsto_at_top_of_add_const_right C hf

theorem tendsto_at_top_of_add_bdd_above_left' {α : Type u_3} {β : Type u_4}
    [ordered_cancel_add_comm_monoid β] {l : filter α} {f : α → β} {g : α → β} (C : β)
    (hC : filter.eventually (fun (x : α) => f x ≤ C) l)
    (h : tendsto (fun (x : α) => f x + g x) l at_top) : tendsto g l at_top :=
  tendsto_at_top_of_add_const_left C
    (tendsto_at_top_mono' l
      (eventually.mono hC fun (x : α) (hx : f x ≤ C) => add_le_add_right hx (g x)) h)

theorem tendsto_at_bot_of_add_bdd_below_left' {α : Type u_3} {β : Type u_4}
    [ordered_cancel_add_comm_monoid β] {l : filter α} {f : α → β} {g : α → β} (C : β)
    (hC : filter.eventually (fun (x : α) => C ≤ f x) l)
    (h : tendsto (fun (x : α) => f x + g x) l at_bot) : tendsto g l at_bot :=
  tendsto_at_top_of_add_bdd_above_left' C hC h

theorem tendsto_at_top_of_add_bdd_above_left {α : Type u_3} {β : Type u_4}
    [ordered_cancel_add_comm_monoid β] {l : filter α} {f : α → β} {g : α → β} (C : β)
    (hC : ∀ (x : α), f x ≤ C) : tendsto (fun (x : α) => f x + g x) l at_top → tendsto g l at_top :=
  tendsto_at_top_of_add_bdd_above_left' C (univ_mem_sets' hC)

theorem tendsto_at_bot_of_add_bdd_below_left {α : Type u_3} {β : Type u_4}
    [ordered_cancel_add_comm_monoid β] {l : filter α} {f : α → β} {g : α → β} (C : β)
    (hC : ∀ (x : α), C ≤ f x) : tendsto (fun (x : α) => f x + g x) l at_bot → tendsto g l at_bot :=
  tendsto_at_top_of_add_bdd_above_left C hC

theorem tendsto_at_top_of_add_bdd_above_right' {α : Type u_3} {β : Type u_4}
    [ordered_cancel_add_comm_monoid β] {l : filter α} {f : α → β} {g : α → β} (C : β)
    (hC : filter.eventually (fun (x : α) => g x ≤ C) l)
    (h : tendsto (fun (x : α) => f x + g x) l at_top) : tendsto f l at_top :=
  tendsto_at_top_of_add_const_right C
    (tendsto_at_top_mono' l
      (eventually.mono hC fun (x : α) (hx : g x ≤ C) => add_le_add_left hx (f x)) h)

theorem tendsto_at_bot_of_add_bdd_below_right' {α : Type u_3} {β : Type u_4}
    [ordered_cancel_add_comm_monoid β] {l : filter α} {f : α → β} {g : α → β} (C : β)
    (hC : filter.eventually (fun (x : α) => C ≤ g x) l)
    (h : tendsto (fun (x : α) => f x + g x) l at_bot) : tendsto f l at_bot :=
  tendsto_at_top_of_add_bdd_above_right' C hC h

theorem tendsto_at_top_of_add_bdd_above_right {α : Type u_3} {β : Type u_4}
    [ordered_cancel_add_comm_monoid β] {l : filter α} {f : α → β} {g : α → β} (C : β)
    (hC : ∀ (x : α), g x ≤ C) : tendsto (fun (x : α) => f x + g x) l at_top → tendsto f l at_top :=
  tendsto_at_top_of_add_bdd_above_right' C (univ_mem_sets' hC)

theorem tendsto_at_bot_of_add_bdd_below_right {α : Type u_3} {β : Type u_4}
    [ordered_cancel_add_comm_monoid β] {l : filter α} {f : α → β} {g : α → β} (C : β)
    (hC : ∀ (x : α), C ≤ g x) : tendsto (fun (x : α) => f x + g x) l at_bot → tendsto f l at_bot :=
  tendsto_at_top_of_add_bdd_above_right C hC

theorem tendsto_at_top_add_left_of_le' {α : Type u_3} {β : Type u_4} [ordered_add_comm_group β]
    (l : filter α) {f : α → β} {g : α → β} (C : β)
    (hf : filter.eventually (fun (x : α) => C ≤ f x) l) (hg : tendsto g l at_top) :
    tendsto (fun (x : α) => f x + g x) l at_top :=
  sorry

theorem tendsto_at_bot_add_left_of_ge' {α : Type u_3} {β : Type u_4} [ordered_add_comm_group β]
    (l : filter α) {f : α → β} {g : α → β} (C : β)
    (hf : filter.eventually (fun (x : α) => f x ≤ C) l) (hg : tendsto g l at_bot) :
    tendsto (fun (x : α) => f x + g x) l at_bot :=
  tendsto_at_top_add_left_of_le' l C hf hg

theorem tendsto_at_top_add_left_of_le {α : Type u_3} {β : Type u_4} [ordered_add_comm_group β]
    (l : filter α) {f : α → β} {g : α → β} (C : β) (hf : ∀ (x : α), C ≤ f x)
    (hg : tendsto g l at_top) : tendsto (fun (x : α) => f x + g x) l at_top :=
  tendsto_at_top_add_left_of_le' l C (univ_mem_sets' hf) hg

theorem tendsto_at_bot_add_left_of_ge {α : Type u_3} {β : Type u_4} [ordered_add_comm_group β]
    (l : filter α) {f : α → β} {g : α → β} (C : β) (hf : ∀ (x : α), f x ≤ C)
    (hg : tendsto g l at_bot) : tendsto (fun (x : α) => f x + g x) l at_bot :=
  tendsto_at_top_add_left_of_le l C hf hg

theorem tendsto_at_top_add_right_of_le' {α : Type u_3} {β : Type u_4} [ordered_add_comm_group β]
    (l : filter α) {f : α → β} {g : α → β} (C : β) (hf : tendsto f l at_top)
    (hg : filter.eventually (fun (x : α) => C ≤ g x) l) :
    tendsto (fun (x : α) => f x + g x) l at_top :=
  sorry

theorem tendsto_at_bot_add_right_of_ge' {α : Type u_3} {β : Type u_4} [ordered_add_comm_group β]
    (l : filter α) {f : α → β} {g : α → β} (C : β) (hf : tendsto f l at_bot)
    (hg : filter.eventually (fun (x : α) => g x ≤ C) l) :
    tendsto (fun (x : α) => f x + g x) l at_bot :=
  tendsto_at_top_add_right_of_le' l C hf hg

theorem tendsto_at_top_add_right_of_le {α : Type u_3} {β : Type u_4} [ordered_add_comm_group β]
    (l : filter α) {f : α → β} {g : α → β} (C : β) (hf : tendsto f l at_top)
    (hg : ∀ (x : α), C ≤ g x) : tendsto (fun (x : α) => f x + g x) l at_top :=
  tendsto_at_top_add_right_of_le' l C hf (univ_mem_sets' hg)

theorem tendsto_at_bot_add_right_of_ge {α : Type u_3} {β : Type u_4} [ordered_add_comm_group β]
    (l : filter α) {f : α → β} {g : α → β} (C : β) (hf : tendsto f l at_bot)
    (hg : ∀ (x : α), g x ≤ C) : tendsto (fun (x : α) => f x + g x) l at_bot :=
  tendsto_at_top_add_right_of_le l C hf hg

theorem tendsto_at_top_add_const_left {α : Type u_3} {β : Type u_4} [ordered_add_comm_group β]
    (l : filter α) {f : α → β} (C : β) (hf : tendsto f l at_top) :
    tendsto (fun (x : α) => C + f x) l at_top :=
  tendsto_at_top_add_left_of_le' l C (univ_mem_sets' fun (_x : α) => le_refl C) hf

theorem tendsto_at_bot_add_const_left {α : Type u_3} {β : Type u_4} [ordered_add_comm_group β]
    (l : filter α) {f : α → β} (C : β) (hf : tendsto f l at_bot) :
    tendsto (fun (x : α) => C + f x) l at_bot :=
  tendsto_at_top_add_const_left l C hf

theorem tendsto_at_top_add_const_right {α : Type u_3} {β : Type u_4} [ordered_add_comm_group β]
    (l : filter α) {f : α → β} (C : β) (hf : tendsto f l at_top) :
    tendsto (fun (x : α) => f x + C) l at_top :=
  tendsto_at_top_add_right_of_le' l C hf (univ_mem_sets' fun (_x : α) => le_refl C)

theorem tendsto_at_bot_add_const_right {α : Type u_3} {β : Type u_4} [ordered_add_comm_group β]
    (l : filter α) {f : α → β} (C : β) (hf : tendsto f l at_bot) :
    tendsto (fun (x : α) => f x + C) l at_bot :=
  tendsto_at_top_add_const_right l C hf

theorem tendsto_neg_at_top_at_bot {β : Type u_4} [ordered_add_comm_group β] :
    tendsto Neg.neg at_top at_bot :=
  sorry

theorem tendsto_neg_at_bot_at_top {β : Type u_4} [ordered_add_comm_group β] :
    tendsto Neg.neg at_bot at_top :=
  tendsto_neg_at_top_at_bot

theorem tendsto_bit1_at_top {α : Type u_3} [ordered_semiring α] : tendsto bit1 at_top at_top :=
  tendsto_at_top_add_nonneg_right tendsto_bit0_at_top fun (_x : α) => zero_le_one

theorem tendsto.at_top_mul_at_top {α : Type u_3} {β : Type u_4} [ordered_semiring α] {l : filter β}
    {f : β → α} {g : β → α} (hf : tendsto f l at_top) (hg : tendsto g l at_top) :
    tendsto (fun (x : β) => f x * g x) l at_top :=
  sorry

theorem tendsto_mul_self_at_top {α : Type u_3} [ordered_semiring α] :
    tendsto (fun (x : α) => x * x) at_top at_top :=
  tendsto.at_top_mul_at_top tendsto_id tendsto_id

/-- The monomial function `x^n` tends to `+∞` at `+∞` for any positive natural `n`.
A version for positive real powers exists as `tendsto_rpow_at_top`. -/
theorem tendsto_pow_at_top {α : Type u_3} [ordered_semiring α] {n : ℕ} (hn : 1 ≤ n) :
    tendsto (fun (x : α) => x ^ n) at_top at_top :=
  sorry

theorem zero_pow_eventually_eq {α : Type u_3} [monoid_with_zero α] :
    eventually_eq at_top (fun (n : ℕ) => 0 ^ n) fun (n : ℕ) => 0 :=
  iff.mpr eventually_at_top
    (Exists.intro 1 fun (n : ℕ) (hn : n ≥ 1) => zero_pow (has_lt.lt.trans_le zero_lt_one hn))

theorem tendsto.at_top_mul_at_bot {α : Type u_3} {β : Type u_4} [ordered_ring α] {l : filter β}
    {f : β → α} {g : β → α} (hf : tendsto f l at_top) (hg : tendsto g l at_bot) :
    tendsto (fun (x : β) => f x * g x) l at_bot :=
  sorry

theorem tendsto.at_bot_mul_at_top {α : Type u_3} {β : Type u_4} [ordered_ring α] {l : filter β}
    {f : β → α} {g : β → α} (hf : tendsto f l at_bot) (hg : tendsto g l at_top) :
    tendsto (fun (x : β) => f x * g x) l at_bot :=
  sorry

theorem tendsto.at_bot_mul_at_bot {α : Type u_3} {β : Type u_4} [ordered_ring α] {l : filter β}
    {f : β → α} {g : β → α} (hf : tendsto f l at_bot) (hg : tendsto g l at_bot) :
    tendsto (fun (x : β) => f x * g x) l at_top :=
  sorry

/-- $\lim_{x\to+\infty}|x|=+\infty$ -/
theorem tendsto_abs_at_top_at_top {α : Type u_3} [linear_ordered_add_comm_group α] :
    tendsto abs at_top at_top :=
  tendsto_at_top_mono le_abs_self tendsto_id

/-- $\lim_{x\to-\infty}|x|=+\infty$ -/
theorem tendsto_abs_at_bot_at_top {α : Type u_3} [linear_ordered_add_comm_group α] :
    tendsto abs at_bot at_top :=
  tendsto_at_top_mono neg_le_abs_self tendsto_neg_at_bot_at_top

theorem tendsto.at_top_of_const_mul {α : Type u_3} {β : Type u_4} [linear_ordered_semiring α]
    {l : filter β} {f : β → α} {c : α} (hc : 0 < c)
    (hf : tendsto (fun (x : β) => c * f x) l at_top) : tendsto f l at_top :=
  iff.mpr tendsto_at_top
    fun (b : α) =>
      eventually.mono (iff.mp tendsto_at_top hf (c * b))
        fun (x : β) (hx : c * b ≤ c * f x) => le_of_mul_le_mul_left hx hc

theorem tendsto.at_top_of_mul_const {α : Type u_3} {β : Type u_4} [linear_ordered_semiring α]
    {l : filter β} {f : β → α} {c : α} (hc : 0 < c)
    (hf : tendsto (fun (x : β) => f x * c) l at_top) : tendsto f l at_top :=
  sorry

theorem nonneg_of_eventually_pow_nonneg {α : Type u_3} [linear_ordered_ring α] {a : α}
    (h : filter.eventually (fun (n : ℕ) => 0 ≤ a ^ n) at_top) : 0 ≤ a :=
  (fun (_a : ∃ (x : ℕ), (fun (x : ℕ) => 0 ≤ a ^ bit1 x) x) =>
      Exists.dcases_on _a
        fun (w : ℕ) (h_1 : 0 ≤ a ^ bit1 w) => idRhs (0 ≤ a) (iff.mp pow_bit1_nonneg_iff h_1))
    (eventually.exists (tendsto.eventually tendsto_bit1_at_top h))

/-- If a function tends to infinity along a filter, then this function multiplied by a positive
constant (on the left) also tends to infinity. For a version working in `ℕ` or `ℤ`, use
`filter.tendsto.const_mul_at_top'` instead. -/
theorem tendsto.const_mul_at_top {α : Type u_3} {β : Type u_4} [linear_ordered_field α]
    {l : filter β} {f : β → α} {r : α} (hr : 0 < r) (hf : tendsto f l at_top) :
    tendsto (fun (x : β) => r * f x) l at_top :=
  sorry

/-- If a function tends to infinity along a filter, then this function multiplied by a positive
constant (on the right) also tends to infinity. For a version working in `ℕ` or `ℤ`, use
`filter.tendsto.at_top_mul_const'` instead. -/
theorem tendsto.at_top_mul_const {α : Type u_3} {β : Type u_4} [linear_ordered_field α]
    {l : filter β} {f : β → α} {r : α} (hr : 0 < r) (hf : tendsto f l at_top) :
    tendsto (fun (x : β) => f x * r) l at_top :=
  sorry

/-- If a function tends to infinity along a filter, then this function divided by a positive
constant also tends to infinity. -/
theorem tendsto.at_top_div_const {α : Type u_3} {β : Type u_4} [linear_ordered_field α]
    {l : filter β} {f : β → α} {r : α} (hr : 0 < r) (hf : tendsto f l at_top) :
    tendsto (fun (x : β) => f x / r) l at_top :=
  tendsto.at_top_mul_const (iff.mpr inv_pos hr) hf

/-- If a function tends to infinity along a filter, then this function multiplied by a negative
constant (on the left) tends to negative infinity. -/
theorem tendsto.neg_const_mul_at_top {α : Type u_3} {β : Type u_4} [linear_ordered_field α]
    {l : filter β} {f : β → α} {r : α} (hr : r < 0) (hf : tendsto f l at_top) :
    tendsto (fun (x : β) => r * f x) l at_bot :=
  sorry

/-- If a function tends to infinity along a filter, then this function multiplied by a negative
constant (on the right) tends to negative infinity. -/
theorem tendsto.at_top_mul_neg_const {α : Type u_3} {β : Type u_4} [linear_ordered_field α]
    {l : filter β} {f : β → α} {r : α} (hr : r < 0) (hf : tendsto f l at_top) :
    tendsto (fun (x : β) => f x * r) l at_bot :=
  sorry

/-- If a function tends to negative infinity along a filter, then this function multiplied by
a positive constant (on the left) also tends to negative infinity. -/
theorem tendsto.const_mul_at_bot {α : Type u_3} {β : Type u_4} [linear_ordered_field α]
    {l : filter β} {f : β → α} {r : α} (hr : 0 < r) (hf : tendsto f l at_bot) :
    tendsto (fun (x : β) => r * f x) l at_bot :=
  sorry

/-- If a function tends to negative infinity along a filter, then this function multiplied by
a positive constant (on the right) also tends to negative infinity. -/
theorem tendsto.at_bot_mul_const {α : Type u_3} {β : Type u_4} [linear_ordered_field α]
    {l : filter β} {f : β → α} {r : α} (hr : 0 < r) (hf : tendsto f l at_bot) :
    tendsto (fun (x : β) => f x * r) l at_bot :=
  sorry

/-- If a function tends to negative infinity along a filter, then this function divided by
a positive constant also tends to negative infinity. -/
theorem tendsto.at_bot_div_const {α : Type u_3} {β : Type u_4} [linear_ordered_field α]
    {l : filter β} {f : β → α} {r : α} (hr : 0 < r) (hf : tendsto f l at_bot) :
    tendsto (fun (x : β) => f x / r) l at_bot :=
  tendsto.at_bot_mul_const (iff.mpr inv_pos hr) hf

/-- If a function tends to negative infinity along a filter, then this function multiplied by
a negative constant (on the left) tends to positive infinity. -/
theorem tendsto.neg_const_mul_at_bot {α : Type u_3} {β : Type u_4} [linear_ordered_field α]
    {l : filter β} {f : β → α} {r : α} (hr : r < 0) (hf : tendsto f l at_bot) :
    tendsto (fun (x : β) => r * f x) l at_top :=
  sorry

/-- If a function tends to negative infinity along a filter, then this function multiplied by
a negative constant (on the right) tends to positive infinity. -/
theorem tendsto.at_bot_mul_neg_const {α : Type u_3} {β : Type u_4} [linear_ordered_field α]
    {l : filter β} {f : β → α} {r : α} (hr : r < 0) (hf : tendsto f l at_bot) :
    tendsto (fun (x : β) => f x * r) l at_top :=
  sorry

theorem tendsto_at_top' {α : Type u_3} {β : Type u_4} [Nonempty α] [semilattice_sup α] {f : α → β}
    {l : filter β} :
    tendsto f at_top l ↔ ∀ (s : set β), s ∈ l → ∃ (a : α), ∀ (b : α), b ≥ a → f b ∈ s :=
  sorry

theorem tendsto_at_bot' {α : Type u_3} {β : Type u_4} [Nonempty α] [semilattice_inf α] {f : α → β}
    {l : filter β} :
    tendsto f at_bot l ↔ ∀ (s : set β), s ∈ l → ∃ (a : α), ∀ (b : α), b ≤ a → f b ∈ s :=
  tendsto_at_top'

theorem tendsto_at_top_principal {α : Type u_3} {β : Type u_4} [Nonempty β] [semilattice_sup β]
    {f : β → α} {s : set α} :
    tendsto f at_top (principal s) ↔ ∃ (N : β), ∀ (n : β), n ≥ N → f n ∈ s :=
  sorry

theorem tendsto_at_bot_principal {α : Type u_3} {β : Type u_4} [Nonempty β] [semilattice_inf β]
    {f : β → α} {s : set α} :
    tendsto f at_bot (principal s) ↔ ∃ (N : β), ∀ (n : β), n ≤ N → f n ∈ s :=
  tendsto_at_top_principal

/-- A function `f` grows to `+∞` independent of an order-preserving embedding `e`. -/
theorem tendsto_at_top_at_top {α : Type u_3} {β : Type u_4} [Nonempty α] [semilattice_sup α]
    [preorder β] {f : α → β} :
    tendsto f at_top at_top ↔ ∀ (b : β), ∃ (i : α), ∀ (a : α), i ≤ a → b ≤ f a :=
  iff.trans tendsto_infi (forall_congr fun (b : β) => tendsto_at_top_principal)

theorem tendsto_at_top_at_bot {α : Type u_3} {β : Type u_4} [Nonempty α] [semilattice_sup α]
    [preorder β] {f : α → β} :
    tendsto f at_top at_bot ↔ ∀ (b : β), ∃ (i : α), ∀ (a : α), i ≤ a → f a ≤ b :=
  tendsto_at_top_at_top

theorem tendsto_at_bot_at_top {α : Type u_3} {β : Type u_4} [Nonempty α] [semilattice_inf α]
    [preorder β] {f : α → β} :
    tendsto f at_bot at_top ↔ ∀ (b : β), ∃ (i : α), ∀ (a : α), a ≤ i → b ≤ f a :=
  tendsto_at_top_at_top

theorem tendsto_at_bot_at_bot {α : Type u_3} {β : Type u_4} [Nonempty α] [semilattice_inf α]
    [preorder β] {f : α → β} :
    tendsto f at_bot at_bot ↔ ∀ (b : β), ∃ (i : α), ∀ (a : α), a ≤ i → f a ≤ b :=
  tendsto_at_top_at_top

theorem tendsto_at_top_at_top_of_monotone {α : Type u_3} {β : Type u_4} [preorder α] [preorder β]
    {f : α → β} (hf : monotone f) (h : ∀ (b : β), ∃ (a : α), b ≤ f a) : tendsto f at_top at_top :=
  sorry

theorem tendsto_at_bot_at_bot_of_monotone {α : Type u_3} {β : Type u_4} [preorder α] [preorder β]
    {f : α → β} (hf : monotone f) (h : ∀ (b : β), ∃ (a : α), f a ≤ b) : tendsto f at_bot at_bot :=
  sorry

theorem tendsto_at_top_at_top_iff_of_monotone {α : Type u_3} {β : Type u_4} [Nonempty α]
    [semilattice_sup α] [preorder β] {f : α → β} (hf : monotone f) :
    tendsto f at_top at_top ↔ ∀ (b : β), ∃ (a : α), b ≤ f a :=
  sorry

theorem tendsto_at_bot_at_bot_iff_of_monotone {α : Type u_3} {β : Type u_4} [Nonempty α]
    [semilattice_inf α] [preorder β] {f : α → β} (hf : monotone f) :
    tendsto f at_bot at_bot ↔ ∀ (b : β), ∃ (a : α), f a ≤ b :=
  sorry

theorem Mathlib.monotone.tendsto_at_top_at_top {α : Type u_3} {β : Type u_4} [preorder α]
    [preorder β] {f : α → β} (hf : monotone f) (h : ∀ (b : β), ∃ (a : α), b ≤ f a) :
    tendsto f at_top at_top :=
  tendsto_at_top_at_top_of_monotone

theorem Mathlib.monotone.tendsto_at_bot_at_bot {α : Type u_3} {β : Type u_4} [preorder α]
    [preorder β] {f : α → β} (hf : monotone f) (h : ∀ (b : β), ∃ (a : α), f a ≤ b) :
    tendsto f at_bot at_bot :=
  tendsto_at_bot_at_bot_of_monotone

theorem Mathlib.monotone.tendsto_at_top_at_top_iff {α : Type u_3} {β : Type u_4} [Nonempty α]
    [semilattice_sup α] [preorder β] {f : α → β} (hf : monotone f) :
    tendsto f at_top at_top ↔ ∀ (b : β), ∃ (a : α), b ≤ f a :=
  tendsto_at_top_at_top_iff_of_monotone

theorem Mathlib.monotone.tendsto_at_bot_at_bot_iff {α : Type u_3} {β : Type u_4} [Nonempty α]
    [semilattice_inf α] [preorder β] {f : α → β} (hf : monotone f) :
    tendsto f at_bot at_bot ↔ ∀ (b : β), ∃ (a : α), f a ≤ b :=
  tendsto_at_bot_at_bot_iff_of_monotone

theorem tendsto_at_top_embedding {α : Type u_3} {β : Type u_4} {γ : Type u_5} [preorder β]
    [preorder γ] {f : α → β} {e : β → γ} {l : filter α} (hm : ∀ (b₁ b₂ : β), e b₁ ≤ e b₂ ↔ b₁ ≤ b₂)
    (hu : ∀ (c : γ), ∃ (b : β), c ≤ e b) : tendsto (e ∘ f) l at_top ↔ tendsto f l at_top :=
  sorry

/-- A function `f` goes to `-∞` independent of an order-preserving embedding `e`. -/
theorem tendsto_at_bot_embedding {α : Type u_3} {β : Type u_4} {γ : Type u_5} [preorder β]
    [preorder γ] {f : α → β} {e : β → γ} {l : filter α} (hm : ∀ (b₁ b₂ : β), e b₁ ≤ e b₂ ↔ b₁ ≤ b₂)
    (hu : ∀ (c : γ), ∃ (b : β), e b ≤ c) : tendsto (e ∘ f) l at_bot ↔ tendsto f l at_bot :=
  tendsto_at_top_embedding (function.swap hm) hu

theorem tendsto_finset_range : tendsto finset.range at_top at_top :=
  monotone.tendsto_at_top_at_top finset.range_mono finset.exists_nat_subset_range

theorem at_top_finset_eq_infi {α : Type u_3} :
    at_top = infi fun (x : α) => principal (set.Ici (singleton x)) :=
  sorry

/-- If `f` is a monotone sequence of `finset`s and each `x` belongs to one of `f n`, then
`tendsto f at_top at_top`. -/
theorem tendsto_at_top_finset_of_monotone {α : Type u_3} {β : Type u_4} [preorder β]
    {f : β → finset α} (h : monotone f) (h' : ∀ (x : α), ∃ (n : β), x ∈ f n) :
    tendsto f at_top at_top :=
  sorry

theorem Mathlib.monotone.tendsto_at_top_finset {α : Type u_3} {β : Type u_4} [preorder β]
    {f : β → finset α} (h : monotone f) (h' : ∀ (x : α), ∃ (n : β), x ∈ f n) :
    tendsto f at_top at_top :=
  tendsto_at_top_finset_of_monotone

theorem tendsto_finset_image_at_top_at_top {β : Type u_4} {γ : Type u_5} {i : β → γ} {j : γ → β}
    (h : function.left_inverse j i) : tendsto (finset.image j) at_top at_top :=
  sorry

theorem tendsto_finset_preimage_at_top_at_top {α : Type u_3} {β : Type u_4} {f : α → β}
    (hf : function.injective f) :
    tendsto (fun (s : finset β) => finset.preimage s f (function.injective.inj_on hf (f ⁻¹' ↑s)))
        at_top at_top :=
  monotone.tendsto_at_top_finset (finset.monotone_preimage hf)
    fun (x : α) =>
      Exists.intro (singleton (f x)) (iff.mpr finset.mem_preimage (finset.mem_singleton_self (f x)))

theorem prod_at_top_at_top_eq {β₁ : Type u_1} {β₂ : Type u_2} [semilattice_sup β₁]
    [semilattice_sup β₂] : filter.prod at_top at_top = at_top :=
  sorry

theorem prod_at_bot_at_bot_eq {β₁ : Type u_1} {β₂ : Type u_2} [semilattice_inf β₁]
    [semilattice_inf β₂] : filter.prod at_bot at_bot = at_bot :=
  prod_at_top_at_top_eq

theorem prod_map_at_top_eq {α₁ : Type u_1} {α₂ : Type u_2} {β₁ : Type u_3} {β₂ : Type u_4}
    [semilattice_sup β₁] [semilattice_sup β₂] (u₁ : β₁ → α₁) (u₂ : β₂ → α₂) :
    filter.prod (map u₁ at_top) (map u₂ at_top) = map (prod.map u₁ u₂) at_top :=
  sorry

theorem prod_map_at_bot_eq {α₁ : Type u_1} {α₂ : Type u_2} {β₁ : Type u_3} {β₂ : Type u_4}
    [semilattice_inf β₁] [semilattice_inf β₂] (u₁ : β₁ → α₁) (u₂ : β₂ → α₂) :
    filter.prod (map u₁ at_bot) (map u₂ at_bot) = map (prod.map u₁ u₂) at_bot :=
  prod_map_at_top_eq u₁ u₂

/-- A function `f` maps upwards closed sets (at_top sets) to upwards closed sets when it is a
Galois insertion. The Galois "insertion" and "connection" is weakened to only require it to be an
insertion and a connetion above `b'`. -/
theorem map_at_top_eq_of_gc {α : Type u_3} {β : Type u_4} [semilattice_sup α] [semilattice_sup β]
    {f : α → β} (g : β → α) (b' : β) (hf : monotone f)
    (gc : ∀ (a : α) (b : β), b ≥ b' → (f a ≤ b ↔ a ≤ g b)) (hgi : ∀ (b : β), b ≥ b' → b ≤ f (g b)) :
    map f at_top = at_top :=
  sorry

theorem map_at_bot_eq_of_gc {α : Type u_3} {β : Type u_4} [semilattice_inf α] [semilattice_inf β]
    {f : α → β} (g : β → α) (b' : β) (hf : monotone f)
    (gc : ∀ (a : α) (b : β), b ≤ b' → (b ≤ f a ↔ g b ≤ a)) (hgi : ∀ (b : β), b ≤ b' → f (g b) ≤ b) :
    map f at_bot = at_bot :=
  map_at_top_eq_of_gc (fun (b : β) => g b) b' (monotone.order_dual hf) gc hgi

theorem map_coe_at_top_of_Ici_subset {α : Type u_3} [semilattice_sup α] {a : α} {s : set α}
    (h : set.Ici a ⊆ s) : map coe at_top = at_top :=
  sorry

/-- The image of the filter `at_top` on `Ici a` under the coercion equals `at_top`. -/
@[simp] theorem map_coe_Ici_at_top {α : Type u_3} [semilattice_sup α] (a : α) :
    map coe at_top = at_top :=
  map_coe_at_top_of_Ici_subset (set.subset.refl (set.Ici a))

/-- The image of the filter `at_top` on `Ioi a` under the coercion equals `at_top`. -/
@[simp] theorem map_coe_Ioi_at_top {α : Type u_3} [semilattice_sup α] [no_top_order α] (a : α) :
    map coe at_top = at_top :=
  Exists.dcases_on (no_top a)
    fun (b : α) (hb : a < b) => map_coe_at_top_of_Ici_subset (iff.mpr set.Ici_subset_Ioi hb)

/-- The `at_top` filter for an open interval `Ioi a` comes from the `at_top` filter in the ambient
order. -/
theorem at_top_Ioi_eq {α : Type u_3} [semilattice_sup α] (a : α) : at_top = comap coe at_top :=
  sorry

/-- The `at_top` filter for an open interval `Ici a` comes from the `at_top` filter in the ambient
order. -/
theorem at_top_Ici_eq {α : Type u_3} [semilattice_sup α] (a : α) : at_top = comap coe at_top :=
  eq.mpr (id (Eq._oldrec (Eq.refl (at_top = comap coe at_top)) (Eq.symm (map_coe_Ici_at_top a))))
    (eq.mpr
      (id
        (Eq._oldrec (Eq.refl (at_top = comap coe (map coe at_top)))
          (comap_map subtype.coe_injective)))
      (Eq.refl at_top))

/-- The `at_bot` filter for an open interval `Iio a` comes from the `at_bot` filter in the ambient
order. -/
@[simp] theorem map_coe_Iio_at_bot {α : Type u_3} [semilattice_inf α] [no_bot_order α] (a : α) :
    map coe at_bot = at_bot :=
  map_coe_Ioi_at_top a

/-- The `at_bot` filter for an open interval `Iio a` comes from the `at_bot` filter in the ambient
order. -/
theorem at_bot_Iio_eq {α : Type u_3} [semilattice_inf α] (a : α) : at_bot = comap coe at_bot :=
  at_top_Ioi_eq a

/-- The `at_bot` filter for an open interval `Iic a` comes from the `at_bot` filter in the ambient
order. -/
@[simp] theorem map_coe_Iic_at_bot {α : Type u_3} [semilattice_inf α] (a : α) :
    map coe at_bot = at_bot :=
  map_coe_Ici_at_top a

/-- The `at_bot` filter for an open interval `Iic a` comes from the `at_bot` filter in the ambient
order. -/
theorem at_bot_Iic_eq {α : Type u_3} [semilattice_inf α] (a : α) : at_bot = comap coe at_bot :=
  at_top_Ici_eq a

theorem tendsto_Ioi_at_top {α : Type u_3} {β : Type u_4} [semilattice_sup α] {a : α}
    {f : β → ↥(set.Ioi a)} {l : filter β} :
    tendsto f l at_top ↔ tendsto (fun (x : β) => ↑(f x)) l at_top :=
  sorry

theorem tendsto_Iio_at_bot {α : Type u_3} {β : Type u_4} [semilattice_inf α] {a : α}
    {f : β → ↥(set.Iio a)} {l : filter β} :
    tendsto f l at_bot ↔ tendsto (fun (x : β) => ↑(f x)) l at_bot :=
  sorry

theorem tendsto_Ici_at_top {α : Type u_3} {β : Type u_4} [semilattice_sup α] {a : α}
    {f : β → ↥(set.Ici a)} {l : filter β} :
    tendsto f l at_top ↔ tendsto (fun (x : β) => ↑(f x)) l at_top :=
  sorry

theorem tendsto_Iic_at_bot {α : Type u_3} {β : Type u_4} [semilattice_inf α] {a : α}
    {f : β → ↥(set.Iic a)} {l : filter β} :
    tendsto f l at_bot ↔ tendsto (fun (x : β) => ↑(f x)) l at_bot :=
  sorry

@[simp] theorem tendsto_comp_coe_Ioi_at_top {α : Type u_3} {β : Type u_4} [semilattice_sup α]
    [no_top_order α] {a : α} {f : α → β} {l : filter β} :
    tendsto (fun (x : ↥(set.Ioi a)) => f ↑x) at_top l ↔ tendsto f at_top l :=
  sorry

@[simp] theorem tendsto_comp_coe_Ici_at_top {α : Type u_3} {β : Type u_4} [semilattice_sup α]
    {a : α} {f : α → β} {l : filter β} :
    tendsto (fun (x : ↥(set.Ici a)) => f ↑x) at_top l ↔ tendsto f at_top l :=
  sorry

@[simp] theorem tendsto_comp_coe_Iio_at_bot {α : Type u_3} {β : Type u_4} [semilattice_inf α]
    [no_bot_order α] {a : α} {f : α → β} {l : filter β} :
    tendsto (fun (x : ↥(set.Iio a)) => f ↑x) at_bot l ↔ tendsto f at_bot l :=
  sorry

@[simp] theorem tendsto_comp_coe_Iic_at_bot {α : Type u_3} {β : Type u_4} [semilattice_inf α]
    {a : α} {f : α → β} {l : filter β} :
    tendsto (fun (x : ↥(set.Iic a)) => f ↑x) at_bot l ↔ tendsto f at_bot l :=
  sorry

theorem map_add_at_top_eq_nat (k : ℕ) : map (fun (a : ℕ) => a + k) at_top = at_top :=
  map_at_top_eq_of_gc (fun (a : ℕ) => a - k) k (fun (a b : ℕ) (h : a ≤ b) => add_le_add_right h k)
    (fun (a b : ℕ) (h : b ≥ k) => iff.symm (nat.le_sub_right_iff_add_le h))
    fun (a : ℕ) (h : a ≥ k) =>
      eq.mpr (id (Eq._oldrec (Eq.refl (a ≤ a - k + k)) (nat.sub_add_cancel h))) (le_refl a)

theorem map_sub_at_top_eq_nat (k : ℕ) : map (fun (a : ℕ) => a - k) at_top = at_top :=
  map_at_top_eq_of_gc (fun (a : ℕ) => a + k) 0
    (fun (a b : ℕ) (h : a ≤ b) => nat.sub_le_sub_right h k)
    (fun (a b : ℕ) (_x : b ≥ 0) => nat.sub_le_right_iff_le_add)
    fun (b : ℕ) (_x : b ≥ 0) =>
      eq.mpr (id (Eq._oldrec (Eq.refl (b ≤ b + k - k)) (nat.add_sub_cancel b k))) (le_refl b)

theorem tendsto_add_at_top_nat (k : ℕ) : tendsto (fun (a : ℕ) => a + k) at_top at_top :=
  le_of_eq (map_add_at_top_eq_nat k)

theorem tendsto_sub_at_top_nat (k : ℕ) : tendsto (fun (a : ℕ) => a - k) at_top at_top :=
  le_of_eq (map_sub_at_top_eq_nat k)

theorem tendsto_add_at_top_iff_nat {α : Type u_3} {f : ℕ → α} {l : filter α} (k : ℕ) :
    tendsto (fun (n : ℕ) => f (n + k)) at_top l ↔ tendsto f at_top l :=
  sorry

theorem map_div_at_top_eq_nat (k : ℕ) (hk : 0 < k) : map (fun (a : ℕ) => a / k) at_top = at_top :=
  sorry

/-- If `u` is a monotone function with linear ordered codomain and the range of `u` is not bounded
above, then `tendsto u at_top at_top`. -/
theorem tendsto_at_top_at_top_of_monotone' {ι : Type u_1} {α : Type u_3} [preorder ι]
    [linear_order α] {u : ι → α} (h : monotone u) (H : ¬bdd_above (set.range u)) :
    tendsto u at_top at_top :=
  sorry

/-- If `u` is a monotone function with linear ordered codomain and the range of `u` is not bounded
below, then `tendsto u at_bot at_bot`. -/
theorem tendsto_at_bot_at_bot_of_monotone' {ι : Type u_1} {α : Type u_3} [preorder ι]
    [linear_order α] {u : ι → α} (h : monotone u) (H : ¬bdd_below (set.range u)) :
    tendsto u at_bot at_bot :=
  tendsto_at_top_at_top_of_monotone' (monotone.order_dual h) H

theorem unbounded_of_tendsto_at_top {α : Type u_3} {β : Type u_4} [Nonempty α] [semilattice_sup α]
    [preorder β] [no_top_order β] {f : α → β} (h : tendsto f at_top at_top) :
    ¬bdd_above (set.range f) :=
  sorry

theorem unbounded_of_tendsto_at_bot {α : Type u_3} {β : Type u_4} [Nonempty α] [semilattice_sup α]
    [preorder β] [no_bot_order β] {f : α → β} (h : tendsto f at_top at_bot) :
    ¬bdd_below (set.range f) :=
  unbounded_of_tendsto_at_top h

theorem unbounded_of_tendsto_at_top' {α : Type u_3} {β : Type u_4} [Nonempty α] [semilattice_inf α]
    [preorder β] [no_top_order β] {f : α → β} (h : tendsto f at_bot at_top) :
    ¬bdd_above (set.range f) :=
  unbounded_of_tendsto_at_top h

theorem unbounded_of_tendsto_at_bot' {α : Type u_3} {β : Type u_4} [Nonempty α] [semilattice_inf α]
    [preorder β] [no_bot_order β] {f : α → β} (h : tendsto f at_bot at_bot) :
    ¬bdd_below (set.range f) :=
  unbounded_of_tendsto_at_top h

/-- If a monotone function `u : ι → α` tends to `at_top` along *some* non-trivial filter `l`, then
it tends to `at_top` along `at_top`. -/
theorem tendsto_at_top_of_monotone_of_filter {ι : Type u_1} {α : Type u_3} [preorder ι] [preorder α]
    {l : filter ι} {u : ι → α} (h : monotone u) [ne_bot l] (hu : tendsto u l at_top) :
    tendsto u at_top at_top :=
  monotone.tendsto_at_top_at_top h
    fun (b : α) => eventually.exists (tendsto.eventually hu (mem_at_top b))

/-- If a monotone function `u : ι → α` tends to `at_bot` along *some* non-trivial filter `l`, then
it tends to `at_bot` along `at_bot`. -/
theorem tendsto_at_bot_of_monotone_of_filter {ι : Type u_1} {α : Type u_3} [preorder ι] [preorder α]
    {l : filter ι} {u : ι → α} (h : monotone u) [ne_bot l] (hu : tendsto u l at_bot) :
    tendsto u at_bot at_bot :=
  tendsto_at_top_of_monotone_of_filter (monotone.order_dual h) hu

theorem tendsto_at_top_of_monotone_of_subseq {ι : Type u_1} {ι' : Type u_2} {α : Type u_3}
    [preorder ι] [preorder α] {u : ι → α} {φ : ι' → ι} (h : monotone u) {l : filter ι'} [ne_bot l]
    (H : tendsto (u ∘ φ) l at_top) : tendsto u at_top at_top :=
  tendsto_at_top_of_monotone_of_filter h (tendsto_map' H)

theorem tendsto_at_bot_of_monotone_of_subseq {ι : Type u_1} {ι' : Type u_2} {α : Type u_3}
    [preorder ι] [preorder α] {u : ι → α} {φ : ι' → ι} (h : monotone u) {l : filter ι'} [ne_bot l]
    (H : tendsto (u ∘ φ) l at_bot) : tendsto u at_bot at_bot :=
  tendsto_at_bot_of_monotone_of_filter h (tendsto_map' H)

/-- Let `f` and `g` be two maps to the same commutative monoid. This lemma gives a sufficient
condition for comparison of the filter `at_top.map (λ s, ∏ b in s, f b)` with
`at_top.map (λ s, ∏ b in s, g b)`. This is useful to compare the set of limit points of
`Π b in s, f b` as `s → at_top` with the similar set for `g`. -/
theorem map_at_top_finset_prod_le_of_prod_eq {α : Type u_3} {β : Type u_4} {γ : Type u_5}
    [comm_monoid α] {f : β → α} {g : γ → α}
    (h_eq :
      ∀ (u : finset γ),
        ∃ (v : finset β),
          ∀ (v' : finset β),
            v ⊆ v' →
              ∃ (u' : finset γ),
                u ⊆ u' ∧ (finset.prod u' fun (x : γ) => g x) = finset.prod v' fun (b : β) => f b) :
    map (fun (s : finset β) => finset.prod s fun (b : β) => f b) at_top ≤
        map (fun (s : finset γ) => finset.prod s fun (x : γ) => g x) at_top :=
  sorry

theorem has_antimono_basis.tendsto {ι : Type u_1} {α : Type u_3} [semilattice_sup ι] [Nonempty ι]
    {l : filter α} {p : ι → Prop} {s : ι → set α} (hl : has_antimono_basis l p s) {φ : ι → α}
    (h : ∀ (i : ι), φ i ∈ s i) : tendsto φ at_top l :=
  sorry

namespace is_countably_generated

/-- An abstract version of continuity of sequentially continuous functions on metric spaces:
if a filter `k` is countably generated then `tendsto f k l` iff for every sequence `u`
converging to `k`, `f ∘ u` tends to `l`. -/
theorem tendsto_iff_seq_tendsto {α : Type u_3} {β : Type u_4} {f : α → β} {k : filter α}
    {l : filter β} (hcb : is_countably_generated k) :
    tendsto f k l ↔ ∀ (x : ℕ → α), tendsto x at_top k → tendsto (f ∘ x) at_top l :=
  sorry

theorem tendsto_of_seq_tendsto {α : Type u_3} {β : Type u_4} {f : α → β} {k : filter α}
    {l : filter β} (hcb : is_countably_generated k) :
    (∀ (x : ℕ → α), tendsto x at_top k → tendsto (f ∘ x) at_top l) → tendsto f k l :=
  iff.mpr (tendsto_iff_seq_tendsto hcb)

theorem subseq_tendsto {α : Type u_3} {f : filter α} (hf : is_countably_generated f) {u : ℕ → α}
    (hx : ne_bot (f ⊓ map u at_top)) : ∃ (θ : ℕ → ℕ), strict_mono θ ∧ tendsto (u ∘ θ) at_top f :=
  sorry

end is_countably_generated

end filter

theorem exists_lt_mul_self {R : Type u_6} [linear_ordered_semiring R] (a : R) :
    ∃ (x : R), ∃ (H : x ≥ 0), a < x * x :=
  sorry

theorem exists_le_mul_self {R : Type u_6} [linear_ordered_semiring R] (a : R) :
    ∃ (x : R), ∃ (H : x ≥ 0), a ≤ x * x :=
  sorry

namespace order_iso

@[simp] theorem comap_at_top {α : Type u_3} {β : Type u_4} [preorder α] [preorder β] (e : α ≃o β) :
    filter.comap (⇑e) filter.at_top = filter.at_top :=
  sorry

@[simp] theorem comap_at_bot {α : Type u_3} {β : Type u_4} [preorder α] [preorder β] (e : α ≃o β) :
    filter.comap (⇑e) filter.at_bot = filter.at_bot :=
  comap_at_top (order_iso.dual e)

@[simp] theorem map_at_top {α : Type u_3} {β : Type u_4} [preorder α] [preorder β] (e : α ≃o β) :
    filter.map (⇑e) filter.at_top = filter.at_top :=
  sorry

@[simp] theorem map_at_bot {α : Type u_3} {β : Type u_4} [preorder α] [preorder β] (e : α ≃o β) :
    filter.map (⇑e) filter.at_bot = filter.at_bot :=
  map_at_top (order_iso.dual e)

theorem tendsto_at_top {α : Type u_3} {β : Type u_4} [preorder α] [preorder β] (e : α ≃o β) :
    filter.tendsto (⇑e) filter.at_top filter.at_top :=
  eq.le (map_at_top e)

theorem tendsto_at_bot {α : Type u_3} {β : Type u_4} [preorder α] [preorder β] (e : α ≃o β) :
    filter.tendsto (⇑e) filter.at_bot filter.at_bot :=
  eq.le (map_at_bot e)

@[simp] theorem tendsto_at_top_iff {α : Type u_3} {β : Type u_4} {γ : Type u_5} [preorder α]
    [preorder β] {l : filter γ} {f : γ → α} (e : α ≃o β) :
    filter.tendsto (fun (x : γ) => coe_fn e (f x)) l filter.at_top ↔
        filter.tendsto f l filter.at_top :=
  sorry

@[simp] theorem tendsto_at_bot_iff {α : Type u_3} {β : Type u_4} {γ : Type u_5} [preorder α]
    [preorder β] {l : filter γ} {f : γ → α} (e : α ≃o β) :
    filter.tendsto (fun (x : γ) => coe_fn e (f x)) l filter.at_bot ↔
        filter.tendsto f l filter.at_bot :=
  tendsto_at_top_iff (order_iso.dual e)

end order_iso

/-- Let `g : γ → β` be an injective function and `f : β → α` be a function from the codomain of `g`
to a commutative monoid. Suppose that `f x = 1` outside of the range of `g`. Then the filters
`at_top.map (λ s, ∏ i in s, f (g i))` and `at_top.map (λ s, ∏ i in s, f i)` coincide.

The additive version of this lemma is used to prove the equality `∑' x, f (g x) = ∑' y, f y` under
the same assumptions.-/
theorem function.injective.map_at_top_finset_sum_eq {α : Type u_3} {β : Type u_4} {γ : Type u_5}
    [add_comm_monoid α] {g : γ → β} (hg : function.injective g) {f : β → α}
    (hf : ∀ (x : β), ¬x ∈ set.range g → f x = 0) :
    filter.map (fun (s : finset γ) => finset.sum s fun (i : γ) => f (g i)) filter.at_top =
        filter.map (fun (s : finset β) => finset.sum s fun (i : β) => f i) filter.at_top :=
  sorry

end Mathlib


/-
Copyright (c) 2018 Robert Y. Lewis. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Robert Y. Lewis
-/
import analysis.normed_space.basic
import number_theory.padics.padic_norm

/-!
# p-adic numbers

This file defines the p-adic numbers (rationals) `ℚ_p` as
the completion of `ℚ` with respect to the p-adic norm.
We show that the p-adic norm on ℚ extends to `ℚ_p`, that `ℚ` is embedded in `ℚ_p`,
and that `ℚ_p` is Cauchy complete.

## Important definitions

* `padic` : the type of p-adic numbers
* `padic_norm_e` : the rational valued p-adic norm on `ℚ_p`

## Notation

We introduce the notation `ℚ_[p]` for the p-adic numbers.

## Implementation notes

Much, but not all, of this file assumes that `p` is prime. This assumption is inferred automatically
by taking `[fact (prime p)]` as a type class argument.

We use the same concrete Cauchy sequence construction that is used to construct ℝ.
`ℚ_p` inherits a field structure from this construction.
The extension of the norm on ℚ to `ℚ_p` is *not* analogous to extending the absolute value to ℝ,
and hence the proof that `ℚ_p` is complete is different from the proof that ℝ is complete.

A small special-purpose simplification tactic, `padic_index_simp`, is used to manipulate sequence
indices in the proof that the norm extends.

`padic_norm_e` is the rational-valued p-adic norm on `ℚ_p`.
To instantiate `ℚ_p` as a normed field, we must cast this into a ℝ-valued norm.
The `ℝ`-valued norm, using notation `∥ ∥` from normed spaces,
is the canonical representation of this norm.

`simp` prefers `padic_norm` to `padic_norm_e` when possible.
Since `padic_norm_e` and `∥ ∥` have different types, `simp` does not rewrite one to the other.

Coercions from `ℚ` to `ℚ_p` are set up to work with the `norm_cast` tactic.

## References

* [F. Q. Gouêva, *p-adic numbers*][gouvea1997]
* [R. Y. Lewis, *A formal proof of Hensel's lemma over the p-adic integers*][lewis2019]
* <https://en.wikipedia.org/wiki/P-adic_number>

## Tags

p-adic, p adic, padic, norm, valuation, cauchy, completion, p-adic completion
-/

noncomputable theory
open_locale classical

open nat multiplicity padic_norm cau_seq cau_seq.completion metric

/-- The type of Cauchy sequences of rationals with respect to the p-adic norm. -/
@[reducible] def padic_seq (p : ℕ) := cau_seq _ (padic_norm p)

namespace padic_seq

section
variables {p : ℕ} [fact p.prime]

/-- The p-adic norm of the entries of a nonzero Cauchy sequence of rationals is eventually
constant. -/
lemma stationary {f : cau_seq ℚ (padic_norm p)} (hf : ¬ f ≈ 0) :
  ∃ N, ∀ m n, N ≤ m → N ≤ n → padic_norm p (f n) = padic_norm p (f m) :=
have ∃ ε > 0, ∃ N1, ∀ j ≥ N1, ε ≤ padic_norm p (f j),
  from cau_seq.abv_pos_of_not_lim_zero $ not_lim_zero_of_not_congr_zero hf,
let ⟨ε, hε, N1, hN1⟩ := this,
    ⟨N2, hN2⟩ := cau_seq.cauchy₂ f hε in
⟨ max N1 N2,
  λ n m hn hm,
  have padic_norm p (f n - f m) < ε, from hN2 _ _ (max_le_iff.1 hn).2 (max_le_iff.1 hm).2,
  have padic_norm p (f n - f m) < padic_norm p (f n),
    from lt_of_lt_of_le this $ hN1 _ (max_le_iff.1 hn).1,
  have  padic_norm p (f n - f m) < max (padic_norm p (f n)) (padic_norm p (f m)),
    from lt_max_iff.2 (or.inl this),
  begin
    by_contradiction hne,
    rw ←padic_norm.neg p (f m) at hne,
    have hnam := add_eq_max_of_ne p hne,
    rw [padic_norm.neg, max_comm] at hnam,
    rw [←hnam, sub_eq_add_neg, add_comm] at this,
    apply _root_.lt_irrefl _ this
  end ⟩

/-- For all n ≥ stationary_point f hf, the p-adic norm of f n is the same. -/
def stationary_point {f : padic_seq p} (hf : ¬ f ≈ 0) : ℕ :=
classical.some $ stationary hf

lemma stationary_point_spec {f : padic_seq p} (hf : ¬ f ≈ 0) :
  ∀ {m n}, stationary_point hf ≤ m → stationary_point hf ≤ n →
    padic_norm p (f n) = padic_norm p (f m) :=
classical.some_spec $ stationary hf

/-- Since the norm of the entries of a Cauchy sequence is eventually stationary,
we can lift the norm to sequences. -/
def norm (f : padic_seq p) : ℚ :=
if hf : f ≈ 0 then 0 else padic_norm p (f (stationary_point hf))

lemma norm_zero_iff (f : padic_seq p) : f.norm = 0 ↔ f ≈ 0 :=
begin
  constructor,
  { intro h,
    by_contradiction hf,
    unfold norm at h, split_ifs at h,
    apply hf,
    intros ε hε,
    existsi stationary_point hf,
    intros j hj,
    have heq := stationary_point_spec hf (le_refl _) hj,
    simpa [h, heq] },
  { intro h,
    simp [norm, h] }
end

end

section embedding
open cau_seq
variables {p : ℕ} [fact p.prime]

lemma equiv_zero_of_val_eq_of_equiv_zero {f g : padic_seq p}
  (h : ∀ k, padic_norm p (f k) = padic_norm p (g k)) (hf : f ≈ 0) : g ≈ 0 :=
λ ε hε, let ⟨i, hi⟩ := hf _ hε in
⟨i, λ j hj, by simpa [h] using hi _ hj⟩

lemma norm_nonzero_of_not_equiv_zero {f : padic_seq p} (hf : ¬ f ≈ 0) :
  f.norm ≠ 0 :=
hf ∘ f.norm_zero_iff.1

lemma norm_eq_norm_app_of_nonzero {f : padic_seq p} (hf : ¬ f ≈ 0) :
  ∃ k, f.norm = padic_norm p k ∧ k ≠ 0 :=
have heq : f.norm = padic_norm p (f $ stationary_point hf), by simp [norm, hf],
⟨f $ stationary_point hf, heq,
  λ h, norm_nonzero_of_not_equiv_zero hf (by simpa [h] using heq)⟩

lemma not_lim_zero_const_of_nonzero {q : ℚ} (hq : q ≠ 0) : ¬ lim_zero (const (padic_norm p) q) :=
λ h', hq $ const_lim_zero.1 h'

lemma not_equiv_zero_const_of_nonzero {q : ℚ} (hq : q ≠ 0) : ¬ (const (padic_norm p) q) ≈ 0 :=
λ h : lim_zero (const (padic_norm p) q - 0), not_lim_zero_const_of_nonzero hq $ by simpa using h

lemma norm_nonneg (f : padic_seq p) : 0 ≤ f.norm :=
if hf : f ≈ 0 then by simp [hf, norm]
else by simp [norm, hf, padic_norm.nonneg]

/-- An auxiliary lemma for manipulating sequence indices. -/
lemma lift_index_left_left {f : padic_seq p} (hf : ¬ f ≈ 0) (v2 v3 : ℕ) :
  padic_norm p (f (stationary_point hf)) =
    padic_norm p (f (max (stationary_point hf) (max v2 v3))) :=
begin
  apply stationary_point_spec hf,
  { apply le_max_left },
  { apply le_refl }
end

/-- An auxiliary lemma for manipulating sequence indices. -/
lemma lift_index_left {f : padic_seq p} (hf : ¬ f ≈ 0) (v1 v3 : ℕ) :
  padic_norm p (f (stationary_point hf)) =
    padic_norm p (f (max v1 (max (stationary_point hf) v3))) :=
begin
  apply stationary_point_spec hf,
  { apply le_trans,
    { apply le_max_left _ v3 },
    { apply le_max_right } },
  { apply le_refl }
end

/-- An auxiliary lemma for manipulating sequence indices. -/
lemma lift_index_right {f : padic_seq p} (hf : ¬ f ≈ 0) (v1 v2 : ℕ) :
  padic_norm p (f (stationary_point hf)) =
    padic_norm p (f (max v1 (max v2 (stationary_point hf)))) :=
begin
  apply stationary_point_spec hf,
  { apply le_trans,
    { apply le_max_right v2 },
    { apply le_max_right } },
  { apply le_refl }
end

end embedding

section valuation
open cau_seq
variables {p : ℕ} [fact p.prime]

/-! ### Valuation on `padic_seq` -/

/--
The `p`-adic valuation on `ℚ` lifts to `padic_seq p`.
`valuation f` is defined to be the valuation of the (`ℚ`-valued) stationary point of `f`.
-/
def valuation (f : padic_seq p) : ℤ :=
if hf : f ≈ 0 then 0 else padic_val_rat p (f (stationary_point hf))

lemma norm_eq_pow_val {f : padic_seq p} (hf : ¬ f ≈ 0) :
  f.norm = p^(-f.valuation : ℤ) :=
begin
  rw [norm, valuation, dif_neg hf, dif_neg hf, padic_norm, if_neg],
  intro H,
  apply cau_seq.not_lim_zero_of_not_congr_zero hf,
  intros ε hε,
  use (stationary_point hf),
  intros n hn,
  rw stationary_point_spec hf (le_refl _) hn,
  simpa [H] using hε,
end

lemma val_eq_iff_norm_eq {f g : padic_seq p} (hf : ¬ f ≈ 0) (hg : ¬ g ≈ 0) :
  f.valuation = g.valuation ↔ f.norm = g.norm :=
begin
  rw [norm_eq_pow_val hf, norm_eq_pow_val hg, ← neg_inj, zpow_inj],
  { exact_mod_cast (fact.out p.prime).pos },
  { exact_mod_cast (fact.out p.prime).ne_one },
end

end valuation

end padic_seq

section
open padic_seq

private meta def index_simp_core (hh hf hg : expr)
  (at_ : interactive.loc := interactive.loc.ns [none]) : tactic unit :=
do [v1, v2, v3] ← [hh, hf, hg].mmap
     (λ n, tactic.mk_app ``stationary_point [n] <|> return n),
   e1 ← tactic.mk_app ``lift_index_left_left [hh, v2, v3] <|> return `(true),
   e2 ← tactic.mk_app ``lift_index_left [hf, v1, v3] <|> return `(true),
   e3 ← tactic.mk_app ``lift_index_right [hg, v1, v2] <|> return `(true),
   sl ← [e1, e2, e3].mfoldl (λ s e, simp_lemmas.add s e) simp_lemmas.mk,
   when at_.include_goal (tactic.simp_target sl >> tactic.skip),
   hs ← at_.get_locals, hs.mmap' (tactic.simp_hyp sl [])

/--
  This is a special-purpose tactic that lifts padic_norm (f (stationary_point f)) to
  padic_norm (f (max _ _ _)).
-/
meta def tactic.interactive.padic_index_simp (l : interactive.parse interactive.types.pexpr_list)
  (at_ : interactive.parse interactive.types.location) : tactic unit :=
do [h, f, g] ← l.mmap tactic.i_to_expr,
   index_simp_core h f g at_
end

namespace padic_seq
section embedding

open cau_seq
variables {p : ℕ} [hp : fact p.prime]
include hp

lemma norm_mul (f g : padic_seq p) : (f * g).norm = f.norm * g.norm :=
if hf : f ≈ 0 then
  have hg : f * g ≈ 0, from mul_equiv_zero' _ hf,
  by simp only [hf, hg, norm, dif_pos, zero_mul]
else if hg : g ≈ 0 then
  have hf : f * g ≈ 0, from mul_equiv_zero _ hg,
  by simp only [hf, hg, norm, dif_pos, mul_zero]
else
  have hfg : ¬ f * g ≈ 0, by apply mul_not_equiv_zero; assumption,
  begin
    unfold norm,
    split_ifs,
    padic_index_simp [hfg, hf, hg],
    apply padic_norm.mul
  end

lemma eq_zero_iff_equiv_zero (f : padic_seq p) : mk f = 0 ↔ f ≈ 0 :=
mk_eq

lemma ne_zero_iff_nequiv_zero (f : padic_seq p) : mk f ≠ 0 ↔ ¬ f ≈ 0 :=
not_iff_not.2 (eq_zero_iff_equiv_zero _)

lemma norm_const (q : ℚ) : norm (const (padic_norm p) q) = padic_norm p q :=
if hq : q = 0 then
  have (const (padic_norm p) q) ≈ 0,
    by simp [hq]; apply setoid.refl (const (padic_norm p) 0),
  by subst hq; simp [norm, this]
else
  have ¬ (const (padic_norm p) q) ≈ 0, from not_equiv_zero_const_of_nonzero hq,
  by simp [norm, this]

lemma norm_values_discrete (a : padic_seq p) (ha : ¬ a ≈ 0) :
  (∃ (z : ℤ), a.norm = ↑p ^ (-z)) :=
let ⟨k, hk, hk'⟩ := norm_eq_norm_app_of_nonzero ha in
by simpa [hk] using padic_norm.values_discrete p hk'

lemma norm_one : norm (1 : padic_seq p) = 1 :=
have h1 : ¬ (1 : padic_seq p) ≈ 0, from one_not_equiv_zero _,
by simp [h1, norm, hp.1.one_lt]

private lemma norm_eq_of_equiv_aux {f g : padic_seq p} (hf : ¬ f ≈ 0) (hg : ¬ g ≈ 0) (hfg : f ≈ g)
  (h : padic_norm p (f (stationary_point hf)) ≠ padic_norm p (g (stationary_point hg)))
  (hlt : padic_norm p (g (stationary_point hg)) < padic_norm p (f (stationary_point hf))) :
  false :=
begin
  have hpn : 0 < padic_norm p (f (stationary_point hf)) - padic_norm p (g (stationary_point hg)),
    from sub_pos_of_lt hlt,
  cases hfg _ hpn with N hN,
  let i := max N (max (stationary_point hf) (stationary_point hg)),
  have hi : N ≤ i, from le_max_left _ _,
  have hN' := hN _ hi,
  padic_index_simp [N, hf, hg] at hN' h hlt,
  have hpne : padic_norm p (f i) ≠ padic_norm p (-(g i)),
    by rwa [ ←padic_norm.neg p (g i)] at h,
  let hpnem := add_eq_max_of_ne p hpne,
  have hpeq : padic_norm p ((f - g) i) = max (padic_norm p (f i)) (padic_norm p (g i)),
  { rwa padic_norm.neg at hpnem },
  rw [hpeq, max_eq_left_of_lt hlt] at hN',
  have : padic_norm p (f i) < padic_norm p (f i),
  { apply lt_of_lt_of_le hN', apply sub_le_self, apply padic_norm.nonneg },
  exact lt_irrefl _ this
end

private lemma norm_eq_of_equiv {f g : padic_seq p} (hf : ¬ f ≈ 0) (hg : ¬ g ≈ 0) (hfg : f ≈ g) :
  padic_norm p (f (stationary_point hf)) = padic_norm p (g (stationary_point hg)) :=
begin
  by_contradiction h,
  cases (decidable.em (padic_norm p (g (stationary_point hg)) <
          padic_norm p (f (stationary_point hf))))
      with hlt hnlt,
  { exact norm_eq_of_equiv_aux hf hg hfg h hlt },
  { apply norm_eq_of_equiv_aux hg hf (setoid.symm hfg) (ne.symm h),
    apply lt_of_le_of_ne,
    apply le_of_not_gt hnlt,
    apply h }
end

theorem norm_equiv {f g : padic_seq p} (hfg : f ≈ g) : f.norm = g.norm :=
if hf : f ≈ 0 then
  have hg : g ≈ 0, from setoid.trans (setoid.symm hfg) hf,
  by simp [norm, hf, hg]
else have hg : ¬ g ≈ 0, from hf ∘ setoid.trans hfg,
by unfold norm; split_ifs; exact norm_eq_of_equiv hf hg hfg

private lemma norm_nonarchimedean_aux {f g : padic_seq p}
  (hfg : ¬ f + g ≈ 0) (hf : ¬ f ≈ 0) (hg : ¬ g ≈ 0) : (f + g).norm ≤ max (f.norm) (g.norm) :=
begin
  unfold norm, split_ifs,
  padic_index_simp [hfg, hf, hg],
  apply padic_norm.nonarchimedean
end

theorem norm_nonarchimedean (f g : padic_seq p) : (f + g).norm ≤ max (f.norm) (g.norm) :=
if hfg : f + g ≈ 0 then
  have 0 ≤ max (f.norm) (g.norm), from le_max_of_le_left (norm_nonneg _),
  by simpa only [hfg, norm, ne.def, le_max_iff, cau_seq.add_apply, not_true, dif_pos]
else if hf : f ≈ 0 then
  have hfg' : f + g ≈ g,
  { change lim_zero (f - 0) at hf,
    show lim_zero (f + g - g), by simpa only [sub_zero, add_sub_cancel] using hf },
  have hcfg : (f + g).norm = g.norm, from norm_equiv hfg',
  have hcl : f.norm = 0, from (norm_zero_iff f).2 hf,
  have max (f.norm) (g.norm) = g.norm,
    by rw hcl; exact max_eq_right (norm_nonneg _),
  by rw [this, hcfg]
else if hg : g ≈ 0 then
  have hfg' : f + g ≈ f,
  { change lim_zero (g - 0) at hg,
    show lim_zero (f + g - f), by simpa only [add_sub_cancel', sub_zero] using hg },
  have hcfg : (f + g).norm = f.norm, from norm_equiv hfg',
  have hcl : g.norm = 0, from (norm_zero_iff g).2 hg,
  have max (f.norm) (g.norm) = f.norm,
    by rw hcl; exact max_eq_left (norm_nonneg _),
  by rw [this, hcfg]
else norm_nonarchimedean_aux hfg hf hg

lemma norm_eq {f g : padic_seq p} (h : ∀ k, padic_norm p (f k) = padic_norm p (g k)) :
  f.norm = g.norm :=
if hf : f ≈ 0 then
  have hg : g ≈ 0, from equiv_zero_of_val_eq_of_equiv_zero h hf,
  by simp only [hf, hg, norm, dif_pos]
else
  have hg : ¬ g ≈ 0, from λ hg, hf $ equiv_zero_of_val_eq_of_equiv_zero
    (by simp only [h, forall_const, eq_self_iff_true]) hg,
  begin
    simp only [hg, hf, norm, dif_neg, not_false_iff],
    let i := max (stationary_point hf) (stationary_point hg),
    have hpf : padic_norm p (f (stationary_point hf)) = padic_norm p (f i),
    { apply stationary_point_spec, apply le_max_left, apply le_refl },
    have hpg : padic_norm p (g (stationary_point hg)) = padic_norm p (g i),
    { apply stationary_point_spec, apply le_max_right, apply le_refl },
    rw [hpf, hpg, h]
  end

lemma norm_neg (a : padic_seq p) : (-a).norm = a.norm :=
norm_eq $ by simp

lemma norm_eq_of_add_equiv_zero {f g : padic_seq p} (h : f + g ≈ 0) : f.norm = g.norm :=
have lim_zero (f + g - 0), from h,
have f ≈ -g, from show lim_zero (f - (-g)), by simpa only [sub_zero, sub_neg_eq_add],
have f.norm = (-g).norm, from norm_equiv this,
by simpa only [norm_neg] using this

lemma add_eq_max_of_ne {f g : padic_seq p} (hfgne : f.norm ≠ g.norm) :
  (f + g).norm = max f.norm g.norm :=
have hfg : ¬f + g ≈ 0, from mt norm_eq_of_add_equiv_zero hfgne,
if hf : f ≈ 0 then
  have lim_zero (f - 0), from hf,
  have f + g ≈ g, from show lim_zero ((f + g) - g), by simpa only [sub_zero, add_sub_cancel],
  have h1 : (f+g).norm = g.norm, from norm_equiv this,
  have h2 : f.norm = 0, from (norm_zero_iff _).2 hf,
  by rw [h1, h2]; rw max_eq_right (norm_nonneg _)
else if hg : g ≈ 0 then
  have lim_zero (g - 0), from hg,
  have f + g ≈ f, from show lim_zero ((f + g) - f), by rw [add_sub_cancel']; simpa only [sub_zero],
  have h1 : (f+g).norm = f.norm, from norm_equiv this,
  have h2 : g.norm = 0, from (norm_zero_iff _).2 hg,
  by rw [h1, h2]; rw max_eq_left (norm_nonneg _)
else
begin
  unfold norm at ⊢ hfgne, split_ifs at ⊢ hfgne,
  padic_index_simp [hfg, hf, hg] at ⊢ hfgne,
  exact padic_norm.add_eq_max_of_ne p hfgne
end

end embedding
end padic_seq

/-- The p-adic numbers `Q_[p]` are the Cauchy completion of `ℚ` with respect to the p-adic norm. -/
def padic (p : ℕ) [fact p.prime] := @cau_seq.completion.Cauchy _ _ _ _ (padic_norm p) _
notation `ℚ_[` p `]` := padic p

namespace padic

section completion
variables {p : ℕ} [fact p.prime]

/-- The discrete field structure on `ℚ_p` is inherited from the Cauchy completion construction. -/
instance field : field (ℚ_[p]) :=
cau_seq.completion.field

instance : inhabited ℚ_[p] := ⟨0⟩

-- short circuits

instance : has_zero ℚ_[p] := by apply_instance
instance : has_one ℚ_[p] := by apply_instance
instance : has_add ℚ_[p] := by apply_instance
instance : has_mul ℚ_[p] := by apply_instance
instance : has_sub ℚ_[p] := by apply_instance
instance : has_neg ℚ_[p] := by apply_instance
instance : has_div ℚ_[p] := by apply_instance
instance : add_comm_group ℚ_[p] := by apply_instance
instance : comm_ring ℚ_[p] := by apply_instance

/-- Builds the equivalence class of a Cauchy sequence of rationals. -/
def mk : padic_seq p → ℚ_[p] := quotient.mk
end completion

section completion
variables (p : ℕ) [fact p.prime]

lemma mk_eq {f g : padic_seq p} : mk f = mk g ↔ f ≈ g := quotient.eq

/-- Embeds the rational numbers in the p-adic numbers. -/
def of_rat : ℚ → ℚ_[p] := cau_seq.completion.of_rat

@[simp] lemma of_rat_add : ∀ (x y : ℚ), of_rat p (x + y) = of_rat p x + of_rat p y :=
cau_seq.completion.of_rat_add

@[simp] lemma of_rat_neg : ∀ (x : ℚ), of_rat p (-x) = -of_rat p x :=
cau_seq.completion.of_rat_neg

@[simp] lemma of_rat_mul : ∀ (x y : ℚ), of_rat p (x * y) = of_rat p x * of_rat p y :=
cau_seq.completion.of_rat_mul

@[simp] lemma of_rat_sub : ∀ (x y : ℚ), of_rat p (x - y) = of_rat p x - of_rat p y :=
cau_seq.completion.of_rat_sub

@[simp] lemma of_rat_div : ∀ (x y : ℚ), of_rat p (x / y) = of_rat p x / of_rat p y :=
cau_seq.completion.of_rat_div

@[simp] lemma of_rat_one : of_rat p 1 = 1 := rfl

@[simp] lemma of_rat_zero : of_rat p 0 = 0 := rfl

lemma cast_eq_of_rat_of_nat (n : ℕ) : (↑n : ℚ_[p]) = of_rat p n :=
begin
  induction n with n ih,
  { refl },
  { simpa using ih }
end

lemma cast_eq_of_rat_of_int (n : ℤ) : ↑n = of_rat p n :=
by induction n; simp [cast_eq_of_rat_of_nat]

lemma cast_eq_of_rat : ∀ (q : ℚ), (↑q : ℚ_[p]) = of_rat p q
| ⟨n, d, h1, h2⟩ :=
  show ↑n / ↑d = _, from
    have (⟨n, d, h1, h2⟩ : ℚ) = rat.mk n d, from rat.num_denom',
    by simp [this, rat.mk_eq_div, of_rat_div, cast_eq_of_rat_of_int, cast_eq_of_rat_of_nat]

@[norm_cast] lemma coe_add : ∀ {x y : ℚ}, (↑(x + y) : ℚ_[p]) = ↑x + ↑y := by simp [cast_eq_of_rat]
@[norm_cast] lemma coe_neg : ∀ {x : ℚ}, (↑(-x) : ℚ_[p]) = -↑x := by simp [cast_eq_of_rat]
@[norm_cast] lemma coe_mul : ∀ {x y : ℚ}, (↑(x * y) : ℚ_[p]) = ↑x * ↑y := by simp [cast_eq_of_rat]
@[norm_cast] lemma coe_sub : ∀ {x y : ℚ}, (↑(x - y) : ℚ_[p]) = ↑x - ↑y := by simp [cast_eq_of_rat]
@[norm_cast] lemma coe_div : ∀ {x y : ℚ}, (↑(x / y) : ℚ_[p]) = ↑x / ↑y := by simp [cast_eq_of_rat]

@[norm_cast] lemma coe_one : (↑1 : ℚ_[p]) = 1 := by simp [cast_eq_of_rat]
@[norm_cast] lemma coe_zero : (↑0 : ℚ_[p]) = 0 := rfl

lemma const_equiv {q r : ℚ} : const (padic_norm p) q ≈ const (padic_norm p) r ↔ q = r :=
⟨ λ heq : lim_zero (const (padic_norm p) (q - r)),
    eq_of_sub_eq_zero $ const_lim_zero.1 heq,
  λ heq, by rw heq; apply setoid.refl _ ⟩

lemma of_rat_eq {q r : ℚ} : of_rat p q = of_rat p r ↔ q = r :=
⟨(const_equiv p).1 ∘ quotient.eq.1, λ h, by rw h⟩

@[norm_cast] lemma coe_inj {q r : ℚ} : (↑q : ℚ_[p]) = ↑r ↔ q = r :=
by simp [cast_eq_of_rat, of_rat_eq]

instance : char_zero ℚ_[p] :=
⟨λ m n, by { rw ← rat.cast_coe_nat, norm_cast, exact id }⟩

end completion
end padic

/-- The rational-valued p-adic norm on `ℚ_p` is lifted from the norm on Cauchy sequences. The
canonical form of this function is the normed space instance, with notation `∥ ∥`. -/
def padic_norm_e {p : ℕ} [hp : fact p.prime] : ℚ_[p] → ℚ :=
quotient.lift padic_seq.norm $ @padic_seq.norm_equiv _ _

namespace padic_norm_e
section embedding
open padic_seq
variables {p : ℕ} [fact p.prime]

lemma defn (f : padic_seq p) {ε : ℚ} (hε : 0 < ε) : ∃ N, ∀ i ≥ N, padic_norm_e (⟦f⟧ - f i) < ε :=
begin
  simp only [padic.cast_eq_of_rat],
  change ∃ N, ∀ i ≥ N, (f - const _ (f i)).norm < ε,
  by_contradiction h,
  cases cauchy₂ f hε with N hN,
  have : ∀ N, ∃ i ≥ N, ε ≤ (f - const _ (f i)).norm,
    by simpa only [not_forall, not_exists, not_lt] using h,
  rcases this N with ⟨i, hi, hge⟩,
  have hne : ¬ (f - const (padic_norm p) (f i)) ≈ 0,
  { intro h, unfold padic_seq.norm at hge; split_ifs at hge, exact not_lt_of_ge hge hε },
  unfold padic_seq.norm at hge; split_ifs at hge,
  apply not_le_of_gt _ hge,
  cases decidable.em (N ≤ stationary_point hne) with hgen hngen,
  { apply hN; assumption },
  { have := stationary_point_spec hne (le_refl _) (le_of_not_le hngen),
    rw ←this,
    apply hN,
    apply le_refl, assumption }
end

protected lemma nonneg (q : ℚ_[p]) : 0 ≤ padic_norm_e q :=
quotient.induction_on q $ norm_nonneg

lemma zero_def : (0 : ℚ_[p]) = ⟦0⟧ := rfl

lemma zero_iff (q : ℚ_[p]) : padic_norm_e q = 0 ↔ q = 0 :=
quotient.induction_on q $
  by simpa only [zero_def, quotient.eq] using norm_zero_iff

@[simp] protected lemma zero : padic_norm_e (0 : ℚ_[p]) = 0 :=
(zero_iff _).2 rfl

/-- Theorems about `padic_norm_e` are named with a `'` so the names do not conflict with the
equivalent theorems about `norm` (`∥ ∥`). -/
@[simp] protected lemma one' : padic_norm_e (1 : ℚ_[p]) = 1 :=
norm_one

@[simp] protected lemma neg (q : ℚ_[p]) : padic_norm_e (-q) = padic_norm_e q :=
quotient.induction_on q $ norm_neg

/-- Theorems about `padic_norm_e` are named with a `'` so the names do not conflict with the
equivalent theorems about `norm` (`∥ ∥`). -/
theorem nonarchimedean' (q r : ℚ_[p]) :
  padic_norm_e (q + r) ≤ max (padic_norm_e q) (padic_norm_e r) :=
quotient.induction_on₂ q r $ norm_nonarchimedean

/-- Theorems about `padic_norm_e` are named with a `'` so the names do not conflict with the
equivalent theorems about `norm` (`∥ ∥`). -/
theorem add_eq_max_of_ne' {q r : ℚ_[p]} :
  padic_norm_e q ≠ padic_norm_e r → padic_norm_e (q + r) = max (padic_norm_e q) (padic_norm_e r) :=
quotient.induction_on₂ q r $ λ _ _, padic_seq.add_eq_max_of_ne

lemma triangle_ineq (x y z : ℚ_[p]) :
  padic_norm_e (x - z) ≤ padic_norm_e (x - y) + padic_norm_e (y - z) :=
calc padic_norm_e (x - z) = padic_norm_e ((x - y) + (y - z)) : by rw sub_add_sub_cancel
  ... ≤ max (padic_norm_e (x - y)) (padic_norm_e (y - z)) : padic_norm_e.nonarchimedean' _ _
  ... ≤ padic_norm_e (x - y) + padic_norm_e (y - z) :
    max_le_add_of_nonneg (padic_norm_e.nonneg _) (padic_norm_e.nonneg _)

protected lemma add (q r : ℚ_[p]) : padic_norm_e (q + r) ≤ (padic_norm_e q) + (padic_norm_e r) :=
calc
  padic_norm_e (q + r) ≤ max (padic_norm_e q) (padic_norm_e r) : nonarchimedean' _ _
                      ... ≤ (padic_norm_e q) + (padic_norm_e r) :
                              max_le_add_of_nonneg (padic_norm_e.nonneg _) (padic_norm_e.nonneg _)

protected lemma mul' (q r : ℚ_[p]) : padic_norm_e (q * r) = (padic_norm_e q) * (padic_norm_e r) :=
quotient.induction_on₂ q r $ norm_mul

instance : is_absolute_value (@padic_norm_e p _) :=
{ abv_nonneg := padic_norm_e.nonneg,
  abv_eq_zero := zero_iff,
  abv_add := padic_norm_e.add,
  abv_mul := padic_norm_e.mul' }

@[simp] lemma eq_padic_norm' (q : ℚ) : padic_norm_e (padic.of_rat p q) = padic_norm p q :=
norm_const _

protected theorem image' {q : ℚ_[p]} : q ≠ 0 → ∃ n : ℤ, padic_norm_e q = p ^ (-n) :=
quotient.induction_on q $ λ f hf,
  have ¬ f ≈ 0, from (ne_zero_iff_nequiv_zero f).1 hf,
  norm_values_discrete f this

lemma sub_rev (q r : ℚ_[p]) : padic_norm_e (q - r) = padic_norm_e (r - q) :=
by rw ←(padic_norm_e.neg); simp

end embedding
end padic_norm_e

namespace padic

section complete
open padic_seq padic

theorem rat_dense' {p : ℕ} [fact p.prime] (q : ℚ_[p]) {ε : ℚ} (hε : 0 < ε) :
  ∃ r : ℚ, padic_norm_e (q - r) < ε :=
quotient.induction_on q $ λ q',
  have ∃ N, ∀ m n ≥ N, padic_norm p (q' m - q' n) < ε, from cauchy₂ _ hε,
  let ⟨N, hN⟩ := this in
  ⟨q' N,
    begin
      simp only [padic.cast_eq_of_rat],
      change padic_seq.norm (q' - const _ (q' N)) < ε,
      cases decidable.em ((q' - const (padic_norm p) (q' N)) ≈ 0) with heq hne',
      { simpa only [heq, padic_seq.norm, dif_pos] },
      { simp only [padic_seq.norm, dif_neg hne'],
        change padic_norm p (q' _ - q' _) < ε,
        have := stationary_point_spec hne',
        cases decidable.em (stationary_point hne' ≤ N) with hle hle,
        { have := eq.symm (this (le_refl _) hle),
          simp only [const_apply, sub_apply, padic_norm.zero, sub_self] at this,
          simpa only [this] },
        { apply hN,
          apply le_of_lt, apply lt_of_not_ge, apply hle, apply le_refl }}
    end⟩

variables {p : ℕ} [fact p.prime] (f : cau_seq _ (@padic_norm_e p _))
open classical

private lemma div_nat_pos (n : ℕ) : 0 < (1 / ((n + 1): ℚ)) :=
div_pos zero_lt_one (by exact_mod_cast succ_pos _)

/-- `lim_seq f`, for `f` a Cauchy sequence of `p`-adic numbers,
is a sequence of rationals with the same limit point as `f`. -/
def lim_seq : ℕ → ℚ := λ n, classical.some (rat_dense' (f n) (div_nat_pos n))

lemma exi_rat_seq_conv {ε : ℚ} (hε : 0 < ε) :
  ∃ N, ∀ i ≥ N, padic_norm_e (f i - ((lim_seq f) i : ℚ_[p])) < ε :=
begin
  refine (exists_nat_gt (1/ε)).imp (λ N hN i hi, _),
  have h := classical.some_spec (rat_dense' (f i) (div_nat_pos i)),
  refine lt_of_lt_of_le h ((div_le_iff' $ by exact_mod_cast succ_pos _).mpr _),
  rw right_distrib,
  apply le_add_of_le_of_nonneg,
  { exact (div_le_iff hε).mp (le_trans (le_of_lt hN) (by exact_mod_cast hi)) },
  { apply le_of_lt, simpa }
end

lemma exi_rat_seq_conv_cauchy : is_cau_seq (padic_norm p) (lim_seq f) :=
assume ε hε,
have hε3 : 0 < ε / 3, from div_pos hε (by norm_num),
let ⟨N, hN⟩ := exi_rat_seq_conv f hε3,
    ⟨N2, hN2⟩ := f.cauchy₂ hε3 in
begin
  existsi max N N2,
  intros j hj,
  suffices :
    padic_norm_e ((↑(lim_seq f j) - f (max N N2)) + (f (max N N2) - lim_seq f (max N N2))) < ε,
  { ring_nf at this ⊢,
    rw [← padic_norm_e.eq_padic_norm', ← padic.cast_eq_of_rat],
    exact_mod_cast this },
  { apply lt_of_le_of_lt,
    { apply padic_norm_e.add },
    { have : (3 : ℚ) ≠ 0, by norm_num,
      have : ε = ε / 3 + ε / 3 + ε / 3,
      { field_simp [this], simp only [bit0, bit1, mul_add, mul_one] },
      rw this,
      apply add_lt_add,
      { suffices : padic_norm_e ((↑(lim_seq f j) - f j) + (f j - f (max N N2))) < ε / 3 + ε / 3,
          by simpa only [sub_add_sub_cancel],
        apply lt_of_le_of_lt,
        { apply padic_norm_e.add },
        { apply add_lt_add,
          { rw [padic_norm_e.sub_rev],
            apply_mod_cast hN,
            exact le_of_max_le_left hj },
          { apply hN2,
            exact le_of_max_le_right hj,
            apply le_max_right }}},
      { apply_mod_cast hN,
        apply le_max_left }}}
end

private def lim' : padic_seq p := ⟨_, exi_rat_seq_conv_cauchy f⟩

private def lim : ℚ_[p] := ⟦lim' f⟧

end complete

section normed_space
variables (p : ℕ) [fact p.prime]

instance : has_dist ℚ_[p] := ⟨λ x y, padic_norm_e (x - y)⟩

instance : metric_space ℚ_[p] :=
{ dist_self := by simp [dist],
  dist_comm := λ x y, by unfold dist; rw ←padic_norm_e.neg (x - y); simp,
  dist_triangle :=
    begin
      intros, unfold dist,
      exact_mod_cast padic_norm_e.triangle_ineq _ _ _,
    end,
  eq_of_dist_eq_zero :=
    begin
      unfold dist, intros _ _ h,
      apply eq_of_sub_eq_zero,
      apply (padic_norm_e.zero_iff _).1,
      exact_mod_cast h
    end }

instance : has_norm ℚ_[p] := ⟨λ x, padic_norm_e x⟩

instance : normed_field ℚ_[p] :=
{ dist_eq := λ _ _, rfl,
  norm_mul' := by simp [has_norm.norm, padic_norm_e.mul'] }

instance is_absolute_value : is_absolute_value (λ a : ℚ_[p], ∥a∥) :=
{ abv_nonneg := norm_nonneg,
  abv_eq_zero := λ _, norm_eq_zero,
  abv_add := norm_add_le,
  abv_mul := by simp [has_norm.norm, padic_norm_e.mul'] }

theorem rat_dense {p : ℕ} {hp : fact p.prime} (q : ℚ_[p]) {ε : ℝ} (hε : 0 < ε) :
        ∃ r : ℚ, ∥q - r∥ < ε :=
let ⟨ε', hε'l, hε'r⟩ := exists_rat_btwn hε,
    ⟨r, hr⟩ := rat_dense' q (by simpa using hε'l)  in
⟨r, lt_trans (by simpa [has_norm.norm] using hr) hε'r⟩

end normed_space
end padic

namespace padic_norm_e
section normed_space
variables {p : ℕ} [hp : fact p.prime]
include hp

@[simp] protected lemma mul (q r : ℚ_[p]) : ∥q * r∥ = ∥q∥ * ∥r∥ :=
by simp [has_norm.norm, padic_norm_e.mul']

protected lemma is_norm (q : ℚ_[p]) : ↑(padic_norm_e q) = ∥q∥ := rfl

theorem nonarchimedean (q r : ℚ_[p]) : ∥q + r∥ ≤ max (∥q∥) (∥r∥) :=
begin
  unfold has_norm.norm,
  exact_mod_cast nonarchimedean' _ _
end

theorem add_eq_max_of_ne {q r : ℚ_[p]} (h : ∥q∥ ≠ ∥r∥) : ∥q+r∥ = max (∥q∥) (∥r∥) :=
begin
  unfold has_norm.norm,
  apply_mod_cast add_eq_max_of_ne',
  intro h',
  apply h,
  unfold has_norm.norm,
  exact_mod_cast h'
end

@[simp] lemma eq_padic_norm (q : ℚ) : ∥(↑q : ℚ_[p])∥ = padic_norm p q :=
begin
  unfold has_norm.norm,
  rw [← padic_norm_e.eq_padic_norm', ← padic.cast_eq_of_rat]
end

@[simp] lemma norm_p : ∥(p : ℚ_[p])∥ = p⁻¹ :=
begin
  have p₀ : p ≠ 0 := hp.1.ne_zero,
  have p₁ : p ≠ 1 := hp.1.ne_one,
  simp [p₀, p₁, norm, padic_norm, padic_val_rat, zpow_neg, padic.cast_eq_of_rat_of_nat],
end

lemma norm_p_lt_one : ∥(p : ℚ_[p])∥ < 1 :=
begin
  rw norm_p,
  apply inv_lt_one,
  exact_mod_cast hp.1.one_lt
end

@[simp] lemma norm_p_pow (n : ℤ) : ∥(p^n : ℚ_[p])∥ = p^-n :=
by rw [normed_field.norm_zpow, norm_p]; field_simp

instance : nondiscrete_normed_field ℚ_[p] :=
{ non_trivial := ⟨p⁻¹, begin
    rw [normed_field.norm_inv, norm_p, inv_inv₀],
    exact_mod_cast hp.1.one_lt
  end⟩ }

protected theorem image {q : ℚ_[p]} : q ≠ 0 → ∃ n : ℤ, ∥q∥ = ↑((↑p : ℚ) ^ (-n)) :=
quotient.induction_on q $ λ f hf,
  have ¬ f ≈ 0, from (padic_seq.ne_zero_iff_nequiv_zero f).1 hf,
  let ⟨n, hn⟩ := padic_seq.norm_values_discrete f this in
  ⟨n, congr_arg coe hn⟩

protected lemma is_rat (q : ℚ_[p]) : ∃ q' : ℚ, ∥q∥ = ↑q' :=
if h : q = 0 then ⟨0, by simp [h]⟩
else let ⟨n, hn⟩ := padic_norm_e.image h in ⟨_, hn⟩

/--`rat_norm q`, for a `p`-adic number `q` is the `p`-adic norm of `q`, as rational number.

The lemma `padic_norm_e.eq_rat_norm` asserts `∥q∥ = rat_norm q`. -/
def rat_norm (q : ℚ_[p]) : ℚ := classical.some (padic_norm_e.is_rat q)

lemma eq_rat_norm (q : ℚ_[p]) : ∥q∥ = rat_norm q := classical.some_spec (padic_norm_e.is_rat q)

theorem norm_rat_le_one : ∀ {q : ℚ} (hq : ¬ p ∣ q.denom), ∥(q : ℚ_[p])∥ ≤ 1
| ⟨n, d, hn, hd⟩ := λ hq : ¬ p ∣ d,
  if hnz : n = 0 then
    have (⟨n, d, hn, hd⟩ : ℚ) = 0,
    from rat.zero_iff_num_zero.mpr hnz,
    by norm_num [this]
  else
    begin
      have hnz' : { rat . num := n, denom := d, pos := hn, cop := hd } ≠ 0,
        from mt rat.zero_iff_num_zero.1 hnz,
      rw [padic_norm_e.eq_padic_norm],
      norm_cast,
      rw [padic_norm.eq_zpow_of_nonzero p hnz', padic_val_rat_def p hnz'],
      have h : (multiplicity p d).get _ = 0, by simp [multiplicity_eq_zero_of_not_dvd, hq],
      simp only, norm_cast,
      rw_mod_cast [h, sub_zero],
      apply zpow_le_one_of_nonpos,
      { exact_mod_cast le_of_lt hp.1.one_lt, },
      { apply neg_nonpos_of_nonneg, norm_cast, simp, }
    end

theorem norm_int_le_one (z : ℤ) : ∥(z : ℚ_[p])∥ ≤ 1 :=
suffices ∥((z : ℚ) : ℚ_[p])∥ ≤ 1, by simpa,
norm_rat_le_one $ by simp [hp.1.ne_one]

lemma norm_int_lt_one_iff_dvd (k : ℤ) : ∥(k : ℚ_[p])∥ < 1 ↔ ↑p ∣ k :=
begin
  split,
  { intro h,
    contrapose! h,
    apply le_of_eq,
    rw eq_comm,
    calc ∥(k : ℚ_[p])∥ = ∥((k : ℚ) : ℚ_[p])∥ : by { norm_cast }
    ... = padic_norm p k : padic_norm_e.eq_padic_norm _
    ... = 1 : _,
    rw padic_norm,
    split_ifs with H,
    { exfalso,
      apply h,
      norm_cast at H,
      rw H,
      apply dvd_zero },
    { norm_cast at H ⊢,
      convert zpow_zero _,
      simp only [neg_eq_zero],
      rw padic_val_rat.padic_val_rat_of_int _ hp.1.ne_one H,
      norm_cast,
      rw [← enat.coe_inj, enat.coe_get, nat.cast_zero],
      apply multiplicity.multiplicity_eq_zero_of_not_dvd h } },
  { rintro ⟨x, rfl⟩,
    push_cast,
    rw padic_norm_e.mul,
    calc _ ≤ ∥(p : ℚ_[p])∥ * 1 : mul_le_mul (le_refl _) (by simpa using norm_int_le_one _)
                                            (norm_nonneg _) (norm_nonneg _)
    ... < 1 : _,
    { rw [mul_one, padic_norm_e.norm_p],
      apply inv_lt_one,
      exact_mod_cast hp.1.one_lt }, },
end

lemma norm_int_le_pow_iff_dvd (k : ℤ) (n : ℕ) : ∥(k : ℚ_[p])∥ ≤ ((↑p)^(-n : ℤ)) ↔ ↑(p^n) ∣ k :=
begin
  have : (p : ℝ) ^ (-n : ℤ) = ↑((p ^ (-n : ℤ) : ℚ)), {simp},
  rw [show (k : ℚ_[p]) = ((k : ℚ) : ℚ_[p]), by norm_cast, eq_padic_norm, this],
  norm_cast,
  rw padic_norm.dvd_iff_norm_le,
end

lemma eq_of_norm_add_lt_right {p : ℕ} {hp : fact p.prime} {z1 z2 : ℚ_[p]}
  (h : ∥z1 + z2∥ < ∥z2∥) : ∥z1∥ = ∥z2∥ :=
by_contradiction $ λ hne,
  not_lt_of_ge (by rw padic_norm_e.add_eq_max_of_ne hne; apply le_max_right) h

lemma eq_of_norm_add_lt_left {p : ℕ} {hp : fact p.prime} {z1 z2 : ℚ_[p]}
  (h : ∥z1 + z2∥ < ∥z1∥) : ∥z1∥ = ∥z2∥ :=
by_contradiction $ λ hne,
  not_lt_of_ge (by rw padic_norm_e.add_eq_max_of_ne hne; apply le_max_left) h

end normed_space
end padic_norm_e

namespace padic
variables {p : ℕ} [hp_prime : fact p.prime]
include hp_prime

set_option eqn_compiler.zeta true
instance complete : cau_seq.is_complete ℚ_[p] norm :=
begin
  split, intro f,
  have cau_seq_norm_e : is_cau_seq padic_norm_e f,
  { intros ε hε,
    let h := is_cau f ε (by exact_mod_cast hε),
    unfold norm at h,
    apply_mod_cast h },
  cases padic.complete' ⟨f, cau_seq_norm_e⟩ with q hq,
  existsi q,
  intros ε hε,
  cases exists_rat_btwn hε with ε' hε',
  norm_cast at hε',
  cases hq ε' hε'.1 with N hN, existsi N,
  intros i hi, let h := hN i hi,
  unfold norm,
  rw_mod_cast [cau_seq.sub_apply, padic_norm_e.sub_rev],
  refine lt_trans _ hε'.2,
  exact_mod_cast hN i hi
end

lemma padic_norm_e_lim_le {f : cau_seq ℚ_[p] norm} {a : ℝ} (ha : 0 < a)
      (hf : ∀ i, ∥f i∥ ≤ a) : ∥f.lim∥ ≤ a :=
let ⟨N, hN⟩ := setoid.symm (cau_seq.equiv_lim f) _ ha in
calc ∥f.lim∥ = ∥f.lim - f N + f N∥ : by simp
                ... ≤ max (∥f.lim - f N∥) (∥f N∥) : padic_norm_e.nonarchimedean _ _
                ... ≤ a : max_le (le_of_lt (hN _ (le_refl _))) (hf _)

/-!
### Valuation on `ℚ_[p]`
-/

/--
`padic.valuation` lifts the p-adic valuation on rationals to `ℚ_[p]`.
-/
def valuation : ℚ_[p] → ℤ :=
quotient.lift (@padic_seq.valuation p _) (λ f g h,
begin
  by_cases hf : f ≈ 0,
  { have hg : g ≈ 0, from setoid.trans (setoid.symm h) hf,
    simp [hf, hg, padic_seq.valuation] },
  { have hg : ¬ g ≈ 0, from (λ hg, hf (setoid.trans h hg)),
    rw padic_seq.val_eq_iff_norm_eq hf hg,
    exact padic_seq.norm_equiv h },
end)

@[simp] lemma valuation_zero : valuation (0 : ℚ_[p]) = 0 :=
dif_pos ((const_equiv p).2 rfl)

@[simp] lemma valuation_one : valuation (1 : ℚ_[p]) = 0 :=
begin
  change dite (cau_seq.const (padic_norm p) 1 ≈ _) _ _ = _,
  have h : ¬ cau_seq.const (padic_norm p) 1 ≈ 0,
  { assume H, erw const_equiv p at H, exact one_ne_zero H },
  rw dif_neg h,
  simp,
end

lemma norm_eq_pow_val {x : ℚ_[p]} : x ≠ 0 → ∥x∥ = p^(-x.valuation) :=
begin
  apply quotient.induction_on' x, clear x,
  intros f hf,
  change (padic_seq.norm _ : ℝ) = (p : ℝ) ^ -padic_seq.valuation _,
  rw padic_seq.norm_eq_pow_val,
  change ↑((p : ℚ) ^ -padic_seq.valuation f) = (p : ℝ) ^ -padic_seq.valuation f,
  { rw rat.cast_zpow,
    congr' 1,
    norm_cast },
  { apply cau_seq.not_lim_zero_of_not_congr_zero,
    contrapose! hf,
    apply quotient.sound,
    simpa using hf, }
end

@[simp] lemma valuation_p : valuation (p : ℚ_[p]) = 1 :=
begin
  have h : (1 : ℝ) < p := by exact_mod_cast (fact.out p.prime).one_lt,
  rw ← neg_inj,
  apply (zpow_strict_mono h).injective,
  dsimp only,
  rw ← norm_eq_pow_val,
  { simp },
  { exact_mod_cast (fact.out p.prime).ne_zero }
end

section norm_le_iff
/-! ### Various characterizations of open unit balls -/
lemma norm_le_pow_iff_norm_lt_pow_add_one (x : ℚ_[p]) (n : ℤ) :
  ∥x∥ ≤ p ^ n ↔ ∥x∥ < p ^ (n + 1) :=
begin
  have aux : ∀ n : ℤ, 0 < (p ^ n : ℝ),
  { apply nat.zpow_pos_of_pos, exact hp_prime.1.pos },
  by_cases hx0 : x = 0, { simp [hx0, norm_zero, aux, le_of_lt (aux _)], },
  rw norm_eq_pow_val hx0,
  have h1p : 1 < (p : ℝ), { exact_mod_cast hp_prime.1.one_lt },
  have H := zpow_strict_mono h1p,
  rw [H.le_iff_le, H.lt_iff_lt, int.lt_add_one_iff],
end

lemma norm_lt_pow_iff_norm_le_pow_sub_one (x : ℚ_[p]) (n : ℤ) :
  ∥x∥ < p ^ n ↔ ∥x∥ ≤ p ^ (n - 1) :=
by rw [norm_le_pow_iff_norm_lt_pow_add_one, sub_add_cancel]

end norm_le_iff
end padic


/-
Copyright (c) 2021 Vladimir Goryachev. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yaël Dillies, Vladimir Goryachev, Kyle Miller, Scott Morrison, Eric Rodriguez
-/
import data.list.basic
import data.nat.prime
import set_theory.cardinal.finite

/-!
# Counting on ℕ

This file defines the `count` function, which gives, for any predicate on the natural numbers,
"how many numbers under `k` satisfy this predicate?".
We then prove several expected lemmas about `count`, relating it to the cardinality of other
objects, and helping to evaluate it for specific `k`.

-/

open finset

namespace nat
variable (p : ℕ → Prop)

section count
variable [decidable_pred p]

/-- Count the number of naturals `k < n` satisfying `p k`. -/
def count (n : ℕ) : ℕ := (list.range n).countp p

@[simp] lemma count_zero : count p 0 = 0 :=
by rw [count, list.range_zero, list.countp]

/-- A fintype instance for the set relevant to `nat.count`. Locally an instance in locale `count` -/
def count_set.fintype (n : ℕ) : fintype {i // i < n ∧ p i} :=
begin
  apply fintype.of_finset ((finset.range n).filter p),
  intro x,
  rw [mem_filter, mem_range],
  refl,
end

localized "attribute [instance] nat.count_set.fintype" in count

lemma count_eq_card_filter_range (n : ℕ) : count p n = ((range n).filter p).card :=
by { rw [count, list.countp_eq_length_filter], refl, }

/-- `count p n` can be expressed as the cardinality of `{k // k < n ∧ p k}`. -/
lemma count_eq_card_fintype (n : ℕ) : count p n = fintype.card {k : ℕ // k < n ∧ p k} :=
by { rw [count_eq_card_filter_range, ←fintype.card_of_finset, ←count_set.fintype], refl, }

lemma count_succ (n : ℕ) : count p (n + 1) = count p n + (if p n then 1 else 0) :=
by split_ifs; simp [count, list.range_succ, h]

@[mono] lemma count_monotone : monotone (count p) :=
monotone_nat_of_le_succ $ λ n, by by_cases h : p n; simp [count_succ, h]

lemma count_add (a b : ℕ) : count p (a + b) = count p a + count (λ k, p (a + k)) b :=
begin
  have : disjoint ((range a).filter p) (((range b).map $ add_left_embedding a).filter p),
  { intros x hx,
    simp_rw [inf_eq_inter, mem_inter, mem_filter, mem_map, mem_range] at hx,
    obtain ⟨⟨hx, _⟩, ⟨c, _, rfl⟩, _⟩ := hx,
    exact (self_le_add_right _ _).not_lt hx },
  simp_rw [count_eq_card_filter_range, range_add, filter_union, card_disjoint_union this,
    map_filter, add_left_embedding, card_map], refl,
end

lemma count_add' (a b : ℕ) : count p (a + b) = count (λ k, p (k + b)) a + count p b :=
by { rw [add_comm, count_add, add_comm], simp_rw [add_comm b] }

lemma count_one : count p 1 = if p 0 then 1 else 0 := by simp [count_succ]

lemma count_succ' (n : ℕ) : count p (n + 1) = count (λ k, p (k + 1)) n + if p 0 then 1 else 0 :=
by rw [count_add', count_one]

variables {p}

@[simp] lemma count_lt_count_succ_iff {n : ℕ} : count p n < count p (n + 1) ↔ p n :=
by by_cases h : p n; simp [count_succ, h]

lemma count_succ_eq_succ_count_iff {n : ℕ} : count p (n + 1) = count p n + 1 ↔ p n :=
by by_cases h : p n; simp [h, count_succ]

lemma count_succ_eq_count_iff {n : ℕ} : count p (n + 1) = count p n ↔ ¬p n :=
by by_cases h : p n; simp [h, count_succ]

alias count_succ_eq_succ_count_iff ↔ _ count_succ_eq_succ_count
alias count_succ_eq_count_iff ↔ _ count_succ_eq_count

lemma count_le_cardinal (n : ℕ) : (count p n : cardinal) ≤ cardinal.mk {k | p k} :=
begin
  rw [count_eq_card_fintype, ← cardinal.mk_fintype],
  exact cardinal.mk_subtype_mono (λ x hx, hx.2),
end

lemma lt_of_count_lt_count {a b : ℕ} (h : count p a < count p b) : a < b :=
(count_monotone p).reflect_lt h

lemma count_strict_mono {m n : ℕ} (hm : p m) (hmn : m < n) : count p m < count p n :=
(count_lt_count_succ_iff.2 hm).trans_le $ count_monotone _ (nat.succ_le_iff.2 hmn)

lemma count_injective {m n : ℕ} (hm : p m) (hn : p n) (heq : count p m = count p n) : m = n :=
begin
  by_contra,
  wlog hmn : m < n,
  { exact ne.lt_or_lt h },
  { simpa [heq] using count_strict_mono hm hmn }
end

lemma count_le_card (hp : (set_of p).finite) (n : ℕ) : count p n ≤ hp.to_finset.card :=
begin
  rw count_eq_card_filter_range,
  exact finset.card_mono (λ x hx, hp.mem_to_finset.2 (mem_filter.1 hx).2)
end

lemma count_lt_card {n : ℕ} (hp : (set_of p).finite) (hpn : p n) :
  count p n < hp.to_finset.card :=
(count_lt_count_succ_iff.2 hpn).trans_le (count_le_card hp _)

variable {q : ℕ → Prop}
variable [decidable_pred q]

end count

end nat