import Mathlib.Algebra.EuclideanDomain.Basic
import Mathlib.RingTheory.PrincipalIdealDomain
instance : Zero gaussInt :=
instance : One gaussInt :=
instance : Add gaussInt :=
⟨fun x y ↦ ⟨x.re + y.re, x.im + y.im⟩⟩
instance : Neg gaussInt :=
instance : Mul gaussInt :=
⟨fun x y ↦ ⟨x.re * y.re - x.im * y.im, x.re * y.im + x.im * y.re⟩⟩
theorem zero_def : (0 : gaussInt) = ⟨0, 0⟩ :=
theorem one_def : (1 : gaussInt) = ⟨1, 0⟩ :=
theorem add_def (x y : gaussInt) : x + y = ⟨x.re + y.re, x.im + y.im⟩ :=
theorem neg_def (x : gaussInt) : -x = ⟨-x.re, -x.im⟩ :=
theorem mul_def (x y : gaussInt) :
x * y = ⟨x.re * y.re - x.im * y.im, x.re * y.im + x.im * y.re⟩ :=
theorem zero_re : (0 : gaussInt).re = 0 :=
theorem zero_im : (0 : gaussInt).im = 0 :=
theorem one_re : (1 : gaussInt).re = 1 :=
theorem one_im : (1 : gaussInt).im = 0 :=
theorem add_re (x y : gaussInt) : (x + y).re = x.re + y.re :=
theorem add_im (x y : gaussInt) : (x + y).im = x.im + y.im :=
theorem neg_re (x : gaussInt) : (-x).re = -x.re :=
theorem neg_im (x : gaussInt) : (-x).im = -x.im :=
theorem mul_re (x y : gaussInt) : (x * y).re = x.re * y.re - x.im * y.im :=
theorem mul_im (x y : gaussInt) : (x * y).im = x.re * y.im + x.im * y.re :=
instance instCommRing : CommRing gaussInt where
theorem sub_re (x y : gaussInt) : (x - y).re = x.re - y.re :=
theorem sub_im (x y : gaussInt) : (x - y).im = x.im - y.im :=
instance : Nontrivial gaussInt := by
rw [Ne, gaussInt.ext_iff]
theorem div'_add_mod' (a b : ℤ) : b * div' a b + mod' a b = a := by
linarith [Int.ediv_add_emod (a + b / 2) b]
theorem abs_mod'_le (a b : ℤ) (h : 0 < b) : |mod' a b| ≤ b / 2 := by
· linarith [Int.emod_nonneg (a + b / 2) h.ne']
have := Int.emod_lt_of_pos (a + b / 2) h
have := Int.ediv_add_emod b 2
have := Int.emod_lt_of_pos b zero_lt_two
revert this; intro this -- FIXME, this should not be needed
theorem mod'_eq (a b : ℤ) : mod' a b = a - b * div' a b := by linarith [div'_add_mod' a b]
private theorem aux {α : Type*} [LinearOrderedRing α] {x y : α} (h : x ^ 2 + y ^ 2 = 0) : x = 0 :=
haveI h' : x ^ 2 = 0 := by
apply le_antisymm _ (sq_nonneg x)
apply le_add_of_nonneg_right (sq_nonneg y)
theorem sq_add_sq_eq_zero {α : Type*} [LinearOrderedRing α] (x y : α) :
x ^ 2 + y ^ 2 = 0 ↔ x = 0 ∧ y = 0 := by
def norm (x : gaussInt) :=
theorem norm_nonneg (x : gaussInt) : 0 ≤ norm x := by
theorem norm_eq_zero (x : gaussInt) : norm x = 0 ↔ x = 0 := by
rw [norm, sq_add_sq_eq_zero, gaussInt.ext_iff]
theorem norm_pos (x : gaussInt) : 0 < norm x ↔ x ≠ 0 := by
rw [lt_iff_le_and_ne, ne_comm, Ne, norm_eq_zero]
theorem norm_mul (x y : gaussInt) : norm (x * y) = norm x * norm y := by
def conj (x : gaussInt) : gaussInt :=
theorem conj_re (x : gaussInt) : (conj x).re = x.re :=
theorem conj_im (x : gaussInt) : (conj x).im = -x.im :=
theorem norm_conj (x : gaussInt) : norm (conj x) = norm x := by simp [norm]
instance : Div gaussInt :=
⟨fun x y ↦ ⟨Int.div' (x * conj y).re (norm y), Int.div' (x * conj y).im (norm y)⟩⟩
instance : Mod gaussInt :=
⟨fun x y ↦ x - y * (x / y)⟩
theorem div_def (x y : gaussInt) :
x / y = ⟨Int.div' (x * conj y).re (norm y), Int.div' (x * conj y).im (norm y)⟩ :=
theorem mod_def (x y : gaussInt) : x % y = x - y * (x / y) :=
theorem norm_mod_lt (x : gaussInt) {y : gaussInt} (hy : y ≠ 0) :
(x % y).norm < y.norm := by
have norm_y_pos : 0 < norm y := by rwa [norm_pos]
have H1 : x % y * conj y = ⟨Int.mod' (x * conj y).re (norm y), Int.mod' (x * conj y).im (norm y)⟩
· ext <;> simp [Int.mod'_eq, mod_def, div_def, norm] <;> ring
have H2 : norm (x % y) * norm y ≤ norm y / 2 * norm y
norm (x % y) * norm y = norm (x % y * conj y) := by simp only [norm_mul, norm_conj]
_ = |Int.mod' (x.re * y.re + x.im * y.im) (norm y)| ^ 2
+ |Int.mod' (-(x.re * y.im) + x.im * y.re) (norm y)| ^ 2 := by simp [H1, norm, sq_abs]
_ ≤ (y.norm / 2) ^ 2 + (y.norm / 2) ^ 2 := by gcongr <;> apply Int.abs_mod'_le _ _ norm_y_pos
_ = norm y / 2 * (norm y / 2 * 2) := by ring
_ ≤ norm y / 2 * norm y := by gcongr; apply Int.ediv_mul_le; norm_num
calc norm (x % y) ≤ norm y / 2 := le_of_mul_le_mul_right H2 norm_y_pos
apply Int.ediv_lt_of_lt_mul
theorem coe_natAbs_norm (x : gaussInt) : (x.norm.natAbs : ℤ) = x.norm :=
Int.natAbs_of_nonneg (norm_nonneg _)
theorem natAbs_norm_mod_lt (x y : gaussInt) (hy : y ≠ 0) :
(x % y).norm.natAbs < y.norm.natAbs := by
simp only [Int.coe_natAbs, abs_of_nonneg, norm_nonneg]
theorem not_norm_mul_left_lt_norm (x : gaussInt) {y : gaussInt} (hy : y ≠ 0) :
¬(norm (x * y)).natAbs < (norm x).natAbs := by
rw [norm_mul, Int.natAbs_mul]
apply le_mul_of_one_le_right (Nat.zero_le _)
exact Int.add_one_le_of_lt ((norm_pos _).mpr hy)
instance : EuclideanDomain gaussInt :=
{ gaussInt.instCommRing with
quotient_mul_add_remainder_eq :=
fun x y ↦ by simp only; rw [mod_def, add_comm] ; ring
quotient_zero := fun x ↦ by
simp [div_def, norm, Int.div']
r := (measure (Int.natAbs ∘ norm)).1
r_wellFounded := (measure (Int.natAbs ∘ norm)).2
remainder_lt := natAbs_norm_mod_lt
mul_left_not_lt := not_norm_mul_left_lt_norm }
example (x : gaussInt) : Irreducible x ↔ Prime x :=
PrincipalIdealRing.irreducible_iff_prime