import data.nat.basic
import data.int.nat_prime
import data.complex.basic
import tactic
import data.nat.prime
import ring_theory.principal_ideal_domain
import ring_theory.roots_of_unity
import algebra.ring
import algebra.euclidean_domain
import algebra.associated
import Eisenstein_Int

open int_cubic_root
/- if norm = 1 -/
lemma norm_eq_one_2(a b : ℤ): a^2 - a * b + b^2 = 1 →
(abs a = 1 ∧ abs b = 0) ∨ (abs a = 0 ∧ abs b = 1) ∨ (abs a = 1 ∧ abs b = 1):=
begin
     intro h,
     have h1 : (2*a - b)^2 + 3*b^2 = 4,
     calc (2*a - b)^2 + 3*b^2 = 4 * (a^2 - a * b + b^2) : by ring
                      ...     = 4 * 1                   : by rw h
                      ...     = 4                       : by norm_num,
     /-first we show that abs b ≤ 1 and abs a ≤ 1-/
     /-abs b ≤ 1-/
     have h2: abs b ≤ 1,
     {contrapose! h1,
     have h3 : abs b >= 2, by exact lt_le_succ 1 (abs b) h1,
     have a1: 0 ≤ (3 : ℤ), by norm_num,
     have a2: 0 ≤ (4 : ℤ), by norm_num,
     have t2: 4 ≤ (abs b)^2 , by nlinarith,
     have t1: (2*a - b)^2 + 3*b^2 >= 12,
     calc (2*a - b)^2 + 3*b^2 >= 3*b^2   :  by exact left_add_nonneg ((2*a - b)^2) (3*b^2) (pow_two_nonneg (2*a - b))
                ...           = 3 * (abs b)^2 : by rw pow_two_abs b
                ...           = 3 * ((abs b)^2)  : by ring
                ...           ≥ 3 * 4         : by exact mul_le_mul (le_refl 3) t2 a2 a1
                ...           = 12            : by norm_num,
     linarith,},
     have b1: (2*b - a)^2 + 3*a^2 = 4,
     calc (2*b - a)^2 + 3*a^2 = 4 * (a^2 - a * b + b^2) : by ring
                      ...     = 4 * 1                   : by rw h
                      ...     = 4                       : by norm_num,
     /-abs a ≤ 1, the same as the previous part-/
     have h3: abs a <= 1, {contrapose! b1,
     have h3 : abs a >= 2, by exact lt_le_succ 1 (abs a) b1,
     have a1: 0 ≤ (3 : ℤ), by norm_num,
     have a2: 0 ≤ (4 : ℤ), by norm_num,
     have t2: 4 ≤ (abs a)^2 , by nlinarith,
     have t1: (2*b - a)^2 + 3*a^2 >= 12,
     calc (2*b - a)^2 + 3*a^2 >= 3*a^2   :  by exact left_add_nonneg ((2*b - a)^2) (3*a^2) (pow_two_nonneg (2*b - a))
                ...           = 3 * (abs a)^2 : by rw pow_two_abs a
                ...           = 3 * ((abs a)^2)  : by ring
                ...           ≥ 3 * 4         : by exact mul_le_mul (le_refl 3) t2 a2 a1
                ...           = 12            : by norm_num,
     linarith,},
     /-our conclusions-/
     have h4: abs a = 0 ∨ abs a = 1,
     by exact smaller_1 (abs a) ⟨h3, abs_nonneg a⟩,
     have h5: abs b = 0 ∨ abs b = 1,
     by exact smaller_1 (abs b) ⟨h2, abs_nonneg b⟩,
     have h6: (abs a = 0 ∧ abs b = 0) ∨ (abs a = 0 ∧ abs b = 1)∨ (abs a = 1 ∧ abs b = 0) ∨ (abs a = 1 ∧ abs b = 1),
     by tauto,
     have h7: ¬(abs a = 0 ∧ abs b = 0),
     {contrapose! h,
      have t1: a = 0, by exact abs_eq_zero.mp h.1,
      have t2: b = 0, by exact abs_eq_zero.mp h.2,
      have t3: a^2 - a*b + b^2 ≠ 1,
      {rw[t1, t2], ring, norm_num,},
      exact t3, },
     have h8: ¬(abs a = 0 ∧ abs b = 0) ∧ ((abs a = 0 ∧ abs b = 0) ∨ (abs a = 0 ∧ abs b = 1)∨ (abs a = 1 ∧ abs b = 0) ∨ (abs a = 1 ∧ abs b = 1)),
     by exact ⟨h7, h6⟩,
     tauto,
end

lemma abs_either: ∀ x : ℤ, x = abs x ∨ x = -abs x :=
begin
     intro x,
     have h: abs x = x ∨ abs x = -x,  by exact abs_choice x,
     cases h,
     left, rw h,
     right, rw h, ring,
end

lemma norm_eq_one_3(a b : ℤ) :
(a^2 - a * b + b^2 = 1) ∧ ((abs a = 1 ∧ abs b = 1)) →
(a = 1 ∧ b = 1) ∨ (a = -1 ∧ b = -1) :=
begin
     intro h;
     have e: a^2 -a*b + b^2 = 1, by exact h.1,
     have h1: abs a = 1, by exact (h.2).1,
     have h2: abs b = 1, by exact (h.2).2,
     have h3: a = 1 ∨ a = -1,
     {have t1: a = abs a ∨ a = - abs a, by exact abs_either a,
     cases t1,
     {rw [t1, h1], left, norm_num,},
     {rw [t1, h1], right, norm_num,}},
     have h4: b = 1∨ b = -1,
     {have t1: b = abs b ∨ b = - abs b, by exact abs_either b,
     cases t1,
     {rw [t1, h2], left, norm_num, },
     {rw [t1, h2], right, norm_num,}},
     have h5: (a = 1 ∧  b = 1) ∨ (a = -1 ∨ b = 1) ∨ (a = 1 ∧ b = -1) ∨ (a = -1 ∧ b = -1), by tauto,
     have h6: ¬(a = 1 ∧ b = -1), {
     contrapose! e,
     calc a^2 - a*b + b^2 = 1^2 - 1*(-1) + (-1)^2  : by rw [e.1, e.2]
                  ...     ≠ 1                      : by norm_num,},
     have h7: ¬(a = -1 ∧ b = 1), {
     contrapose! e,
     calc a^2 - a*b + b^2 = (-1)^2 - (-1)*1 + 1^2  : by rw [e.1, e.2]
                  ...     ≠ 1                      : by norm_num,},
     tauto,
end

lemma norm_eq_one_1 {x : ℤ_ζ}: (x.a^2 - x.a * x.b + x.b^2 = 1) →
(abs x.a = 1 ∧ abs x.b = 0) ∨ (abs x.a = 0 ∧ abs x.b = 1) ∨ (x = ⟨1, 1⟩
∨ (x = ⟨-1, -1⟩)) :=
begin
     intro h,
     have h1: (abs x.a = 1 ∧ abs x.b = 0) ∨ (abs x.a = 0 ∧ abs x.b = 1)
  ∨ (abs x.a = 1 ∧ abs x.b = 1), by apply norm_eq_one_2 x.a x.b h,
     cases h1,
     {have h2: abs x.a = 1 ∧ abs x.b = 0, tauto, by tauto,},
     {cases h1,
     {have h2: abs x.a = 0 ∧ abs x.b = 1, tauto, by tauto,},
     {have h2: (x.a = 1 ∧ x.b = 1) ∨ (x.a = -1 ∧  x.b = -1),
      by exact norm_eq_one_3 x.a x.b ⟨h, h1⟩,
     cases h2,
     {have h3: x = ⟨1, 1⟩, {simp[ext], exact h2,}, tauto,
     },
     {have h3: x = ⟨-1, -1⟩, {simp[ext], exact h2,}, tauto,},}},
end

lemma not1 (a : ℤ) : 0 < a ∧ a ≠ 1 → 1 < a := by omega

lemma norm_eq_zero_iff (z : ℤ_ζ) : z.norm = 0 ↔ z = 0 :=
begin
  split,
  { intro h,
    rw [ext, zero_a, zero_b],
    have h1 : z.a * z.a - z.a * z.b + z.b * z.b = 0, by exact h,
    have h2: (2* z.a - z.b)^2 + 3*z.b^2 = 0,
    {ring, linarith[h1],},
    have h3: z.b = 0, by nlinarith,
    have h4: (2*z.b - z.a)^2 + 3 * z.a ^2 = 0,
    {ring, linarith[h1],},
    have h5: z.a = 0, by nlinarith,
    exact ⟨h5, h3⟩,
   },
  { rintro rfl, exact norm_zero }
end

lemma gt_if_ge_ne(a b : ℤ) : b ≤ a ∧ a ≠ b → b < a := by omega

lemma abs_pow_two(a : ℤ): a^2 = (abs a)^2 :=
begin
     have h: abs a = a ∨ abs a = -a, by exact abs_choice a,
     cases h, rw h,
     {rw h, ring,},
end

lemma abs_ge_zero (a : ℤ) : 0 ≤ a → abs a = a :=
by exact abs_eq_self.mpr

@[simp] lemma norm_eq_one_iff {x : ℤ_ζ} : x.norm.nat_abs = 1 ↔ is_unit x :=
begin
split,
{intro h,
have h0: x.norm = 1,
calc x.norm  = abs x.norm                :  by rw abs_ge_zero x.norm (norm_nonneg x)
        ...  = ((x.norm).nat_abs :ℤ)     : by exact int.abs_eq_nat_abs x.norm
        ...  =  (1 : ℤ)                  : by linarith [h],
have h0_1: x.a^2 - x.a * x.b + x.b^2 = 1,
calc x.a^2 - x.a * x.b + x.b^2 = x.a * x.a - x.a * x.b + x.b * x.b  : by ring
                       ...     = 1                                  : by exact h0,
have h1: (abs x.a = 1 ∧ abs x.b = 0) ∨ (abs x.a = 0 ∧ abs x.b = 1) ∨  (x = ⟨1, 1⟩ ∨ (x = ⟨-1, -1⟩)),
by exact norm_eq_one_1 h0_1,
 cases h1,
 {have h2: ∃ y : ℤ_ζ,  x * y = 1,
 { have t1: x.a * x.a = 1,
 calc x.a * x.a = x.a ^ 2     : by ring
          ...   = 1^2         : by rw [abs_pow_two x.a, h1.1]
          ...   = 1           : by norm_num,
 use ⟨x.a, 0⟩,
 have a: x.b = 0, by exact abs_eq_zero.mp h1.2,
 rw[eql x, a], simp, rw t1, simp[ext], },
 cases h2 with y ty,
 have h3: is_unit x, by exact is_unit_of_mul_eq_one x y ty, tauto,},
 {cases h1,
 {have e1: x.b^2 = x.b * x.b, by ring,
 have a : x.a = 0, by exact abs_eq_zero.mp h1.1,
 have f1: x * ⟨-x.b, -x.b⟩  = 1,
 calc x* ⟨-x.b, -x.b⟩ = ⟨0, x.b⟩ * ⟨-x.b, -x.b⟩  :  by rw [eql x, a]
       ...           = ⟨(abs x.b)^2, 0⟩        :  by {simp, rw e1,}
       ...            = 1                      : by {rw h1.2, simp[ext],},
 have h3: is_unit x,
 by exact is_unit_of_mul_eq_one x ⟨-x.b, -x.b⟩ f1,
 tauto,},
 {cases h1,
 {have f: x * ⟨0, -1⟩ = 1, {rw h1, simp[ext],},
 have h3: is_unit x,
 by exact is_unit_of_mul_eq_one x ⟨0, -1⟩ f,
 tauto,},
 {have f: x * ⟨0, 1⟩ = 1, {rw h1, simp[ext],},
 have h3: is_unit x,
 by exact is_unit_of_mul_eq_one x ⟨0, 1⟩ f,
 tauto,},}}
},
{intro h,
have h1: ∃ y, x*y = 1, by exact is_unit.exists_right_inv h,
cases h1 with y h1',
have h2: norm x * norm y = 1,
{rw[←norm_mul, h1'], try{refl},},
have a1: norm x ≠ 0, {contrapose! h2,
calc x.norm * y.norm = 0           : by {rw h2, norm_num}
                 ... ≠ 1           : by linarith,},
have a2: norm y ≠ 0, {contrapose! h2,
calc x.norm * y.norm =  0          : by {rw h2, norm_num}
                ...  ≠  1          : by linarith,},
have h3: norm x = 1,
{contrapose! h2,
 have t1: norm x > 0, by exact gt_if_ge_ne (norm x) 0 ⟨norm_nonneg x, a1⟩,
 have t3: norm y > 0, by exact gt_if_ge_ne (norm y) 0 ⟨norm_nonneg y, a2⟩,
 have t2: norm x > 1, by omega,
 have t4: norm y ≥ 1, by omega,
 have t5: norm x * norm y > 1,
 calc norm x * norm y > 1 * 1  : by exact mul_lt_mul t2 t4 zero_lt_one (norm_nonneg x)
                ...   = 1      : by norm_num,
 linarith,
},
calc x.norm.nat_abs = (norm x).nat_abs   : rfl
              ...   =  int.nat_abs (norm x)  : rfl
              ...   =  int.nat_abs (1 : ℤ)   : by rw h3
              ...   =  1                     : by exact int.nat_abs_one,
},
end

lemma is_unit_iff_norm_is_unit (z : ℤ_ζ) : is_unit z ↔ is_unit z.norm :=
by rw [int.is_unit_iff_nat_abs_eq, norm_eq_one_iff]

lemma norm_eq_one_iff'  (z : ℤ_ζ) : z.norm = 1 ↔ is_unit z :=
by rw [←norm_eq_one_iff, ←int.coe_nat_inj', int.nat_abs_of_nonneg (norm_nonneg z),
  int.coe_nat_one]

lemma norm_eq_of_associated {x y : ℤ_ζ} (h : associated x y) :
  x.norm = y.norm :=
begin
  obtain ⟨u, rfl⟩ := h,
  rw [norm_mul, (norm_eq_one_iff' _).mpr u.is_unit],
  ring,
end

/-- arithmetic properties of (1 - ζ)  -/
theorem divide_3 : ∀ a b : ℤ, 1 - ζ ∣ (a + b * ζ) ↔ 3 ∣ a + b :=
begin
     intros a b,
     split,
     {intro h,
     have h1 : ∃ z : ℤ_ζ, (a + b * ζ : ℤ_ζ) = (1 - ζ) * z, by tauto,  /-? Curious-/
     cases h1 with z hz,
     have h2: (⟨1, 0⟩ - ⟨0, 1⟩ : ℤ_ζ) = ⟨1, -1⟩, by refl,
     have h3: (a + b * ζ : ℤ_ζ) = ⟨z.a + z.b, 2 * z.b - z.a⟩,
     calc (a + b * ζ : ℤ_ζ) = (1 - ζ) * z         : by exact hz
                 ...        = (1 - ζ) * ⟨z.a, z.b⟩ : by rw eql z
                 ...        = (⟨1, 0⟩ - ⟨0, 1⟩) * ⟨z.a, z.b⟩  :  by try {refl}
                 ...        = ⟨1, -1⟩ * ⟨z.a, z.b⟩           :  by simp*
                 ...        = ⟨1 * z.a - (-1) * z.b, 1 * z.b + (-1) * z.a - (-1) * z.b⟩ : rfl
                 ...        = ⟨z.a + z.b, 2 * z.b - z.a⟩       : by {simp, ring},
     have h4: (a + b * ζ : ℤ_ζ) = ⟨a, b⟩,
     calc (a + b * ζ : ℤ_ζ) = coe a + coe b * ⟨0, 1⟩  :  by try{refl}
                  ...       = ⟨a, b⟩                  :  by simp*,
     have h5: a + b = 3 * z.b,
     calc a + b = (⟨a, b⟩ : ℤ_ζ).a + (⟨a, b⟩ : ℤ_ζ).b                                            :  by simp
           ...  = (a + b * ζ : ℤ_ζ).a + (a + b * ζ : ℤ_ζ).b                                     :  by rw h4
           ...  = (⟨z.a + z.b, 2 * z.b - z.a⟩ : ℤ_ζ).a + (⟨z.a + z.b, 2 * z.b - z.a⟩ : ℤ_ζ).b    :  by rw h3
           ...  = (z.a + z.b) + (2 * z.b - z.a)                                                 :  rfl
           ...  = 3 * z.b                                                                       :  by ring,
     use ⟨z.b, h5⟩,
     },
     {intro h,
     have h1 : ∃ w : ℤ, a + b = 3 * w, by tauto,
     cases h1 with w hw,
     let x := a - w,
     have h3: (⟨1, 0⟩ - ⟨0, 1⟩ : ℤ_ζ) = ⟨1, -1⟩, by refl,
     have h4: 1 * w + (-1) * x - (-1) * w = 2 * w - x, by ring,
     have h5:  (a + b * ζ : ℤ_ζ) = ⟨a, b⟩,
     calc (a + b * ζ : ℤ_ζ) = coe a + coe b * ⟨0, 1⟩  :  by try{refl}
                  ...       = ⟨a, b⟩                  :  by simp*,
     have h2 : (1 - ζ) * ⟨x, w⟩ = (a + b * ζ : ℤ_ζ),
     calc (1 - ζ) * ⟨x, w⟩ = (⟨1, 0⟩ - ⟨0, 1⟩) * ⟨x, w⟩  :  by try {refl}
               ...        = ⟨1, -1⟩ * ⟨x, w⟩           :  by rw h3
               ...        = ⟨1 * x - (-1) * w, 1 * w + (-1) * x - (-1) * w⟩  : rfl
               ...        = ⟨x + w, 2 * w - x⟩        :  by {rw h4, simp}
               ...        = ⟨x + w, 3 * w - (w + x)⟩  :  by {simp*, ring}
               ...        = ⟨a, a + b - a⟩            :  by simp*
               ...        = ⟨a, b⟩                    :  by simp
               ...        = a + b * ζ                :  by rw h5,
     let y : ℤ_ζ := ⟨x, w⟩,
     have hy: (a + b * ζ : ℤ_ζ) = (1 - ζ) * y,
     calc         (a + b * ζ : ℤ_ζ) = (1 - ζ) * ⟨x, w⟩  : by rw h2
                        ...         = (1 - ζ) * y       : by refl,
     use ⟨y, hy⟩,},
end

/-- give a function of mod-/
def mod : ℤ_ζ → ℤ_ζ → ℤ_ζ → Prop
| d a b := ∃ c : ℤ_ζ, a - b = c * d
theorem mod_def : ∀ d a b : ℤ_ζ, mod d a b → ∃ c : ℤ_ζ, a - b = c * d :=
begin
      intros d a b h, exact h,
end

/-- given d, mod is an equivalent relation-/
theorem mod_self : ∀ d a: ℤ_ζ, mod d a a :=
begin
      intros d a, use 0, ring,
end
theorem mod_symm: ∀ d a b : ℤ_ζ, mod d a b → mod d b a :=
begin
      intros d a b,
      intro h, cases h with c hc, use -c, simp, rw ←hc, ring,
end
theorem mod_trans: ∀ d a b c : ℤ_ζ, mod d a b ∧ mod d b c →
mod d a c :=
begin
      intros d a b c h,
      cases h.1 with x hx,  cases h.2 with y hy,
      use x + y,
      calc a - c = a - b + (b - c) :  by ring
            ...  = x * d + y * d   :  by rw[hx, hy]
            ...  = (x + y) * d     :  by ring,
end
theorem mod_0_dvd : ∀ d a : ℤ_ζ, mod d a 0 → d ∣ a :=
begin
      intros d a h, cases h with c hc,
      use c,
      calc a = a - 0  : by ring
         ... = d * c  : by {rw hc, ring},
end

/-
theorem mod_9 {a b : ℤ} : ¬(1 - ζ ∣ a + b * ζ) →
mod 9 ((a + b * ζ)^3) 1 ∨ mod 9 ((a + b * ζ)^3) (-1) :=
begin
      intro h,
      have h₁ : ¬(3 ∣ (a + b)),
      {contrapose! h, exact (divide_3 a b).mpr h,},
      have h₂ : 3 ∣ a ∨ ¬ (3 ∣ a), by exact em (3 ∣ a),
      have h₃ : 3 ∣ b ∨ ¬ (3 ∣ b), by exact em (3 ∣ b),
      cases h₂,
      {have hb1 : ¬ (3 ∣ b),
      {contrapose! h₁,
      cases h₂ with k hk, cases h₁ with l hl,
      use (k + l),
      simp only[hk, hl], ring,},

      },
end -/

#lint


/-
Copyright (c) 2018 Sébastien Gouëzel. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Isometries of emetric and metric spaces
Authors: Sébastien Gouëzel
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.topology.bounded_continuous_function
import Mathlib.topology.compacts
import Mathlib.PostPort

universes u v w u_1 u_2 l

namespace Mathlib

/-!
# Isometries

We define isometries, i.e., maps between emetric spaces that preserve
the edistance (on metric spaces, these are exactly the maps that preserve distances),
and prove their basic properties. We also introduce isometric bijections.
-/

/-- An isometry (also known as isometric embedding) is a map preserving the edistance
between emetric spaces, or equivalently the distance between metric space.  -/
def isometry {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (f : α → β) :=
  ∀ (x1 x2 : α), edist (f x1) (f x2) = edist x1 x2

/-- On metric spaces, a map is an isometry if and only if it preserves distances. -/
theorem isometry_emetric_iff_metric {α : Type u} {β : Type v} [metric_space α] [metric_space β] {f : α → β} : isometry f ↔ ∀ (x y : α), dist (f x) (f y) = dist x y := sorry

/-- An isometry preserves edistances. -/
theorem isometry.edist_eq {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] {f : α → β} (hf : isometry f) (x : α) (y : α) : edist (f x) (f y) = edist x y :=
  hf x y

/-- An isometry preserves distances. -/
theorem isometry.dist_eq {α : Type u} {β : Type v} [metric_space α] [metric_space β] {f : α → β} (hf : isometry f) (x : α) (y : α) : dist (f x) (f y) = dist x y := sorry

theorem isometry.lipschitz {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] {f : α → β} (h : isometry f) : lipschitz_with 1 f :=
  lipschitz_with.of_edist_le fun (x y : α) => le_of_eq (h x y)

theorem isometry.antilipschitz {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] {f : α → β} (h : isometry f) : antilipschitz_with 1 f := sorry

/-- An isometry is injective -/
theorem isometry.injective {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] {f : α → β} (h : isometry f) : function.injective f :=
  antilipschitz_with.injective (isometry.antilipschitz h)

/-- Any map on a subsingleton is an isometry -/
theorem isometry_subsingleton {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] {f : α → β} [subsingleton α] : isometry f := sorry

/-- The identity is an isometry -/
theorem isometry_id {α : Type u} [emetric_space α] : isometry id :=
  fun (x y : α) => rfl

/-- The composition of isometries is an isometry -/
theorem isometry.comp {α : Type u} {β : Type v} {γ : Type w} [emetric_space α] [emetric_space β] [emetric_space γ] {g : β → γ} {f : α → β} (hg : isometry g) (hf : isometry f) : isometry (g ∘ f) :=
  fun (x y : α) => Eq.trans (hg (f x) (f y)) (hf x y)

/-- An isometry is an embedding -/
theorem isometry.uniform_embedding {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] {f : α → β} (hf : isometry f) : uniform_embedding f :=
  antilipschitz_with.uniform_embedding (isometry.antilipschitz hf)
    (lipschitz_with.uniform_continuous (isometry.lipschitz hf))

/-- An isometry is continuous. -/
theorem isometry.continuous {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] {f : α → β} (hf : isometry f) : continuous f :=
  lipschitz_with.continuous (isometry.lipschitz hf)

/-- The right inverse of an isometry is an isometry. -/
theorem isometry.right_inv {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] {f : α → β} {g : β → α} (h : isometry f) (hg : function.right_inverse g f) : isometry g := sorry

/-- Isometries preserve the diameter in emetric spaces. -/
theorem isometry.ediam_image {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] {f : α → β} (hf : isometry f) (s : set α) : emetric.diam (f '' s) = emetric.diam s := sorry

theorem isometry.ediam_range {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] {f : α → β} (hf : isometry f) : emetric.diam (set.range f) = emetric.diam set.univ :=
  eq.mpr (id (Eq._oldrec (Eq.refl (emetric.diam (set.range f) = emetric.diam set.univ)) (Eq.symm set.image_univ)))
    (isometry.ediam_image hf set.univ)

/-- The injection from a subtype is an isometry -/
theorem isometry_subtype_coe {α : Type u} [emetric_space α] {s : set α} : isometry coe :=
  fun (x y : ↥s) => rfl

/-- An isometry preserves the diameter in metric spaces. -/
theorem isometry.diam_image {α : Type u} {β : Type v} [metric_space α] [metric_space β] {f : α → β} (hf : isometry f) (s : set α) : metric.diam (f '' s) = metric.diam s := sorry

theorem isometry.diam_range {α : Type u} {β : Type v} [metric_space α] [metric_space β] {f : α → β} (hf : isometry f) : metric.diam (set.range f) = metric.diam set.univ :=
  eq.mpr (id (Eq._oldrec (Eq.refl (metric.diam (set.range f) = metric.diam set.univ)) (Eq.symm set.image_univ)))
    (isometry.diam_image hf set.univ)

namespace add_monoid_hom

theorem isometry_iff_norm {E : Type u_1} {F : Type u_2} [normed_group E] [normed_group F] (f : E →+ F) : isometry ⇑f ↔ ∀ (x : E), norm (coe_fn f x) = norm x := sorry

theorem isometry_of_norm {E : Type u_1} {F : Type u_2} [normed_group E] [normed_group F] (f : E →+ F) (hf : ∀ (x : E), norm (coe_fn f x) = norm x) : isometry ⇑f :=
  iff.mpr (isometry_iff_norm f) hf

end add_monoid_hom

/-- `α` and `β` are isometric if there is an isometric bijection between them. -/
structure isometric (α : Type u_1) (β : Type u_2) [emetric_space α] [emetric_space β]
extends α ≃ β
where
  isometry_to_fun : isometry (equiv.to_fun _to_equiv)

infixl:25 " ≃ᵢ " => Mathlib.isometric

namespace isometric

protected instance has_coe_to_fun {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] : has_coe_to_fun (α ≃ᵢ β) :=
  has_coe_to_fun.mk (fun (_x : α ≃ᵢ β) => α → β) fun (e : α ≃ᵢ β) => ⇑(to_equiv e)

theorem coe_eq_to_equiv {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) (a : α) : coe_fn h a = coe_fn (to_equiv h) a :=
  rfl

@[simp] theorem coe_to_equiv {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) : ⇑(to_equiv h) = ⇑h :=
  rfl

protected theorem isometry {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) : isometry ⇑h :=
  isometry_to_fun h

protected theorem edist_eq {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) (x : α) (y : α) : edist (coe_fn h x) (coe_fn h y) = edist x y :=
  isometry.edist_eq (isometric.isometry h) x y

protected theorem dist_eq {α : Type u_1} {β : Type u_2} [metric_space α] [metric_space β] (h : α ≃ᵢ β) (x : α) (y : α) : dist (coe_fn h x) (coe_fn h y) = dist x y :=
  isometry.dist_eq (isometric.isometry h) x y

protected theorem continuous {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) : continuous ⇑h :=
  isometry.continuous (isometric.isometry h)

@[simp] theorem ediam_image {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) (s : set α) : emetric.diam (⇑h '' s) = emetric.diam s :=
  isometry.ediam_image (isometric.isometry h) s

theorem to_equiv_inj {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] {h₁ : α ≃ᵢ β} {h₂ : α ≃ᵢ β} : to_equiv h₁ = to_equiv h₂ → h₁ = h₂ := sorry

theorem ext {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] {h₁ : α ≃ᵢ β} {h₂ : α ≃ᵢ β} (H : ∀ (x : α), coe_fn h₁ x = coe_fn h₂ x) : h₁ = h₂ :=
  to_equiv_inj (equiv.ext H)

/-- Alternative constructor for isometric bijections,
taking as input an isometry, and a right inverse. -/
def mk' {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (f : α → β) (g : β → α) (hfg : ∀ (x : β), f (g x) = x) (hf : isometry f) : α ≃ᵢ β :=
  mk (equiv.mk f g sorry hfg) hf

/-- The identity isometry of a space. -/
protected def refl (α : Type u_1) [emetric_space α] : α ≃ᵢ α :=
  mk (equiv.mk (equiv.to_fun (equiv.refl α)) (equiv.inv_fun (equiv.refl α)) sorry sorry) isometry_id

/-- The composition of two isometric isomorphisms, as an isometric isomorphism. -/
protected def trans {α : Type u} {β : Type v} {γ : Type w} [emetric_space α] [emetric_space β] [emetric_space γ] (h₁ : α ≃ᵢ β) (h₂ : β ≃ᵢ γ) : α ≃ᵢ γ :=
  mk
    (equiv.mk (equiv.to_fun (equiv.trans (to_equiv h₁) (to_equiv h₂)))
      (equiv.inv_fun (equiv.trans (to_equiv h₁) (to_equiv h₂))) sorry sorry)
    sorry

@[simp] theorem trans_apply {α : Type u} {β : Type v} {γ : Type w} [emetric_space α] [emetric_space β] [emetric_space γ] (h₁ : α ≃ᵢ β) (h₂ : β ≃ᵢ γ) (x : α) : coe_fn (isometric.trans h₁ h₂) x = coe_fn h₂ (coe_fn h₁ x) :=
  rfl

/-- The inverse of an isometric isomorphism, as an isometric isomorphism. -/
protected def symm {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) : β ≃ᵢ α :=
  mk (equiv.symm (to_equiv h)) sorry

@[simp] theorem symm_symm {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) : isometric.symm (isometric.symm h) = h :=
  to_equiv_inj (equiv.symm_symm (to_equiv h))

@[simp] theorem apply_symm_apply {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) (y : β) : coe_fn h (coe_fn (isometric.symm h) y) = y :=
  equiv.apply_symm_apply (to_equiv h) y

@[simp] theorem symm_apply_apply {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) (x : α) : coe_fn (isometric.symm h) (coe_fn h x) = x :=
  equiv.symm_apply_apply (to_equiv h) x

theorem symm_apply_eq {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) {x : α} {y : β} : coe_fn (isometric.symm h) y = x ↔ y = coe_fn h x :=
  equiv.symm_apply_eq (to_equiv h)

theorem eq_symm_apply {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) {x : α} {y : β} : x = coe_fn (isometric.symm h) y ↔ coe_fn h x = y :=
  equiv.eq_symm_apply (to_equiv h)

theorem symm_comp_self {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) : ⇑(isometric.symm h) ∘ ⇑h = id :=
  funext fun (a : α) => equiv.left_inv (to_equiv h) a

theorem self_comp_symm {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) : ⇑h ∘ ⇑(isometric.symm h) = id :=
  funext fun (a : β) => equiv.right_inv (to_equiv h) a

@[simp] theorem range_eq_univ {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) : set.range ⇑h = set.univ :=
  set.eq_univ_of_forall fun (b : β) => Exists.intro (coe_fn (isometric.symm h) b) (congr_fun (self_comp_symm h) b)

theorem image_symm {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) : set.image ⇑(isometric.symm h) = set.preimage ⇑h :=
  set.image_eq_preimage_of_inverse (equiv.left_inv (to_equiv (isometric.symm h)))
    (equiv.right_inv (to_equiv (isometric.symm h)))

theorem preimage_symm {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) : set.preimage ⇑(isometric.symm h) = set.image ⇑h :=
  Eq.symm (set.image_eq_preimage_of_inverse (equiv.left_inv (to_equiv h)) (equiv.right_inv (to_equiv h)))

@[simp] theorem symm_trans_apply {α : Type u} {β : Type v} {γ : Type w} [emetric_space α] [emetric_space β] [emetric_space γ] (h₁ : α ≃ᵢ β) (h₂ : β ≃ᵢ γ) (x : γ) : coe_fn (isometric.symm (isometric.trans h₁ h₂)) x = coe_fn (isometric.symm h₁) (coe_fn (isometric.symm h₂) x) :=
  rfl

theorem ediam_univ {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) : emetric.diam set.univ = emetric.diam set.univ := sorry

@[simp] theorem ediam_preimage {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) (s : set β) : emetric.diam (⇑h ⁻¹' s) = emetric.diam s := sorry

/-- The (bundled) homeomorphism associated to an isometric isomorphism. -/
protected def to_homeomorph {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) : α ≃ₜ β :=
  homeomorph.mk (to_equiv h)

@[simp] theorem coe_to_homeomorph {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) : ⇑(isometric.to_homeomorph h) = ⇑h :=
  rfl

@[simp] theorem coe_to_homeomorph_symm {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) : ⇑(homeomorph.symm (isometric.to_homeomorph h)) = ⇑(isometric.symm h) :=
  rfl

@[simp] theorem to_homeomorph_to_equiv {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] (h : α ≃ᵢ β) : homeomorph.to_equiv (isometric.to_homeomorph h) = to_equiv h :=
  rfl

@[simp] theorem comp_continuous_on_iff {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] {γ : Type u_1} [topological_space γ] (h : α ≃ᵢ β) {f : γ → α} {s : set γ} : continuous_on (⇑h ∘ f) s ↔ continuous_on f s :=
  homeomorph.comp_continuous_on_iff (isometric.to_homeomorph h) f s

@[simp] theorem comp_continuous_iff {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] {γ : Type u_1} [topological_space γ] (h : α ≃ᵢ β) {f : γ → α} : continuous (⇑h ∘ f) ↔ continuous f :=
  homeomorph.comp_continuous_iff (isometric.to_homeomorph h)

@[simp] theorem comp_continuous_iff' {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] {γ : Type u_1} [topological_space γ] (h : α ≃ᵢ β) {f : β → γ} : continuous (f ∘ ⇑h) ↔ continuous f :=
  homeomorph.comp_continuous_iff' (isometric.to_homeomorph h)

/-- The group of isometries. -/
protected instance group {α : Type u} [emetric_space α] : group (α ≃ᵢ α) :=
  group.mk (fun (e₁ e₂ : α ≃ᵢ α) => isometric.trans e₂ e₁) sorry (isometric.refl α) sorry sorry isometric.symm
    (div_inv_monoid.div._default (fun (e₁ e₂ : α ≃ᵢ α) => isometric.trans e₂ e₁) sorry (isometric.refl α) sorry sorry
      isometric.symm)
    sorry

@[simp] theorem coe_one {α : Type u} [emetric_space α] : ⇑1 = id :=
  rfl

@[simp] theorem coe_mul {α : Type u} [emetric_space α] (e₁ : α ≃ᵢ α) (e₂ : α ≃ᵢ α) : ⇑(e₁ * e₂) = ⇑e₁ ∘ ⇑e₂ :=
  rfl

theorem mul_apply {α : Type u} [emetric_space α] (e₁ : α ≃ᵢ α) (e₂ : α ≃ᵢ α) (x : α) : coe_fn (e₁ * e₂) x = coe_fn e₁ (coe_fn e₂ x) :=
  rfl

@[simp] theorem inv_apply_self {α : Type u} [emetric_space α] (e : α ≃ᵢ α) (x : α) : coe_fn (e⁻¹) (coe_fn e x) = x :=
  symm_apply_apply e x

@[simp] theorem apply_inv_self {α : Type u} [emetric_space α] (e : α ≃ᵢ α) (x : α) : coe_fn e (coe_fn (e⁻¹) x) = x :=
  apply_symm_apply e x

/-- Addition `y ↦ y + x` as an `isometry`. -/
protected def add_right {G : Type u_1} [normed_group G] (x : G) : G ≃ᵢ G :=
  mk (equiv.mk (equiv.to_fun (equiv.add_right x)) (equiv.inv_fun (equiv.add_right x)) sorry sorry) sorry

@[simp] theorem add_right_to_equiv {G : Type u_1} [normed_group G] (x : G) : to_equiv (isometric.add_right x) = equiv.add_right x :=
  rfl

@[simp] theorem coe_add_right {G : Type u_1} [normed_group G] (x : G) : ⇑(isometric.add_right x) = fun (y : G) => y + x :=
  rfl

theorem add_right_apply {G : Type u_1} [normed_group G] (x : G) (y : G) : coe_fn (isometric.add_right x) y = y + x :=
  rfl

@[simp] theorem add_right_symm {G : Type u_1} [normed_group G] (x : G) : isometric.symm (isometric.add_right x) = isometric.add_right (-x) :=
  ext fun (y : G) => rfl

/-- Addition `y ↦ x + y` as an `isometry`. -/
protected def add_left {G : Type u_1} [normed_group G] (x : G) : G ≃ᵢ G :=
  mk (equiv.add_left x) sorry

@[simp] theorem add_left_to_equiv {G : Type u_1} [normed_group G] (x : G) : to_equiv (isometric.add_left x) = equiv.add_left x :=
  rfl

@[simp] theorem coe_add_left {G : Type u_1} [normed_group G] (x : G) : ⇑(isometric.add_left x) = Add.add x :=
  rfl

@[simp] theorem add_left_symm {G : Type u_1} [normed_group G] (x : G) : isometric.symm (isometric.add_left x) = isometric.add_left (-x) :=
  ext fun (y : G) => rfl

/-- Negation `x ↦ -x` as an `isometry`. -/
protected def neg (G : Type u_1) [normed_group G] : G ≃ᵢ G :=
  mk (equiv.neg G) sorry

@[simp] theorem neg_symm {G : Type u_1} [normed_group G] : isometric.symm (isometric.neg G) = isometric.neg G :=
  rfl

@[simp] theorem neg_to_equiv {G : Type u_1} [normed_group G] : to_equiv (isometric.neg G) = equiv.neg G :=
  rfl

@[simp] theorem coe_neg {G : Type u_1} [normed_group G] : ⇑(isometric.neg G) = Neg.neg :=
  rfl

end isometric

namespace isometric

@[simp] theorem diam_image {α : Type u} {β : Type v} [metric_space α] [metric_space β] (h : α ≃ᵢ β) (s : set α) : metric.diam (⇑h '' s) = metric.diam s :=
  isometry.diam_image (isometric.isometry h) s

@[simp] theorem diam_preimage {α : Type u} {β : Type v} [metric_space α] [metric_space β] (h : α ≃ᵢ β) (s : set β) : metric.diam (⇑h ⁻¹' s) = metric.diam s := sorry

theorem diam_univ {α : Type u} {β : Type v} [metric_space α] [metric_space β] (h : α ≃ᵢ β) : metric.diam set.univ = metric.diam set.univ :=
  congr_arg ennreal.to_real (ediam_univ h)

end isometric

/-- An isometry induces an isometric isomorphism between the source space and the
range of the isometry. -/
def isometry.isometric_on_range {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] {f : α → β} (h : isometry f) : α ≃ᵢ ↥(set.range f) :=
  isometric.mk
    (equiv.mk (equiv.to_fun (equiv.set.range f (isometry.injective h)))
      (equiv.inv_fun (equiv.set.range f (isometry.injective h))) sorry sorry)
    sorry

@[simp] theorem isometry.isometric_on_range_apply {α : Type u} {β : Type v} [emetric_space α] [emetric_space β] {f : α → β} (h : isometry f) (x : α) : coe_fn (isometry.isometric_on_range h) x = { val := f x, property := set.mem_range_self x } :=
  rfl

/-- In a normed algebra, the inclusion of the base field in the extended field is an isometry. -/
theorem algebra_map_isometry (𝕜 : Type u_1) (𝕜' : Type u_2) [normed_field 𝕜] [normed_ring 𝕜'] [normed_algebra 𝕜 𝕜'] : isometry ⇑(algebra_map 𝕜 𝕜') := sorry

/-- The space of bounded sequences, with its sup norm -/
def ℓ_infty_ℝ :=
  bounded_continuous_function ℕ ℝ

namespace Kuratowski_embedding

/-! ### In this section, we show that any separable metric space can be embedded isometrically in ℓ^∞(ℝ) -/

/-- A metric space can be embedded in `l^∞(ℝ)` via the distances to points in
a fixed countable set, if this set is dense. This map is given in the next definition,
without density assumptions. -/
def embedding_of_subset {α : Type u} [metric_space α] (x : ℕ → α) (a : α) : ℓ_infty_ℝ :=
  bounded_continuous_function.of_normed_group_discrete (fun (n : ℕ) => dist a (x n) - dist (x 0) (x n)) (dist a (x 0))
    sorry

theorem embedding_of_subset_coe {α : Type u} {n : ℕ} [metric_space α] (x : ℕ → α) (a : α) : coe_fn (embedding_of_subset x a) n = dist a (x n) - dist (x 0) (x n) :=
  rfl

/-- The embedding map is always a semi-contraction. -/
theorem embedding_of_subset_dist_le {α : Type u} [metric_space α] (x : ℕ → α) (a : α) (b : α) : dist (embedding_of_subset x a) (embedding_of_subset x b) ≤ dist a b := sorry

/-- When the reference set is dense, the embedding map is an isometry on its image. -/
theorem embedding_of_subset_isometry {α : Type u} [metric_space α] (x : ℕ → α) (H : dense_range x) : isometry (embedding_of_subset x) := sorry

/-- Every separable metric space embeds isometrically in ℓ_infty_ℝ. -/
theorem exists_isometric_embedding (α : Type u) [metric_space α] [topological_space.separable_space α] : ∃ (f : α → ℓ_infty_ℝ), isometry f := sorry

end Kuratowski_embedding

/-- The Kuratowski embedding is an isometric embedding of a separable metric space in ℓ^∞(ℝ) -/
def Kuratowski_embedding (α : Type u) [metric_space α] [topological_space.separable_space α] : α → ℓ_infty_ℝ :=
  classical.some sorry

/-- The Kuratowski embedding is an isometry -/
protected theorem Kuratowski_embedding.isometry (α : Type u) [metric_space α] [topological_space.separable_space α] : isometry (Kuratowski_embedding α) :=
  classical.some_spec (Kuratowski_embedding.exists_isometric_embedding α)

/-- Version of the Kuratowski embedding for nonempty compacts -/
def nonempty_compacts.Kuratowski_embedding (α : Type u) [metric_space α] [compact_space α] [Nonempty α] : topological_space.nonempty_compacts ℓ_infty_ℝ :=
  { val := set.range (Kuratowski_embedding α), property := sorry }


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

! This file was ported from Lean 3 source module group_theory.archimedean
! leanprover-community/mathlib commit f93c11933efbc3c2f0299e47b8ff83e9b539cbf6
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathlib.Algebra.Order.Archimedean
import Mathlib.GroupTheory.Subgroup.Basic

/-!
# Archimedean groups

This file proves a few facts about ordered groups which satisfy the `Archimedean` property, that is:
`class Archimedean (α) [OrderedAddCommMonoid α] : Prop :=`
`(arch : ∀ (x : α) {y}, 0 < y → ∃ n : ℕ, x ≤ n • y)`

They are placed here in a separate file (rather than incorporated as a continuation of
`Algebra.Order.Archimedean`) because they rely on some imports from `GroupTheory` -- bundled
subgroups in particular.

The main result is `AddSubgroup.cyclic_of_min`:  a subgroup of a decidable archimedean abelian
group is cyclic, if its set of positive elements has a minimal element.

This result is used in this file to deduce `Int.subgroup_cyclic`, proving that every subgroup of `ℤ`
is cyclic.  (There are several other methods one could use to prove this fact, including more purely
algebraic methods, but none seem to exist in mathlib as of writing.  The closest is
`Subgroup.is_cyclic`, but that has not been transferred to `AddSubgroup`.)

The result is also used in `Topology.Instances.Real` as an ingredient in the classification of
subgroups of `ℝ`.
-/

open Set
variable {G : Type _} [LinearOrderedAddCommGroup G] [Archimedean G]

/-- Given a subgroup `H` of a decidable linearly ordered archimedean abelian group `G`, if there
exists a minimal element `a` of `H ∩ G_{>0}` then `H` is generated by `a`. -/
theorem AddSubgroup.cyclic_of_min {H : AddSubgroup G} {a : G}
    (ha : IsLeast { g : G | g ∈ H ∧ 0 < g } a) : H = AddSubgroup.closure {a} := by
  obtain ⟨⟨a_in, a_pos⟩, a_min⟩ := ha
  refine' le_antisymm _ (H.closure_le.mpr <| by simp [a_in])
  intro g g_in
  obtain ⟨k, ⟨nonneg, lt⟩, _⟩ := existsUnique_zsmul_near_of_pos' a_pos g
  have h_zero : g - k • a = 0 := by
    by_contra h
    have h : a ≤ g - k • a := by
      refine' a_min ⟨_, _⟩
      · exact AddSubgroup.sub_mem H g_in (AddSubgroup.zsmul_mem H a_in k)
      · exact lt_of_le_of_ne nonneg (Ne.symm h)
    have h' : ¬a ≤ g - k • a := not_le.mpr lt
    contradiction
  simp [sub_eq_zero.mp h_zero, AddSubgroup.mem_closure_singleton]
#align add_subgroup.cyclic_of_min AddSubgroup.cyclic_of_min

/-- If a nontrivial additive subgroup of a linear ordered additive commutative group is disjoint
with the interval `Set.Ioo 0 a` for some positive `a`, then the set of positive elements of this
group admits the least element. -/
theorem AddSubgroup.exists_isLeast_pos {H : AddSubgroup G} (hbot : H ≠ ⊥) {a : G} (h₀ : 0 < a)
    (hd : Disjoint (H : Set G) (Ioo 0 a)) : ∃ b, IsLeast { g : G | g ∈ H ∧ 0 < g } b := by
  -- todo: move to a lemma?
  have hex : ∀ g > 0, ∃ n : ℕ, g ∈ Ioc (n • a) ((n + 1) • a) := fun g hg => by
    rcases existsUnique_add_zsmul_mem_Ico h₀ 0 (g - a) with ⟨m, ⟨hm, hm'⟩, -⟩
    simp only [zero_add, sub_le_iff_le_add, sub_add_cancel, ← add_one_zsmul] at hm hm'
    lift m to ℕ
    · rw [← Int.lt_add_one_iff, ← zsmul_lt_zsmul_iff h₀, zero_zsmul]
      exact hg.trans_le hm
    · simp only [← Nat.cast_succ, coe_nat_zsmul] at hm hm'
      exact ⟨m, hm', hm⟩
  have : ∃ n : ℕ, Set.Nonempty (H ∩ Ioc (n • a) ((n + 1) • a))
  · rcases (bot_or_exists_ne_zero H).resolve_left hbot with ⟨g, hgH, hg₀⟩
    rcases hex (|g|) (abs_pos.2 hg₀) with ⟨n, hn⟩
    exact ⟨n, _, (@abs_mem_iff (AddSubgroup G) G _ _).2 hgH, hn⟩
  classical rcases Nat.findX this with ⟨n, ⟨x, hxH, hnx, hxn⟩, hmin⟩
  by_contra hxmin
  simp only [IsLeast, not_and, mem_setOf_eq, mem_lowerBounds, not_exists, not_forall,
    not_le] at hxmin
  rcases hxmin x ⟨hxH, (nsmul_nonneg h₀.le _).trans_lt hnx⟩ with ⟨y, ⟨hyH, hy₀⟩, hxy⟩
  rcases hex y hy₀ with ⟨m, hm⟩
  cases' lt_or_le m n with hmn hnm
  · exact hmin m hmn ⟨y, hyH, hm⟩
  · refine disjoint_left.1 hd (sub_mem hxH hyH) ⟨sub_pos.2 hxy, sub_lt_iff_lt_add'.2 ?_⟩
    calc x ≤ (n + 1) • a := hxn
    _ ≤ (m + 1) • a := nsmul_le_nsmul h₀.le (add_le_add_right hnm _)
    _ = m • a + a := succ_nsmul' _ _
    _ < y + a := add_lt_add_right hm.1 _

/-- If an additive subgroup of a linear ordered additive commutative group is disjoint with the
interval `Set.Ioo 0 a` for some positive `a`, then this is a cyclic subgroup. -/
theorem AddSubgroup.cyclic_of_isolated_zero {H : AddSubgroup G} {a : G} (h₀ : 0 < a)
    (hd : Disjoint (H : Set G) (Ioo 0 a)) : ∃ b, H = closure {b} := by
  rcases eq_or_ne H ⊥ with rfl | hbot
  · exact ⟨0, closure_singleton_zero.symm⟩
  · exact (exists_isLeast_pos hbot h₀ hd).imp fun _ => cyclic_of_min

/-- Every subgroup of `ℤ` is cyclic. -/
theorem Int.subgroup_cyclic (H : AddSubgroup ℤ) : ∃ a, H = AddSubgroup.closure {a} :=
  have : Ioo (0 : ℤ) 1 = ∅ := eq_empty_of_forall_not_mem fun m hm =>
    hm.1.not_le (lt_add_one_iff.1 hm.2)
  AddSubgroup.cyclic_of_isolated_zero one_pos <| by simp [this]
#align int.subgroup_cyclic Int.subgroup_cyclic