/-
Copyright (c) 2020 Devon Tuma. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kenny Lau, Devon Tuma
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.ring_theory.ideal.operations
import Mathlib.ring_theory.polynomial.basic
import Mathlib.PostPort

universes u v

namespace Mathlib

/-!
# Jacobson radical

The Jacobson radical of a ring `R` is defined to be the intersection of all maximal ideals of `R`.
This is similar to how the nilradical is equal to the intersection of all prime ideals of `R`.

We can extend the idea of the nilradical to ideals of `R`,
by letting the radical of an ideal `I` be the intersection of prime ideals containing `I`.
Under this extension, the original nilradical is the radical of the zero ideal `⊥`.
Here we define the Jacobson radical of an ideal `I` in a similar way,
as the intersection of maximal ideals containing `I`.

## Main definitions

Let `R` be a commutative ring, and `I` be an ideal of `R`

* `jacobson I` is the jacobson radical, i.e. the infimum of all maximal ideals containing I.

* `is_local I` is the proposition that the jacobson radical of `I` is itself a maximal ideal

## Main statements

* `mem_jacobson_iff` gives a characterization of members of the jacobson of I

* `is_local_of_is_maximal_radical`: if the radical of I is maximal then so is the jacobson radical

## Tags

Jacobson, Jacobson radical, Local Ideal

-/

namespace ideal

/-- The Jacobson radical of `I` is the infimum of all maximal ideals containing `I`. -/
def jacobson {R : Type u} [comm_ring R] (I : ideal R) : ideal R :=
  Inf (set_of fun (J : ideal R) => I ≤ J ∧ is_maximal J)

theorem le_jacobson {R : Type u} [comm_ring R] {I : ideal R} : I ≤ jacobson I :=
  fun (x : R) (hx : x ∈ I) =>
    iff.mpr mem_Inf
      fun (J : ideal R) (hJ : J ∈ set_of fun (J : ideal R) => I ≤ J ∧ is_maximal J) =>
        and.left hJ x hx

@[simp] theorem jacobson_idem {R : Type u} [comm_ring R] {I : ideal R} :
    jacobson (jacobson I) = jacobson I :=
  sorry

theorem radical_le_jacobson {R : Type u} [comm_ring R] {I : ideal R} : radical I ≤ jacobson I :=
  le_Inf
    fun (J : ideal R) (hJ : J ∈ set_of fun (J : ideal R) => I ≤ J ∧ is_maximal J) =>
      Eq.symm (radical_eq_Inf I) ▸
        Inf_le { left := and.left hJ, right := is_maximal.is_prime (and.right hJ) }

theorem eq_radical_of_eq_jacobson {R : Type u} [comm_ring R] {I : ideal R} :
    jacobson I = I → radical I = I :=
  fun (h : jacobson I = I) => le_antisymm (le_trans radical_le_jacobson (le_of_eq h)) le_radical

@[simp] theorem jacobson_top {R : Type u} [comm_ring R] : jacobson ⊤ = ⊤ :=
  iff.mpr eq_top_iff le_jacobson

@[simp] theorem jacobson_eq_top_iff {R : Type u} [comm_ring R] {I : ideal R} :
    jacobson I = ⊤ ↔ I = ⊤ :=
  sorry

theorem jacobson_eq_bot {R : Type u} [comm_ring R] {I : ideal R} : jacobson I = ⊥ → I = ⊥ :=
  fun (h : jacobson I = ⊥) => iff.mpr eq_bot_iff (h ▸ le_jacobson)

theorem jacobson_eq_self_of_is_maximal {R : Type u} [comm_ring R] {I : ideal R} [H : is_maximal I] :
    jacobson I = I :=
  le_antisymm (Inf_le { left := le_of_eq rfl, right := H }) le_jacobson

protected instance jacobson.is_maximal {R : Type u} [comm_ring R] {I : ideal R} [H : is_maximal I] :
    is_maximal (jacobson I) :=
  { left := fun (htop : jacobson I = ⊤) => and.left H (iff.mp jacobson_eq_top_iff htop),
    right :=
      fun (J : ideal R) (hJ : jacobson I < J) => and.right H J (lt_of_le_of_lt le_jacobson hJ) }

theorem mem_jacobson_iff {R : Type u} [comm_ring R] {I : ideal R} {x : R} :
    x ∈ jacobson I ↔ ∀ (y : R), ∃ (z : R), x * y * z + z - 1 ∈ I :=
  sorry

/-- An ideal equals its Jacobson radical iff it is the intersection of a set of maximal ideals.
Allowing the set to include ⊤ is equivalent, and is included only to simplify some proofs. -/
theorem eq_jacobson_iff_Inf_maximal {R : Type u} [comm_ring R] {I : ideal R} :
    jacobson I = I ↔
        ∃ (M : set (ideal R)), (∀ (J : ideal R), J ∈ M → is_maximal J ∨ J = ⊤) ∧ I = Inf M :=
  sorry

theorem eq_jacobson_iff_Inf_maximal' {R : Type u} [comm_ring R] {I : ideal R} :
    jacobson I = I ↔
        ∃ (M : set (ideal R)),
          (∀ (J : ideal R), J ∈ M → ∀ (K : ideal R), J < K → K = ⊤) ∧ I = Inf M :=
  sorry

/-- An ideal `I` equals its Jacobson radical if and only if every element outside `I`
also lies outside of a maximal ideal containing `I`. -/
theorem eq_jacobson_iff_not_mem {R : Type u} [comm_ring R] {I : ideal R} :
    jacobson I = I ↔ ∀ (x : R), ¬x ∈ I → ∃ (M : ideal R), (I ≤ M ∧ is_maximal M) ∧ ¬x ∈ M :=
  sorry

theorem map_jacobson_of_surjective {R : Type u} [comm_ring R] {I : ideal R} {S : Type v}
    [comm_ring S] {f : R →+* S} (hf : function.surjective ⇑f) :
    ring_hom.ker f ≤ I → map f (jacobson I) = jacobson (map f I) :=
  sorry

theorem map_jacobson_of_bijective {R : Type u} [comm_ring R] {I : ideal R} {S : Type v}
    [comm_ring S] {f : R →+* S} (hf : function.bijective ⇑f) :
    map f (jacobson I) = jacobson (map f I) :=
  map_jacobson_of_surjective (and.right hf)
    (le_trans (le_of_eq (iff.mp (ring_hom.injective_iff_ker_eq_bot f) (and.left hf))) bot_le)

theorem comap_jacobson {R : Type u} [comm_ring R] {S : Type v} [comm_ring S] {f : R →+* S}
    {K : ideal S} :
    comap f (jacobson K) = Inf (comap f '' set_of fun (J : ideal S) => K ≤ J ∧ is_maximal J) :=
  trans (comap_Inf' f (set_of fun (J : ideal S) => K ≤ J ∧ is_maximal J)) (Eq.symm Inf_eq_infi)

theorem comap_jacobson_of_surjective {R : Type u} [comm_ring R] {S : Type v} [comm_ring S]
    {f : R →+* S} (hf : function.surjective ⇑f) {K : ideal S} :
    comap f (jacobson K) = jacobson (comap f K) :=
  sorry

theorem mem_jacobson_bot {R : Type u} [comm_ring R] {x : R} :
    x ∈ jacobson ⊥ ↔ ∀ (y : R), is_unit (x * y + 1) :=
  sorry

/-- An ideal `I` of `R` is equal to its Jacobson radical if and only if
the Jacobson radical of the quotient ring `R/I` is the zero ideal -/
theorem jacobson_eq_iff_jacobson_quotient_eq_bot {R : Type u} [comm_ring R] {I : ideal R} :
    jacobson I = I ↔ jacobson ⊥ = ⊥ :=
  sorry

/-- The standard radical and Jacobson radical of an ideal `I` of `R` are equal if and only if
the nilradical and Jacobson radical of the quotient ring `R/I` coincide -/
theorem radical_eq_jacobson_iff_radical_quotient_eq_jacobson_bot {R : Type u} [comm_ring R]
    {I : ideal R} : radical I = jacobson I ↔ radical ⊥ = jacobson ⊥ :=
  sorry

theorem jacobson_mono {R : Type u} [comm_ring R] {I : ideal R} {J : ideal R} :
    I ≤ J → jacobson I ≤ jacobson J :=
  sorry

theorem jacobson_radical_eq_jacobson {R : Type u} [comm_ring R] {I : ideal R} :
    jacobson (radical I) = jacobson I :=
  sorry

theorem jacobson_bot_polynomial_le_Inf_map_maximal {R : Type u} [comm_ring R] :
    jacobson ⊥ ≤ Inf (map polynomial.C '' set_of fun (J : ideal R) => is_maximal J) :=
  sorry

theorem jacobson_bot_polynomial_of_jacobson_bot {R : Type u} [comm_ring R] (h : jacobson ⊥ = ⊥) :
    jacobson ⊥ = ⊥ :=
  sorry

/-- An ideal `I` is local iff its Jacobson radical is maximal. -/
def is_local {R : Type u} [comm_ring R] (I : ideal R) := is_maximal (jacobson I)

theorem is_local_of_is_maximal_radical {R : Type u} [comm_ring R] {I : ideal R}
    (hi : is_maximal (radical I)) : is_local I :=
  sorry

theorem is_local.le_jacobson {R : Type u} [comm_ring R] {I : ideal R} {J : ideal R}
    (hi : is_local I) (hij : I ≤ J) (hj : J ≠ ⊤) : J ≤ jacobson I :=
  sorry

theorem is_local.mem_jacobson_or_exists_inv {R : Type u} [comm_ring R] {I : ideal R}
    (hi : is_local I) (x : R) : x ∈ jacobson I ∨ ∃ (y : R), y * x - 1 ∈ I :=
  sorry

theorem is_primary_of_is_maximal_radical {R : Type u} [comm_ring R] {I : ideal R}
    (hi : is_maximal (radical I)) : is_primary I :=
  sorry

end Mathlib


def f (x : Nat) (y : Nat := 1) (w : Nat := 2) (z : Nat) :=
x + y + w - z

theorem ex1 (x z : Nat) : f (z := z) x = x + 1 + 2 - z :=
rfl

theorem ex2 (x z : Nat) : f x (z := z) = x + 1 + 2 - z :=
rfl

theorem ex3 (x y : Nat) : f x y = fun z => x + y + 2 - z :=
rfl

theorem ex4 : f = (fun x z => x + 1 + 2 - z) :=
rfl

theorem ex5 (x : Nat) : f x = fun z => x + 1 + 2 - z :=
rfl

theorem ex6 (y : Nat) : f (y := 5) = fun x z => x + 5 + 2 - z :=
rfl

def g {α} [Add α] (a : α) (b? : Option α := none) (c : α) : α :=
match b? with
| none   => a + c
| some b => a + b + c

variable {α} [Add α]

theorem ex7 : g = fun (a c : α) => a + c :=
rfl

theorem ex8 (x : α) : g (c := x) = fun (a : α) => a + x :=
rfl

theorem ex9 (x : α) : g (b? := some x) = fun (a c : α) => a + x + c :=
rfl

theorem ex10 (x : α) : g x = fun (c : α) => x + c :=
rfl

theorem ex11 (x y : α) : g x y = fun (c : α) => x + y + c :=
rfl


/-
Copyright (c) 2018 Kenny Lau. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kenny Lau, Mario Carneiro, Johan Commelin, Amelia Livingston, Anne Baanen
-/
import algebra.algebra.tower
import ring_theory.localization.basic

/-!
# Fraction ring / fraction field Frac(R) as localization

## Main definitions

 * `is_fraction_ring R K` expresses that `K` is a field of fractions of `R`, as an abbreviation of
   `is_localization (non_zero_divisors R) K`

## Main results

 * `is_fraction_ring.field`: a definition (not an instance) stating the localization of an integral
   domain `R` at `R \ {0}` is a field
 * `rat.is_fraction_ring` is an instance stating `ℚ` is the field of fractions of `ℤ`

## Implementation notes

See `src/ring_theory/localization/basic.lean` for a design overview.

## Tags
localization, ring localization, commutative ring localization, characteristic predicate,
commutative ring, field of fractions
-/
variables (R : Type*) [comm_ring R] {M : submonoid R} (S : Type*) [comm_ring S]
variables [algebra R S] {P : Type*} [comm_ring P]
variables {A : Type*} [comm_ring A] [is_domain A] (K : Type*)

/-- `is_fraction_ring R K` states `K` is the field of fractions of an integral domain `R`. -/
-- TODO: should this extend `algebra` instead of assuming it?
abbreviation is_fraction_ring [comm_ring K] [algebra R K] := is_localization (non_zero_divisors R) K

/-- The cast from `int` to `rat` as a `fraction_ring`. -/
instance rat.is_fraction_ring : is_fraction_ring ℤ ℚ :=
{ map_units :=
  begin
    rintro ⟨x, hx⟩,
    rw mem_non_zero_divisors_iff_ne_zero at hx,
    simpa only [ring_hom.eq_int_cast, is_unit_iff_ne_zero, int.cast_eq_zero,
                ne.def, subtype.coe_mk] using hx,
    end,
  surj :=
  begin
    rintro ⟨n, d, hd, h⟩,
    refine ⟨⟨n, ⟨d, _⟩⟩, rat.mul_denom_eq_num⟩,
    rwa [mem_non_zero_divisors_iff_ne_zero, int.coe_nat_ne_zero_iff_pos]
  end,
  eq_iff_exists :=
  begin
    intros x y,
    rw [ring_hom.eq_int_cast, ring_hom.eq_int_cast, int.cast_inj],
    refine ⟨by { rintro rfl, use 1 }, _⟩,
    rintro ⟨⟨c, hc⟩, h⟩,
    apply int.eq_of_mul_eq_mul_right _ h,
    rwa mem_non_zero_divisors_iff_ne_zero at hc,
  end }

namespace is_fraction_ring

open is_localization

variables {R K}

section comm_ring

variables [comm_ring K] [algebra R K] [is_fraction_ring R K] [algebra A K] [is_fraction_ring A K]

lemma to_map_eq_zero_iff {x : R} :
  algebra_map R K x = 0 ↔ x = 0 :=
to_map_eq_zero_iff _ (le_of_eq rfl)

variables (R K)

protected theorem injective : function.injective (algebra_map R K) :=
is_localization.injective _ (le_of_eq rfl)

variables {R K}

@[priority 100] instance [no_zero_divisors K] : no_zero_smul_divisors R K :=
no_zero_smul_divisors.of_algebra_map_injective $ is_fraction_ring.injective R K

variables {R K}

protected lemma to_map_ne_zero_of_mem_non_zero_divisors [nontrivial R]
  {x : R} (hx : x ∈ non_zero_divisors R) : algebra_map R K x ≠ 0 :=
is_localization.to_map_ne_zero_of_mem_non_zero_divisors _ le_rfl hx

variables (A)

/-- A `comm_ring` `K` which is the localization of an integral domain `R` at `R - {0}` is an
integral domain. -/
protected theorem is_domain : is_domain K :=
is_domain_of_le_non_zero_divisors _ (le_refl (non_zero_divisors A))

local attribute [instance] classical.dec_eq

/-- The inverse of an element in the field of fractions of an integral domain. -/
@[irreducible]
protected noncomputable def inv (z : K) : K :=
if h : z = 0 then 0 else
mk' K ↑(sec (non_zero_divisors A) z).2
  ⟨(sec _ z).1,
   mem_non_zero_divisors_iff_ne_zero.2 $ λ h0, h $
    eq_zero_of_fst_eq_zero (sec_spec (non_zero_divisors A) z) h0⟩

local attribute [semireducible] is_fraction_ring.inv

protected lemma mul_inv_cancel (x : K) (hx : x ≠ 0) :
  x * is_fraction_ring.inv A x = 1 :=
show x * dite _ _ _ = 1, by rw [dif_neg hx,
  ←is_unit.mul_left_inj (map_units K ⟨(sec _ x).1, mem_non_zero_divisors_iff_ne_zero.2 $
    λ h0, hx $ eq_zero_of_fst_eq_zero (sec_spec (non_zero_divisors A) x) h0⟩),
  one_mul, mul_assoc, mk'_spec, ←eq_mk'_iff_mul_eq]; exact (mk'_sec _ x).symm

/-- A `comm_ring` `K` which is the localization of an integral domain `R` at `R - {0}` is a field.
See note [reducible non-instances]. -/
@[reducible]
noncomputable def to_field : field K :=
{ inv := is_fraction_ring.inv A,
  mul_inv_cancel := is_fraction_ring.mul_inv_cancel A,
  inv_zero := dif_pos rfl,
  .. is_fraction_ring.is_domain A,
  .. show comm_ring K, by apply_instance }

end comm_ring

variables {B : Type*} [comm_ring B] [is_domain B] [field K] {L : Type*} [field L]
  [algebra A K] [is_fraction_ring A K] {g : A →+* L}

lemma mk'_mk_eq_div {r s} (hs : s ∈ non_zero_divisors A) :
  mk' K r ⟨s, hs⟩ = algebra_map A K r / algebra_map A K s :=
mk'_eq_iff_eq_mul.2 $ (div_mul_cancel (algebra_map A K r)
    (is_fraction_ring.to_map_ne_zero_of_mem_non_zero_divisors hs)).symm

@[simp] lemma mk'_eq_div {r} (s : non_zero_divisors A) :
  mk' K r s = algebra_map A K r / algebra_map A K s :=
mk'_mk_eq_div s.2

lemma div_surjective (z : K) : ∃ (x y : A) (hy : y ∈ non_zero_divisors A),
  algebra_map _ _ x / algebra_map _ _ y = z :=
let ⟨x, ⟨y, hy⟩, h⟩ := mk'_surjective (non_zero_divisors A) z
in ⟨x, y, hy, by rwa mk'_eq_div at h⟩

lemma is_unit_map_of_injective (hg : function.injective g)
  (y : non_zero_divisors A) : is_unit (g y) :=
is_unit.mk0 (g y) $ show g.to_monoid_with_zero_hom y ≠ 0,
  from map_ne_zero_of_mem_non_zero_divisors g hg y.2

@[simp] lemma mk'_eq_zero_iff_eq_zero [algebra R K] [is_fraction_ring R K] {x : R}
  {y : non_zero_divisors R} : mk' K x y = 0 ↔ x = 0 :=
begin
  refine ⟨λ hxy, _, λ h, by rw [h, mk'_zero]⟩,
  { simp_rw [mk'_eq_zero_iff, mul_right_coe_non_zero_divisors_eq_zero_iff] at hxy,
    exact (exists_const _).mp hxy },
end

lemma mk'_eq_one_iff_eq {x : A} {y : non_zero_divisors A} : mk' K x y = 1 ↔ x = y :=
begin
  refine ⟨_, λ hxy, by rw [hxy, mk'_self']⟩,
  { intro hxy, have hy : (algebra_map A K) ↑y ≠ (0 : K) :=
    is_fraction_ring.to_map_ne_zero_of_mem_non_zero_divisors y.property,
    rw [is_fraction_ring.mk'_eq_div, div_eq_one_iff_eq hy] at hxy,
    exact is_fraction_ring.injective A K hxy }
end

open function

/-- Given an integral domain `A` with field of fractions `K`,
and an injective ring hom `g : A →+* L` where `L` is a field, we get a
field hom sending `z : K` to `g x * (g y)⁻¹`, where `(x, y) : A × (non_zero_divisors A)` are
such that `z = f x * (f y)⁻¹`. -/
noncomputable def lift (hg : injective g) : K →+* L :=
lift $ λ (y : non_zero_divisors A), is_unit_map_of_injective hg y

/-- Given an integral domain `A` with field of fractions `K`,
and an injective ring hom `g : A →+* L` where `L` is a field,
the field hom induced from `K` to `L` maps `x` to `g x` for all
`x : A`. -/
@[simp] lemma lift_algebra_map (hg : injective g) (x) :
  lift hg (algebra_map A K x) = g x :=
lift_eq _ _

/-- Given an integral domain `A` with field of fractions `K`,
and an injective ring hom `g : A →+* L` where `L` is a field,
field hom induced from `K` to `L` maps `f x / f y` to `g x / g y` for all
`x : A, y ∈ non_zero_divisors A`. -/
lemma lift_mk' (hg : injective g) (x) (y : non_zero_divisors A) :
  lift hg (mk' K x y) = g x / g y :=
by simp only [mk'_eq_div, ring_hom.map_div, lift_algebra_map]

/-- Given integral domains `A, B` with fields of fractions `K`, `L`
and an injective ring hom `j : A →+* B`, we get a field hom
sending `z : K` to `g (j x) * (g (j y))⁻¹`, where `(x, y) : A × (non_zero_divisors A)` are
such that `z = f x * (f y)⁻¹`. -/
noncomputable def map {A B K L : Type*} [comm_ring A] [comm_ring B] [is_domain B]
  [comm_ring K] [algebra A K] [is_fraction_ring A K] [comm_ring L] [algebra B L]
  [is_fraction_ring B L] {j : A →+* B} (hj : injective j) :
  K →+* L :=
map L j (show non_zero_divisors A ≤ (non_zero_divisors B).comap j,
         from non_zero_divisors_le_comap_non_zero_divisors_of_injective j hj)

/-- Given integral domains `A, B` and localization maps to their fields of fractions
`f : A →+* K, g : B →+* L`, an isomorphism `j : A ≃+* B` induces an isomorphism of
fields of fractions `K ≃+* L`. -/
noncomputable def field_equiv_of_ring_equiv [algebra B L] [is_fraction_ring B L] (h : A ≃+* B) :
  K ≃+* L :=
ring_equiv_of_ring_equiv K L h
begin
  ext b,
  show b ∈ h.to_equiv '' _ ↔ _,
  erw [h.to_equiv.image_eq_preimage, set.preimage, set.mem_set_of_eq,
       mem_non_zero_divisors_iff_ne_zero, mem_non_zero_divisors_iff_ne_zero],
  exact h.symm.map_ne_zero_iff
end

variables (S)

lemma is_fraction_ring_iff_of_base_ring_equiv (h : R ≃+* P) :
  is_fraction_ring R S ↔
    @@is_fraction_ring P _ S _ ((algebra_map R S).comp h.symm.to_ring_hom).to_algebra :=
begin
  delta is_fraction_ring,
  convert is_localization_iff_of_base_ring_equiv _ _ h,
  ext x,
  erw submonoid.map_equiv_eq_comap_symm,
  simp only [mul_equiv.coe_to_monoid_hom,
    ring_equiv.to_mul_equiv_eq_coe, submonoid.mem_comap],
  split,
  { rintros hx z (hz : z * h.symm x = 0),
    rw ← h.map_eq_zero_iff,
    apply hx,
    simpa only [h.map_zero, h.apply_symm_apply, h.map_mul] using congr_arg h hz },
  { rintros (hx : h.symm x ∈ _) z hz,
    rw ← h.symm.map_eq_zero_iff,
    apply hx,
    rw [← h.symm.map_mul, hz, h.symm.map_zero] }
end

protected
lemma nontrivial (R S : Type*) [comm_ring R] [nontrivial R] [comm_ring S] [algebra R S]
  [is_fraction_ring R S] : nontrivial S :=
begin
  apply nontrivial_of_ne,
  intro h,
  apply @zero_ne_one R,
  exact is_localization.injective S (le_of_eq rfl)
    (((algebra_map R S).map_zero.trans h).trans (algebra_map R S).map_one.symm),
end

end is_fraction_ring

variables (R A)

/-- The fraction ring of a commutative ring `R` as a quotient type.

We instantiate this definition as generally as possible, and assume that the
commutative ring `R` is an integral domain only when this is needed for proving.
-/
@[reducible] def fraction_ring := localization (non_zero_divisors R)

namespace fraction_ring

instance unique [subsingleton R] : unique (fraction_ring R) :=
localization.unique

instance [nontrivial R] : nontrivial (fraction_ring R) :=
⟨⟨(algebra_map R _) 0, (algebra_map _ _) 1,
  λ H, zero_ne_one (is_localization.injective _ le_rfl H)⟩⟩

variables {A}

noncomputable instance : field (fraction_ring A) :=
{ add := (+),
  mul := (*),
  neg := has_neg.neg,
  sub := has_sub.sub,
  one := 1,
  zero := 0,
  nsmul := add_monoid.nsmul,
  zsmul := sub_neg_monoid.zsmul,
  npow := localization.npow _,
  .. localization.comm_ring,
  .. is_fraction_ring.to_field A }

@[simp] lemma mk_eq_div {r s} : (localization.mk r s : fraction_ring A) =
  (algebra_map _ _ r / algebra_map A _ s : fraction_ring A) :=
by rw [localization.mk_eq_mk', is_fraction_ring.mk'_eq_div]

noncomputable instance [is_domain R] [field K] [algebra R K] [no_zero_smul_divisors R K] :
  algebra (fraction_ring R) K :=
ring_hom.to_algebra (is_fraction_ring.lift (no_zero_smul_divisors.algebra_map_injective R _))

instance [is_domain R] [field K] [algebra R K] [no_zero_smul_divisors R K] :
  is_scalar_tower R (fraction_ring R) K :=
is_scalar_tower.of_algebra_map_eq (λ x, (is_fraction_ring.lift_algebra_map _ x).symm)

variables (A)

/-- Given an integral domain `A` and a localization map to a field of fractions
`f : A →+* K`, we get an `A`-isomorphism between the field of fractions of `A` as a quotient
type and `K`. -/
noncomputable def alg_equiv (K : Type*) [field K] [algebra A K] [is_fraction_ring A K] :
  fraction_ring A ≃ₐ[A] K :=
localization.alg_equiv (non_zero_divisors A) K

instance [algebra R A] [no_zero_smul_divisors R A] : no_zero_smul_divisors R (fraction_ring A) :=
no_zero_smul_divisors.of_algebra_map_injective
  begin
    rw [is_scalar_tower.algebra_map_eq R A],
    exact function.injective.comp
      (no_zero_smul_divisors.algebra_map_injective _ _)
      (no_zero_smul_divisors.algebra_map_injective _ _)
  end

end fraction_ring


import Mathlib.Tactic.Relation.Symm
import Mathlib.Algebra.Hom.Group
import Mathlib.Logic.Equiv.Basic

-- testing that the attribute is recognized
@[symm] def eq_symm {α : Type} (a b : α) : a = b → b = a := Eq.symm

example (a b : Nat) : a = b → b = a := by intros; symm; assumption
example (a b : Nat) : a = b → True → b = a := by intro h _; symm at h; assumption

def sameParity : Nat → Nat → Prop
| n, m => n % 2 = m % 2

@[symm] def sameParity_symm (n m : Nat) : sameParity n m → sameParity m n := Eq.symm

example (a b : Nat) : sameParity a b → sameParity b a := by intros; symm; assumption

example (a b c : Nat) (ab : a = b) (bc : b = c) : c = a := by
  symm_saturate
  -- Run twice to check that we don't add repeated copies.
  -- Unfortunately `guard_hyp_nums` doesn't seem to work so I haven't made an assertion.
  symm_saturate
  apply Eq.trans <;> assumption

def MulHom.inverse [Mul M] [Mul N] (f : M →ₙ* N) (g : N → M) (h₁ : Function.LeftInverse g f)
    (h₂ : Function.RightInverse g f) : N →ₙ* M where
  toFun := g
  map_mul' x y :=
    calc
      g (x * y) = g (f (g x) * f (g y)) := by rw [h₂ x, h₂ y]
      _ = g (f (g x * g y)) := by rw [f.map_mul]
      _ = g x * g y := h₁ _

structure MulEquiv (M N : Type u) [Mul M] [Mul N] extends M ≃ N, M →ₙ* N

#check @MulEquiv

infixl:25 " ≃* " => MulEquiv

@[symm]
def foo_symm {M N : Type _} [Mul M] [Mul N] (h : M ≃* N) : N ≃* M :=
  { h.toEquiv.symm with map_mul' := (h.toMulHom.inverse h.toEquiv.symm h.left_inv h.right_inv).map_mul }


/-
Copyright (c) 2020 Scott Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Scott Morrison
-/
import topology.sheaves.sheaf_condition.equalizer_products
import category_theory.full_subcategory
import category_theory.limits.unit

/-!
# Sheaves

We define sheaves on a topological space, with values in an arbitrary category with products.

The sheaf condition for a `F : presheaf C X` requires that the morphism
`F.obj U ⟶ ∏ F.obj (U i)` (where `U` is some open set which is the union of the `U i`)
is the equalizer of the two morphisms
`∏ F.obj (U i) ⟶ ∏ F.obj (U i ⊓ U j)`.

We provide the instance `category (sheaf C X)` as the full subcategory of presheaves,
and the fully faithful functor `sheaf.forget : sheaf C X ⥤ presheaf C X`.

## Equivalent conditions

While the "official" definition is in terms of an equalizer diagram,
in `src/topology/sheaves/sheaf_condition/pairwise_intersections.lean`
and in `src/topology/sheaves/sheaf_condition/open_le_cover.lean`
we provide two equivalent conditions (and prove they are equivalent).

The first is that `F.obj U` is the limit point of the diagram consisting of all the `F.obj (U i)`
and `F.obj (U i ⊓ U j)`.
(That is, we explode the equalizer of two products out into its component pieces.)

The second is that `F.obj U` is the limit point of the diagram constisting of all the `F.obj V`,
for those `V : opens X` such that `V ≤ U i` for some `i`.
(This condition is particularly easy to state, and perhaps should become the "official" definition.)

-/

universes w v u

noncomputable theory

open category_theory
open category_theory.limits
open topological_space
open opposite
open topological_space.opens

namespace Top

variables {C : Type u} [category.{v} C] [has_products.{v} C]
variables {X : Top.{w}} (F : presheaf C X) {ι : Type v} (U : ι → opens X)

namespace presheaf

open sheaf_condition_equalizer_products

/--
The sheaf condition for a `F : presheaf C X` requires that the morphism
`F.obj U ⟶ ∏ F.obj (U i)` (where `U` is some open set which is the union of the `U i`)
is the equalizer of the two morphisms
`∏ F.obj (U i) ⟶ ∏ F.obj (U i) ⊓ (U j)`.
-/
def is_sheaf (F : presheaf.{w v u} C X) : Prop :=
∀ ⦃ι : Type v⦄ (U : ι → opens X), nonempty (is_limit (sheaf_condition_equalizer_products.fork F U))

/--
The presheaf valued in `unit` over any topological space is a sheaf.
-/
lemma is_sheaf_unit (F : presheaf (category_theory.discrete unit) X) : F.is_sheaf :=
λ ι U, ⟨punit_cone_is_limit⟩

/--
Transfer the sheaf condition across an isomorphism of presheaves.
-/
lemma is_sheaf_of_iso {F G : presheaf C X} (α : F ≅ G) (h : F.is_sheaf) : G.is_sheaf :=
λ ι U, ⟨is_limit.of_iso_limit
  ((is_limit.postcompose_inv_equiv _ _).symm (h U).some)
  (sheaf_condition_equalizer_products.fork.iso_of_iso U α.symm).symm⟩

lemma is_sheaf_iso_iff {F G : presheaf C X} (α : F ≅ G) : F.is_sheaf ↔ G.is_sheaf :=
⟨(λ h, is_sheaf_of_iso α h), (λ h, is_sheaf_of_iso α.symm h)⟩

end presheaf

variables (C X)

/--
A `sheaf C X` is a presheaf of objects from `C` over a (bundled) topological space `X`,
satisfying the sheaf condition.
-/
@[derive category]
def sheaf : Type (max u v w) := { F : presheaf C X // F.is_sheaf }

-- Let's construct a trivial example, to keep the inhabited linter happy.
instance sheaf_inhabited : inhabited (sheaf (category_theory.discrete punit) X) :=
⟨⟨functor.star _, presheaf.is_sheaf_unit _⟩⟩

namespace sheaf

/--
The forgetful functor from sheaves to presheaves.
-/
@[derive [full, faithful]]
def forget : Top.sheaf C X ⥤ Top.presheaf C X :=
full_subcategory_inclusion presheaf.is_sheaf

@[simp] lemma id_app (F : sheaf C X) (t) : (𝟙 F : F ⟶ F).app t = 𝟙 _ := rfl
@[simp] lemma comp_app {F G H : sheaf C X} (f : F ⟶ G) (g : G ⟶ H) (t) :
  (f ≫ g).app t = f.app t ≫ g.app t := rfl

end sheaf

end Top


/-
Copyright (c) 2018 Chris Hughes. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Chris Hughes, Johannes Hölzl, Scott Morrison, Jens Wagemaker
-/
import data.polynomial.algebra_map
import data.polynomial.degree.lemmas
import data.polynomial.monic

/-!
# Theory of monic polynomials

We define `integral_normalization`, which relate arbitrary polynomials to monic ones.
-/

open_locale big_operators

namespace polynomial
universes u v y
variables {R : Type u} {S : Type v} {a b : R} {m n : ℕ} {ι : Type y}

section integral_normalization

section semiring
variables [semiring R]

/-- If `f : polynomial R` is a nonzero polynomial with root `z`, `integral_normalization f` is
a monic polynomial with root `leading_coeff f * z`.

Moreover, `integral_normalization 0 = 0`.
-/
noncomputable def integral_normalization (f : polynomial R) : polynomial R :=
∑ i in f.support, monomial i (if f.degree = i then 1 else
  coeff f i * f.leading_coeff ^ (f.nat_degree - 1 - i))

@[simp] lemma integral_normalization_zero :
  integral_normalization (0 : polynomial R) = 0 :=
by simp [integral_normalization]

lemma integral_normalization_coeff {f : polynomial R} {i : ℕ} :
  (integral_normalization f).coeff i =
    if f.degree = i then 1 else coeff f i * f.leading_coeff ^ (f.nat_degree - 1 - i) :=
have f.coeff i = 0 → f.degree ≠ i, from λ hc hd, coeff_ne_zero_of_eq_degree hd hc,
by simp [integral_normalization, coeff_monomial, this, mem_support_iff] {contextual := tt}

lemma integral_normalization_support {f : polynomial R} :
  (integral_normalization f).support ⊆ f.support :=
by { intro, simp [integral_normalization, coeff_monomial, mem_support_iff] {contextual := tt} }

lemma integral_normalization_coeff_degree {f : polynomial R} {i : ℕ} (hi : f.degree = i) :
  (integral_normalization f).coeff i = 1 :=
by rw [integral_normalization_coeff, if_pos hi]

lemma integral_normalization_coeff_nat_degree {f : polynomial R} (hf : f ≠ 0) :
  (integral_normalization f).coeff (nat_degree f) = 1 :=
integral_normalization_coeff_degree (degree_eq_nat_degree hf)

lemma integral_normalization_coeff_ne_degree {f : polynomial R} {i : ℕ} (hi : f.degree ≠ i) :
  coeff (integral_normalization f) i = coeff f i * f.leading_coeff ^ (f.nat_degree - 1 - i) :=
by rw [integral_normalization_coeff, if_neg hi]

lemma integral_normalization_coeff_ne_nat_degree
  {f : polynomial R} {i : ℕ} (hi : i ≠ nat_degree f) :
  coeff (integral_normalization f) i = coeff f i * f.leading_coeff ^ (f.nat_degree - 1 - i) :=
integral_normalization_coeff_ne_degree (degree_ne_of_nat_degree_ne hi.symm)

lemma monic_integral_normalization {f : polynomial R} (hf : f ≠ 0) :
  monic (integral_normalization f) :=
monic_of_degree_le f.nat_degree
  (finset.sup_le $ λ i h, with_bot.coe_le_coe.2 $
    le_nat_degree_of_mem_supp i $ integral_normalization_support h)
  (integral_normalization_coeff_nat_degree hf)

end semiring

section is_domain
variables [ring R] [is_domain R]

@[simp] lemma support_integral_normalization {f : polynomial R} :
  (integral_normalization f).support = f.support :=
begin
  by_cases hf : f = 0, { simp [hf] },
  ext i,
  refine ⟨λ h, integral_normalization_support h, _⟩,
  simp only [integral_normalization_coeff, mem_support_iff],
  intro hfi,
  split_ifs with hi; simp [hfi, hi, pow_ne_zero _ (leading_coeff_ne_zero.mpr hf)]
end
end is_domain

section is_domain
variables [comm_ring R] [is_domain R]
variables [comm_ring S]

lemma integral_normalization_eval₂_eq_zero {p : polynomial R} (f : R →+* S)
  {z : S} (hz : eval₂ f z p = 0) (inj : ∀ (x : R), f x = 0 → x = 0) :
  eval₂ f (z * f p.leading_coeff) (integral_normalization p) = 0 :=
calc eval₂ f (z * f p.leading_coeff) (integral_normalization p)
    = p.support.attach.sum
        (λ i, f (coeff (integral_normalization p) i.1 * p.leading_coeff ^ i.1) * z ^ i.1) :
      by { rw [eval₂, sum_def, support_integral_normalization],
           simp only [mul_comm z, mul_pow, mul_assoc, ring_hom.map_pow, ring_hom.map_mul],
           exact finset.sum_attach.symm }
... = p.support.attach.sum
        (λ i, f (coeff p i.1 * p.leading_coeff ^ (nat_degree p - 1)) * z ^ i.1) :
      begin
        by_cases hp : p = 0, { simp [hp] },
        have one_le_deg : 1 ≤ nat_degree p :=
          nat.succ_le_of_lt (nat_degree_pos_of_eval₂_root hp f hz inj),
        congr' with i,
        congr' 2,
        by_cases hi : i.1 = nat_degree p,
        { rw [hi, integral_normalization_coeff_degree, one_mul, leading_coeff, ←pow_succ,
              tsub_add_cancel_of_le one_le_deg],
          exact degree_eq_nat_degree hp },
        { have : i.1 ≤ p.nat_degree - 1 := nat.le_pred_of_lt (lt_of_le_of_ne
            (le_nat_degree_of_ne_zero (mem_support_iff.mp i.2)) hi),
          rw [integral_normalization_coeff_ne_nat_degree hi, mul_assoc, ←pow_add,
              tsub_add_cancel_of_le this] }
      end
... = f p.leading_coeff ^ (nat_degree p - 1) * eval₂ f z p :
      by { simp_rw [eval₂, sum_def, λ i, mul_comm (coeff p i), ring_hom.map_mul,
                    ring_hom.map_pow, mul_assoc, ←finset.mul_sum],
           congr' 1,
           exact @finset.sum_attach _ _ p.support _ (λ i, f (p.coeff i) * z ^ i) }
... = 0 : by rw [hz, _root_.mul_zero]

end is_domain

end integral_normalization

end polynomial


/-
Copyright (c) 2018 Johan Commelin All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johan Commelin, Chris Hughes, Kevin Buzzard
-/
import algebra.hom.group

/-!
# Lift monoid homomorphisms to group homomorphisms of their units subgroups.
-/

universes u v w

namespace units
variables {M : Type u} {N : Type v} {P : Type w} [monoid M] [monoid N] [monoid P]

/-- The group homomorphism on units induced by a `monoid_hom`. -/
@[to_additive "The `add_group` homomorphism on `add_unit`s induced by an `add_monoid_hom`."]
def map (f : M →* N) : Mˣ →* Nˣ :=
monoid_hom.mk'
  (λ u, ⟨f u.val, f u.inv,
                  by rw [← f.map_mul, u.val_inv, f.map_one],
                  by rw [← f.map_mul, u.inv_val, f.map_one]⟩)
  (λ x y, ext (f.map_mul x y))

@[simp, to_additive] lemma coe_map (f : M →* N) (x : Mˣ) : ↑(map f x) = f x := rfl

@[simp, to_additive] lemma coe_map_inv (f : M →* N) (u : Mˣ) :
  ↑(map f u)⁻¹ = f ↑u⁻¹ :=
rfl

@[simp, to_additive]
lemma map_comp (f : M →* N) (g : N →* P) : map (g.comp f) = (map g).comp (map f) := rfl

variables (M)
@[simp, to_additive] lemma map_id : map (monoid_hom.id M) = monoid_hom.id Mˣ :=
by ext; refl

/-- Coercion `Mˣ → M` as a monoid homomorphism. -/
@[to_additive "Coercion `add_units M → M` as an add_monoid homomorphism."]
def coe_hom : Mˣ →* M := ⟨coe, coe_one, coe_mul⟩

variable {M}

@[simp, to_additive] lemma coe_hom_apply (x : Mˣ) : coe_hom M x = ↑x := rfl

@[simp, norm_cast, to_additive]
lemma coe_pow (u : Mˣ) (n : ℕ) : ((u ^ n : Mˣ) : M) = u ^ n :=
(units.coe_hom M).map_pow u n

@[simp, norm_cast, to_additive]
lemma coe_zpow {G} [group G] (u : Gˣ) (n : ℤ) : ((u ^ n : Gˣ) : G) = u ^ n :=
(units.coe_hom G).map_zpow u n

/-- If a map `g : M → Nˣ` agrees with a homomorphism `f : M →* N`, then
this map is a monoid homomorphism too. -/
@[to_additive "If a map `g : M → add_units N` agrees with a homomorphism `f : M →+ N`, then this map
is an add_monoid homomorphism too."]
def lift_right (f : M →* N) (g : M → Nˣ) (h : ∀ x, ↑(g x) = f x) :
  M →* Nˣ :=
{ to_fun := g,
  map_one' := units.ext $ (h 1).symm ▸ f.map_one,
  map_mul' := λ x y, units.ext $ by simp only [h, coe_mul, f.map_mul] }

@[simp, to_additive] lemma coe_lift_right {f : M →* N} {g : M → Nˣ}
  (h : ∀ x, ↑(g x) = f x) (x) : (lift_right f g h x : N) = f x := h x

@[simp, to_additive] lemma mul_lift_right_inv {f : M →* N} {g : M → Nˣ}
  (h : ∀ x, ↑(g x) = f x) (x) : f x * ↑(lift_right f g h x)⁻¹ = 1 :=
by rw [units.mul_inv_eq_iff_eq_mul, one_mul, coe_lift_right]

@[simp, to_additive] lemma lift_right_inv_mul {f : M →* N} {g : M → Nˣ}
  (h : ∀ x, ↑(g x) = f x) (x) : ↑(lift_right f g h x)⁻¹ * f x = 1 :=
by rw [units.inv_mul_eq_iff_eq_mul, mul_one, coe_lift_right]

end units

namespace monoid_hom

/-- If `f` is a homomorphism from a group `G` to a monoid `M`,
then its image lies in the units of `M`,
and `f.to_hom_units` is the corresponding monoid homomorphism from `G` to `Mˣ`. -/
@[to_additive "If `f` is a homomorphism from an additive group `G` to an additive monoid `M`,
then its image lies in the `add_units` of `M`,
and `f.to_hom_units` is the corresponding homomorphism from `G` to `add_units M`."]
def to_hom_units {G M : Type*} [group G] [monoid M] (f : G →* M) : G →* Mˣ :=
{ to_fun := λ g,
    ⟨f g, f (g⁻¹),
      by rw [← f.map_mul, mul_inv_self, f.map_one],
      by rw [← f.map_mul, inv_mul_self, f.map_one]⟩,
  map_one' := units.ext (f.map_one),
  map_mul' := λ _ _, units.ext (f.map_mul _ _) }

@[simp] lemma coe_to_hom_units {G M : Type*} [group G] [monoid M] (f : G →* M) (g : G):
  (f.to_hom_units g : M) = f g := rfl

end monoid_hom

section is_unit
variables {M : Type*} {N : Type*}

@[to_additive] lemma is_unit.map {F : Type*} [monoid M] [monoid N] [monoid_hom_class F M N]
  (f : F) {x : M} (h : is_unit x) : is_unit (f x) :=
by rcases h with ⟨y, rfl⟩; exact (units.map (f : M →* N) y).is_unit

/-- If a homomorphism `f : M →* N` sends each element to an `is_unit`, then it can be lifted
to `f : M →* Nˣ`. See also `units.lift_right` for a computable version. -/
@[to_additive "If a homomorphism `f : M →+ N` sends each element to an `is_add_unit`, then it can be
lifted to `f : M →+ add_units N`. See also `add_units.lift_right` for a computable version."]
noncomputable def is_unit.lift_right [monoid M] [monoid N] (f : M →* N)
  (hf : ∀ x, is_unit (f x)) : M →* Nˣ :=
units.lift_right f (λ x, classical.some (hf x)) $ λ x, classical.some_spec (hf x)

@[to_additive] lemma is_unit.coe_lift_right [monoid M] [monoid N] (f : M →* N)
  (hf : ∀ x, is_unit (f x)) (x) :
  (is_unit.lift_right f hf x : N) = f x :=
units.coe_lift_right _ x

@[simp, to_additive] lemma is_unit.mul_lift_right_inv [monoid M] [monoid N] (f : M →* N)
  (h : ∀ x, is_unit (f x)) (x) : f x * ↑(is_unit.lift_right f h x)⁻¹ = 1 :=
units.mul_lift_right_inv (λ y, classical.some_spec $ h y) x

@[simp, to_additive] lemma is_unit.lift_right_inv_mul [monoid M] [monoid N] (f : M →* N)
  (h : ∀ x, is_unit (f x)) (x) : ↑(is_unit.lift_right f h x)⁻¹ * f x = 1 :=
units.lift_right_inv_mul (λ y, classical.some_spec $ h y) x

end is_unit


/-
Copyright (c) 2021 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johan Commelin
-/
import analysis.normed_space.basic

/-!
# The integers as normed ring

This file contains basic facts about the integers as normed ring.

Recall that `∥n∥` denotes the norm of `n` as real number.
This norm is always nonnegative, so we can bundle the norm together with this fact,
to obtain a term of type `nnreal` (the nonnegative real numbers).
The resulting nonnegative real number is denoted by `∥n∥₊`.
-/

open_locale big_operators

namespace int

lemma norm_coe_units (e : units ℤ) : ∥(e : ℤ)∥ = 1 :=
by rw [← coe_nnnorm, int.nnnorm_coe_units, nnreal.coe_one]

@[simp] lemma nnnorm_coe_nat (n : ℕ) : ∥(n : ℤ)∥₊ = n := real.nnnorm_coe_nat _

@[simp] lemma norm_coe_nat (n : ℕ) : ∥(n : ℤ)∥ = n := real.norm_coe_nat _

@[simp] lemma to_nat_add_to_nat_neg_eq_nnnorm (n : ℤ) : ↑(n.to_nat) + ↑((-n).to_nat) = ∥n∥₊ :=
by rw [← nat.cast_add, to_nat_add_to_nat_neg_eq_nat_abs, nnreal.coe_nat_abs]

@[simp] lemma to_nat_add_to_nat_neg_eq_norm (n : ℤ) : ↑(n.to_nat) + ↑((-n).to_nat) = ∥n∥ :=
by simpa only [nnreal.coe_nat_cast, nnreal.coe_add]
  using congr_arg (coe : _ → ℝ) (to_nat_add_to_nat_neg_eq_nnnorm n)

end int


/-
Copyright (c) 2016 Jeremy Avigad. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jeremy Avigad

The order relation on the integers.

! This file was ported from Lean 3 source module init.data.int.order
! leanprover-community/mathlib commit 4a03bdeb31b3688c31d02d7ff8e0ff2e5d6174db
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
prelude
import Leanbin.Init.Data.Int.Basic
import Leanbin.Init.Data.Ordering.Basic

namespace Int

#print Int.NonNeg /-
def NonNeg (a : ℤ) : Prop :=
  Int.casesOn a (fun n => True) fun n => False
#align int.nonneg Int.NonNeg
-/

#print Int.le /-
protected def le (a b : ℤ) : Prop :=
  NonNeg (b - a)
#align int.le Int.le
-/

instance : LE Int :=
  ⟨Int.le⟩

#print Int.lt /-
protected def lt (a b : ℤ) : Prop :=
  a + 1 ≤ b
#align int.lt Int.lt
-/

instance : LT Int :=
  ⟨Int.lt⟩

#print Int.decNonneg /-
def decNonneg (a : ℤ) : Decidable (NonNeg a) :=
  Int.casesOn a (fun a => Decidable.true) fun a => Decidable.false
#align int.decidable_nonneg Int.decNonneg
-/

#print Int.decLe /-
instance decLe (a b : ℤ) : Decidable (a ≤ b) :=
  decNonneg _
#align int.decidable_le Int.decLe
-/

#print Int.decLt /-
instance decLt (a b : ℤ) : Decidable (a < b) :=
  decNonneg _
#align int.decidable_lt Int.decLt
-/

#print Int.lt_iff_add_one_le /-
theorem lt_iff_add_one_le (a b : ℤ) : a < b ↔ a + 1 ≤ b :=
  Iff.refl _
#align int.lt_iff_add_one_le Int.lt_iff_add_one_le
-/

#print Int.NonNeg.elim /-
theorem NonNeg.elim {a : ℤ} : NonNeg a → ∃ n : ℕ, a = n :=
  Int.casesOn a (fun n H => Exists.intro n rfl) fun n' => False.elim
#align int.nonneg.elim Int.NonNeg.elim
-/

theorem nonNeg_or_nonNeg_neg (a : ℤ) : NonNeg a ∨ NonNeg (-a) :=
  Int.casesOn a (fun n => Or.inl trivial) fun n => Or.inr trivial
#align int.nonneg_or_nonneg_neg Int.nonNeg_or_nonNeg_neg

#print Int.le.intro_sub /-
theorem le.intro_sub {a b : ℤ} {n : ℕ} (h : b - a = n) : a ≤ b :=
  show NonNeg (b - a) by rw [h] <;> trivial
#align int.le.intro_sub Int.le.intro_sub
-/

attribute [local simp]
  Int.sub_eq_add_neg Int.add_assoc Int.add_right_neg Int.add_left_neg Int.zero_add Int.add_zero Int.neg_add Int.neg_neg Int.neg_zero

#print Int.le.intro /-
theorem le.intro {a b : ℤ} {n : ℕ} (h : a + n = b) : a ≤ b :=
  le.intro_sub (by rw [← h, Int.add_comm] <;> simp)
#align int.le.intro Int.le.intro
-/

#print Int.le.dest_sub /-
theorem le.dest_sub {a b : ℤ} (h : a ≤ b) : ∃ n : ℕ, b - a = n :=
  NonNeg.elim h
#align int.le.dest_sub Int.le.dest_sub
-/

#print Int.le.dest /-
theorem le.dest {a b : ℤ} (h : a ≤ b) : ∃ n : ℕ, a + n = b :=
  match le.dest_sub h with
  | ⟨n, h₁⟩ => Exists.intro n (by rw [← h₁, Int.add_comm]; simp)
#align int.le.dest Int.le.dest
-/

#print Int.le.elim /-
theorem le.elim {a b : ℤ} (h : a ≤ b) {P : Prop} (h' : ∀ n : ℕ, a + ↑n = b → P) : P :=
  Exists.elim (le.dest h) h'
#align int.le.elim Int.le.elim
-/

#print Int.le_total /-
protected theorem le_total (a b : ℤ) : a ≤ b ∨ b ≤ a :=
  Or.imp_right
    (fun H : NonNeg (-(b - a)) =>
      have : -(b - a) = a - b := by simp [Int.add_comm]
      show NonNeg (a - b) from this ▸ H)
    (nonNeg_or_nonNeg_neg (b - a))
#align int.le_total Int.le_total
-/

#print Int.ofNat_le_ofNat_of_le /-
theorem ofNat_le_ofNat_of_le {m n : ℕ} (h : m ≤ n) : (↑m : ℤ) ≤ ↑n :=
  match Nat.le.dest h with
  | ⟨k, (hk : m + k = n)⟩ => le.intro (by rw [← hk]; rfl)
#align int.coe_nat_le_coe_nat_of_le Int.ofNat_le_ofNat_of_le
-/

#print Int.le_of_ofNat_le_ofNat /-
theorem le_of_ofNat_le_ofNat {m n : ℕ} (h : (↑m : ℤ) ≤ ↑n) : m ≤ n :=
  le.elim h fun k => fun hk : ↑m + ↑k = ↑n =>
    have : m + k = n := Int.ofNat.inj ((Int.ofNat_add m k).trans hk)
    Nat.le.intro this
#align int.le_of_coe_nat_le_coe_nat Int.le_of_ofNat_le_ofNat
-/

#print Int.ofNat_le /-
theorem ofNat_le (m n : ℕ) : (↑m : ℤ) ≤ ↑n ↔ m ≤ n :=
  Iff.intro le_of_ofNat_le_ofNat ofNat_le_ofNat_of_le
#align int.coe_nat_le_coe_nat_iff Int.ofNat_le
-/

#print Int.ofNat_zero_le /-
theorem ofNat_zero_le (n : ℕ) : 0 ≤ (↑n : ℤ) :=
  ofNat_le_ofNat_of_le n.zero_le
#align int.coe_zero_le Int.ofNat_zero_le
-/

#print Int.eq_ofNat_of_zero_le /-
theorem eq_ofNat_of_zero_le {a : ℤ} (h : 0 ≤ a) : ∃ n : ℕ, a = n :=
  by
  have t := le.dest_sub h
  simp at t
  exact t
#align int.eq_coe_of_zero_le Int.eq_ofNat_of_zero_le
-/

#print Int.eq_succ_of_zero_lt /-
theorem eq_succ_of_zero_lt {a : ℤ} (h : 0 < a) : ∃ n : ℕ, a = n.succ :=
  let ⟨n, (h : ↑(1 + n) = a)⟩ := le.dest h
  ⟨n, by rw [Nat.add_comm] at h <;> exact h.symm⟩
#align int.eq_succ_of_zero_lt Int.eq_succ_of_zero_lt
-/

#print Int.lt_add_succ /-
theorem lt_add_succ (a : ℤ) (n : ℕ) : a < a + ↑(Nat.succ n) :=
  le.intro
    (show a + 1 + n = a + Nat.succ n
      by
      simp [Int.coe_nat_eq, Int.add_comm, Int.add_left_comm]
      rfl)
#align int.lt_add_succ Int.lt_add_succ
-/

#print Int.lt.intro /-
theorem lt.intro {a b : ℤ} {n : ℕ} (h : a + Nat.succ n = b) : a < b :=
  h ▸ lt_add_succ a n
#align int.lt.intro Int.lt.intro
-/

#print Int.lt.dest /-
theorem lt.dest {a b : ℤ} (h : a < b) : ∃ n : ℕ, a + ↑(Nat.succ n) = b :=
  le.elim h fun n => fun hn : a + 1 + n = b =>
    Exists.intro n (by rw [← hn, Int.add_assoc, Int.add_comm 1]; rfl)
#align int.lt.dest Int.lt.dest
-/

#print Int.lt.elim /-
theorem lt.elim {a b : ℤ} (h : a < b) {P : Prop} (h' : ∀ n : ℕ, a + ↑(Nat.succ n) = b → P) : P :=
  Exists.elim (lt.dest h) h'
#align int.lt.elim Int.lt.elim
-/

#print Int.ofNat_lt /-
theorem ofNat_lt (n m : ℕ) : (↑n : ℤ) < ↑m ↔ n < m := by
  rw [lt_iff_add_one_le, ← Int.ofNat_succ, coe_nat_le_coe_nat_iff]; rfl
#align int.coe_nat_lt_coe_nat_iff Int.ofNat_lt
-/

#print Int.lt_of_ofNat_lt_ofNat /-
theorem lt_of_ofNat_lt_ofNat {m n : ℕ} (h : (↑m : ℤ) < ↑n) : m < n :=
  (ofNat_lt _ _).mp h
#align int.lt_of_coe_nat_lt_coe_nat Int.lt_of_ofNat_lt_ofNat
-/

#print Int.ofNat_lt_ofNat_of_lt /-
theorem ofNat_lt_ofNat_of_lt {m n : ℕ} (h : m < n) : (↑m : ℤ) < ↑n :=
  (ofNat_lt _ _).mpr h
#align int.coe_nat_lt_coe_nat_of_lt Int.ofNat_lt_ofNat_of_lt
-/

/-! show that the integers form an ordered additive group -/

#print Int.le_refl /-
protected theorem le_refl (a : ℤ) : a ≤ a :=
  le.intro (Int.add_zero a)
#align int.le_refl Int.le_refl
-/

#print Int.le_trans /-
protected theorem le_trans {a b c : ℤ} (h₁ : a ≤ b) (h₂ : b ≤ c) : a ≤ c :=
  le.elim h₁ fun n => fun hn : a + n = b =>
    le.elim h₂ fun m => fun hm : b + m = c => by apply le.intro; rw [← hm, ← hn, Int.add_assoc]; rfl
#align int.le_trans Int.le_trans
-/

#print Int.le_antisymm /-
protected theorem le_antisymm {a b : ℤ} (h₁ : a ≤ b) (h₂ : b ≤ a) : a = b :=
  le.elim h₁ fun n => fun hn : a + n = b =>
    le.elim h₂ fun m => fun hm : b + m = a =>
      have : a + ↑(n + m) = a + 0 := by rw [Int.ofNat_add, ← Int.add_assoc, hn, hm, Int.add_zero a]
      have : (↑(n + m) : ℤ) = 0 := Int.add_left_cancel this
      have : n + m = 0 := Int.ofNat.inj this
      have : n = 0 := Nat.eq_zero_of_add_eq_zero_right this
      show a = b by rw [← hn, this, Int.ofNat_zero, Int.add_zero a]
#align int.le_antisymm Int.le_antisymm
-/

#print Int.lt_irrefl /-
protected theorem lt_irrefl (a : ℤ) : ¬a < a := fun this : a < a =>
  lt.elim this fun n => fun hn : a + Nat.succ n = a =>
    have : a + Nat.succ n = a + 0 := by rw [hn, Int.add_zero]
    have : Nat.succ n = 0 := Int.ofNat.inj (Int.add_left_cancel this)
    show False from Nat.succ_ne_zero _ this
#align int.lt_irrefl Int.lt_irrefl
-/

#print Int.ne_of_lt /-
protected theorem ne_of_lt {a b : ℤ} (h : a < b) : a ≠ b := fun this : a = b =>
  absurd (by rw [this] at h; exact h) (Int.lt_irrefl b)
#align int.ne_of_lt Int.ne_of_lt
-/

#print Int.le_of_lt /-
theorem le_of_lt {a b : ℤ} (h : a < b) : a ≤ b :=
  lt.elim h fun n => fun hn : a + Nat.succ n = b => le.intro hn
#align int.le_of_lt Int.le_of_lt
-/

#print Int.lt_iff_le_and_ne /-
protected theorem lt_iff_le_and_ne (a b : ℤ) : a < b ↔ a ≤ b ∧ a ≠ b :=
  Iff.intro (fun h => ⟨le_of_lt h, Int.ne_of_lt h⟩) fun ⟨aleb, aneb⟩ =>
    le.elim aleb fun n => fun hn : a + n = b =>
      have : n ≠ 0 := fun this : n = 0 => aneb (by rw [← hn, this, Int.ofNat_zero, Int.add_zero])
      have : n = Nat.succ (Nat.pred n) :=
        Eq.symm (Nat.succ_pred_eq_of_pos (Nat.pos_of_ne_zero this))
      lt.intro (by rw [this] at hn; exact hn)
#align int.lt_iff_le_and_ne Int.lt_iff_le_and_ne
-/

#print Int.lt_succ /-
theorem lt_succ (a : ℤ) : a < a + 1 :=
  Int.le_refl (a + 1)
#align int.lt_succ Int.lt_succ
-/

#print Int.add_le_add_left /-
protected theorem add_le_add_left {a b : ℤ} (h : a ≤ b) (c : ℤ) : c + a ≤ c + b :=
  le.elim h fun n => fun hn : a + n = b =>
    le.intro (show c + a + n = c + b by rw [Int.add_assoc, hn])
#align int.add_le_add_left Int.add_le_add_left
-/

#print Int.add_lt_add_left /-
protected theorem add_lt_add_left {a b : ℤ} (h : a < b) (c : ℤ) : c + a < c + b :=
  Iff.mpr (Int.lt_iff_le_and_ne _ _)
    (And.intro (Int.add_le_add_left (le_of_lt h) _) fun heq =>
      Int.lt_irrefl b (by rw [Int.add_left_cancel HEq] at h; exact h))
#align int.add_lt_add_left Int.add_lt_add_left
-/

#print Int.mul_nonneg /-
protected theorem mul_nonneg {a b : ℤ} (ha : 0 ≤ a) (hb : 0 ≤ b) : 0 ≤ a * b :=
  le.elim ha fun n => fun hn =>
    le.elim hb fun m => fun hm =>
      le.intro (show 0 + ↑n * ↑m = a * b by rw [← hn, ← hm]; simp [Int.zero_add])
#align int.mul_nonneg Int.mul_nonneg
-/

#print Int.mul_pos /-
protected theorem mul_pos {a b : ℤ} (ha : 0 < a) (hb : 0 < b) : 0 < a * b :=
  lt.elim ha fun n => fun hn =>
    lt.elim hb fun m => fun hm =>
      lt.intro
        (show 0 + ↑(Nat.succ (Nat.succ n * m + n)) = a * b
          by
          rw [← hn, ← hm]; simp [Int.ofNat_zero]
          rw [← Int.ofNat_mul]; simp [Nat.mul_succ, Nat.add_succ, Nat.succ_add])
#align int.mul_pos Int.mul_pos
-/

#print Int.zero_lt_one /-
protected theorem zero_lt_one : (0 : ℤ) < 1 :=
  trivial
#align int.zero_lt_one Int.zero_lt_one
-/

#print Int.lt_iff_le_not_le /-
protected theorem lt_iff_le_not_le {a b : ℤ} : a < b ↔ a ≤ b ∧ ¬b ≤ a :=
  by
  simp [Int.lt_iff_le_and_ne]; constructor <;> intro h
  · cases' h with hab hn
    constructor
    · assumption
    · intro hba
      simp [Int.le_antisymm hab hba] at *
      contradiction
  · cases' h with hab hn
    constructor
    · assumption
    · intro h
      simp_all
#align int.lt_iff_le_not_le Int.lt_iff_le_not_le
-/

instance : LinearOrder Int where
  le := Int.le
  le_refl := Int.le_refl
  le_trans := @Int.le_trans
  le_antisymm := @Int.le_antisymm
  lt := Int.lt
  lt_iff_le_not_le := @Int.lt_iff_le_not_le
  le_total := Int.le_total
  DecidableEq := Int.decidableEq
  decidableLe := Int.decLe
  decidableLt := Int.decLt

#print Int.eq_natAbs_of_zero_le /-
theorem eq_natAbs_of_zero_le {a : ℤ} (h : 0 ≤ a) : a = natAbs a :=
  by
  let ⟨n, e⟩ := eq_ofNat_of_zero_le h
  rw [e] <;> rfl
#align int.eq_nat_abs_of_zero_le Int.eq_natAbs_of_zero_le
-/

#print Int.le_natAbs /-
theorem le_natAbs {a : ℤ} : a ≤ natAbs a :=
  Or.elim (le_total 0 a) (fun h => by rw [eq_nat_abs_of_zero_le h] <;> rfl) fun h =>
    le_trans h (ofNat_zero_le _)
#align int.le_nat_abs Int.le_natAbs
-/

#print Int.negSucc_lt_zero /-
theorem negSucc_lt_zero (n : ℕ) : -[n+1] < 0 :=
  lt_of_not_ge fun h => by
    let ⟨m, h⟩ := eq_ofNat_of_zero_le h
    contradiction
#align int.neg_succ_lt_zero Int.negSucc_lt_zero
-/

#print Int.eq_negSucc_of_lt_zero /-
theorem eq_negSucc_of_lt_zero : ∀ {a : ℤ}, a < 0 → ∃ n : ℕ, a = -[n+1]
  | (n : ℕ), h => absurd h (not_lt_of_ge (ofNat_zero_le _))
  | -[n+1], h => ⟨n, rfl⟩
#align int.eq_neg_succ_of_lt_zero Int.eq_negSucc_of_lt_zero
-/

/-! int is an ordered add comm group -/

#print Int.eq_neg_of_eq_neg /-
protected theorem eq_neg_of_eq_neg {a b : ℤ} (h : a = -b) : b = -a := by rw [h, Int.neg_neg]
#align int.eq_neg_of_eq_neg Int.eq_neg_of_eq_neg
-/

#print Int.neg_add_cancel_left /-
protected theorem neg_add_cancel_left (a b : ℤ) : -a + (a + b) = b := by
  rw [← Int.add_assoc, Int.add_left_neg, Int.zero_add]
#align int.neg_add_cancel_left Int.neg_add_cancel_left
-/

#print Int.add_neg_cancel_left /-
protected theorem add_neg_cancel_left (a b : ℤ) : a + (-a + b) = b := by
  rw [← Int.add_assoc, Int.add_right_neg, Int.zero_add]
#align int.add_neg_cancel_left Int.add_neg_cancel_left
-/

#print Int.add_neg_cancel_right /-
protected theorem add_neg_cancel_right (a b : ℤ) : a + b + -b = a := by
  rw [Int.add_assoc, Int.add_right_neg, Int.add_zero]
#align int.add_neg_cancel_right Int.add_neg_cancel_right
-/

#print Int.neg_add_cancel_right /-
protected theorem neg_add_cancel_right (a b : ℤ) : a + -b + b = a := by
  rw [Int.add_assoc, Int.add_left_neg, Int.add_zero]
#align int.neg_add_cancel_right Int.neg_add_cancel_right
-/

#print Int.sub_self /-
protected theorem sub_self (a : ℤ) : a - a = 0 := by rw [Int.sub_eq_add_neg, Int.add_right_neg]
#align int.sub_self Int.sub_self
-/

#print Int.sub_eq_zero_of_eq /-
protected theorem sub_eq_zero_of_eq {a b : ℤ} (h : a = b) : a - b = 0 := by rw [h, Int.sub_self]
#align int.sub_eq_zero_of_eq Int.sub_eq_zero_of_eq
-/

#print Int.eq_of_sub_eq_zero /-
protected theorem eq_of_sub_eq_zero {a b : ℤ} (h : a - b = 0) : a = b :=
  by
  have : 0 + b = b := by rw [Int.zero_add]
  have : a - b + b = b := by rwa [h]
  rwa [Int.sub_eq_add_neg, Int.neg_add_cancel_right] at this
#align int.eq_of_sub_eq_zero Int.eq_of_sub_eq_zero
-/

#print Int.sub_eq_zero /-
protected theorem sub_eq_zero {a b : ℤ} : a - b = 0 ↔ a = b :=
  ⟨Int.eq_of_sub_eq_zero, Int.sub_eq_zero_of_eq⟩
#align int.sub_eq_zero_iff_eq Int.sub_eq_zero
-/

#print Int.neg_eq_of_add_eq_zero /-
@[simp]
protected theorem neg_eq_of_add_eq_zero {a b : ℤ} (h : a + b = 0) : -a = b := by
  rw [← Int.add_zero (-a), ← h, ← Int.add_assoc, Int.add_left_neg, Int.zero_add]
#align int.neg_eq_of_add_eq_zero Int.neg_eq_of_add_eq_zero
-/

#print Int.neg_mul_eq_neg_mul /-
protected theorem neg_mul_eq_neg_mul (a b : ℤ) : -(a * b) = -a * b :=
  Int.neg_eq_of_add_eq_zero (by rw [← Int.add_mul, Int.add_right_neg, Int.zero_mul])
#align int.neg_mul_eq_neg_mul Int.neg_mul_eq_neg_mul
-/

#print Int.neg_mul_eq_mul_neg /-
protected theorem neg_mul_eq_mul_neg (a b : ℤ) : -(a * b) = a * -b :=
  Int.neg_eq_of_add_eq_zero (by rw [← Int.mul_add, Int.add_right_neg, Int.mul_zero])
#align int.neg_mul_eq_mul_neg Int.neg_mul_eq_mul_neg
-/

#print Int.neg_mul_eq_neg_mul_symm /-
theorem neg_mul_eq_neg_mul_symm (a b : ℤ) : -a * b = -(a * b) :=
  Eq.symm (Int.neg_mul_eq_neg_mul a b)
#align int.neg_mul_eq_neg_mul_symm Int.neg_mul_eq_neg_mul_symm
-/

#print Int.mul_neg_eq_neg_mul_symm /-
theorem mul_neg_eq_neg_mul_symm (a b : ℤ) : a * -b = -(a * b) :=
  Eq.symm (Int.neg_mul_eq_mul_neg a b)
#align int.mul_neg_eq_neg_mul_symm Int.mul_neg_eq_neg_mul_symm
-/

attribute [local simp] neg_mul_eq_neg_mul_symm mul_neg_eq_neg_mul_symm

#print Int.neg_mul_neg /-
protected theorem neg_mul_neg (a b : ℤ) : -a * -b = a * b := by simp
#align int.neg_mul_neg Int.neg_mul_neg
-/

#print Int.neg_mul_comm /-
protected theorem neg_mul_comm (a b : ℤ) : -a * b = a * -b := by simp
#align int.neg_mul_comm Int.neg_mul_comm
-/

#print Int.mul_sub /-
protected theorem mul_sub (a b c : ℤ) : a * (b - c) = a * b - a * c :=
  calc
    a * (b - c) = a * b + a * -c := Int.mul_add a b (-c)
    _ = a * b - a * c := by simp

#align int.mul_sub Int.mul_sub
-/

#print Int.sub_mul /-
protected theorem sub_mul (a b c : ℤ) : (a - b) * c = a * c - b * c :=
  calc
    (a - b) * c = a * c + -b * c := Int.add_mul a (-b) c
    _ = a * c - b * c := by simp

#align int.sub_mul Int.sub_mul
-/

section

#print Int.le_of_add_le_add_left /-
protected theorem le_of_add_le_add_left {a b c : ℤ} (h : a + b ≤ a + c) : b ≤ c :=
  by
  have : -a + (a + b) ≤ -a + (a + c) := Int.add_le_add_left h _
  simp [Int.neg_add_cancel_left] at this
  assumption
#align int.le_of_add_le_add_left Int.le_of_add_le_add_left
-/

#print Int.lt_of_add_lt_add_left /-
protected theorem lt_of_add_lt_add_left {a b c : ℤ} (h : a + b < a + c) : b < c :=
  by
  have : -a + (a + b) < -a + (a + c) := Int.add_lt_add_left h _
  simp [Int.neg_add_cancel_left] at this
  assumption
#align int.lt_of_add_lt_add_left Int.lt_of_add_lt_add_left
-/

#print Int.add_le_add_right /-
protected theorem add_le_add_right {a b : ℤ} (h : a ≤ b) (c : ℤ) : a + c ≤ b + c :=
  Int.add_comm c a ▸ Int.add_comm c b ▸ Int.add_le_add_left h c
#align int.add_le_add_right Int.add_le_add_right
-/

#print Int.add_lt_add_right /-
protected theorem add_lt_add_right {a b : ℤ} (h : a < b) (c : ℤ) : a + c < b + c :=
  by
  rw [Int.add_comm a c, Int.add_comm b c]
  exact Int.add_lt_add_left h c
#align int.add_lt_add_right Int.add_lt_add_right
-/

#print Int.add_le_add /-
protected theorem add_le_add {a b c d : ℤ} (h₁ : a ≤ b) (h₂ : c ≤ d) : a + c ≤ b + d :=
  le_trans (Int.add_le_add_right h₁ c) (Int.add_le_add_left h₂ b)
#align int.add_le_add Int.add_le_add
-/

#print Int.le_add_of_nonneg_right /-
protected theorem le_add_of_nonneg_right {a b : ℤ} (h : 0 ≤ b) : a ≤ a + b :=
  by
  have : a + b ≥ a + 0 := Int.add_le_add_left h a
  rwa [Int.add_zero] at this
#align int.le_add_of_nonneg_right Int.le_add_of_nonneg_right
-/

#print Int.le_add_of_nonneg_left /-
protected theorem le_add_of_nonneg_left {a b : ℤ} (h : 0 ≤ b) : a ≤ b + a :=
  by
  have : 0 + a ≤ b + a := Int.add_le_add_right h a
  rwa [Int.zero_add] at this
#align int.le_add_of_nonneg_left Int.le_add_of_nonneg_left
-/

#print Int.add_lt_add /-
protected theorem add_lt_add {a b c d : ℤ} (h₁ : a < b) (h₂ : c < d) : a + c < b + d :=
  lt_trans (Int.add_lt_add_right h₁ c) (Int.add_lt_add_left h₂ b)
#align int.add_lt_add Int.add_lt_add
-/

#print Int.add_lt_add_of_le_of_lt /-
protected theorem add_lt_add_of_le_of_lt {a b c d : ℤ} (h₁ : a ≤ b) (h₂ : c < d) : a + c < b + d :=
  lt_of_le_of_lt (Int.add_le_add_right h₁ c) (Int.add_lt_add_left h₂ b)
#align int.add_lt_add_of_le_of_lt Int.add_lt_add_of_le_of_lt
-/

#print Int.add_lt_add_of_lt_of_le /-
protected theorem add_lt_add_of_lt_of_le {a b c d : ℤ} (h₁ : a < b) (h₂ : c ≤ d) : a + c < b + d :=
  lt_of_lt_of_le (Int.add_lt_add_right h₁ c) (Int.add_le_add_left h₂ b)
#align int.add_lt_add_of_lt_of_le Int.add_lt_add_of_lt_of_le
-/

#print Int.lt_add_of_pos_right /-
protected theorem lt_add_of_pos_right (a : ℤ) {b : ℤ} (h : 0 < b) : a < a + b :=
  by
  have : a + 0 < a + b := Int.add_lt_add_left h a
  rwa [Int.add_zero] at this
#align int.lt_add_of_pos_right Int.lt_add_of_pos_right
-/

#print Int.lt_add_of_pos_left /-
protected theorem lt_add_of_pos_left (a : ℤ) {b : ℤ} (h : 0 < b) : a < b + a :=
  by
  have : 0 + a < b + a := Int.add_lt_add_right h a
  rwa [Int.zero_add] at this
#align int.lt_add_of_pos_left Int.lt_add_of_pos_left
-/

#print Int.le_of_add_le_add_right /-
protected theorem le_of_add_le_add_right {a b c : ℤ} (h : a + b ≤ c + b) : a ≤ c :=
  Int.le_of_add_le_add_left
    (show b + a ≤ b + c by rw [Int.add_comm b a, Int.add_comm b c]; assumption)
#align int.le_of_add_le_add_right Int.le_of_add_le_add_right
-/

#print Int.lt_of_add_lt_add_right /-
protected theorem lt_of_add_lt_add_right {a b c : ℤ} (h : a + b < c + b) : a < c :=
  Int.lt_of_add_lt_add_left
    (show b + a < b + c by rw [Int.add_comm b a, Int.add_comm b c]; assumption)
#align int.lt_of_add_lt_add_right Int.lt_of_add_lt_add_right
-/

#print Int.add_nonneg /-
-- here we start using properties of zero.
protected theorem add_nonneg {a b : ℤ} (ha : 0 ≤ a) (hb : 0 ≤ b) : 0 ≤ a + b :=
  Int.zero_add (0 : ℤ) ▸ Int.add_le_add ha hb
#align int.add_nonneg Int.add_nonneg
-/

#print Int.add_pos /-
protected theorem add_pos {a b : ℤ} (ha : 0 < a) (hb : 0 < b) : 0 < a + b :=
  Int.zero_add (0 : ℤ) ▸ Int.add_lt_add ha hb
#align int.add_pos Int.add_pos
-/

#print Int.add_pos_of_pos_of_nonneg /-
protected theorem add_pos_of_pos_of_nonneg {a b : ℤ} (ha : 0 < a) (hb : 0 ≤ b) : 0 < a + b :=
  Int.zero_add (0 : ℤ) ▸ Int.add_lt_add_of_lt_of_le ha hb
#align int.add_pos_of_pos_of_nonneg Int.add_pos_of_pos_of_nonneg
-/

#print Int.add_pos_of_nonneg_of_pos /-
protected theorem add_pos_of_nonneg_of_pos {a b : ℤ} (ha : 0 ≤ a) (hb : 0 < b) : 0 < a + b :=
  Int.zero_add (0 : ℤ) ▸ Int.add_lt_add_of_le_of_lt ha hb
#align int.add_pos_of_nonneg_of_pos Int.add_pos_of_nonneg_of_pos
-/

#print Int.add_nonpos /-
protected theorem add_nonpos {a b : ℤ} (ha : a ≤ 0) (hb : b ≤ 0) : a + b ≤ 0 :=
  Int.zero_add (0 : ℤ) ▸ Int.add_le_add ha hb
#align int.add_nonpos Int.add_nonpos
-/

#print Int.add_neg /-
protected theorem add_neg {a b : ℤ} (ha : a < 0) (hb : b < 0) : a + b < 0 :=
  Int.zero_add (0 : ℤ) ▸ Int.add_lt_add ha hb
#align int.add_neg Int.add_neg
-/

#print Int.add_neg_of_neg_of_nonpos /-
protected theorem add_neg_of_neg_of_nonpos {a b : ℤ} (ha : a < 0) (hb : b ≤ 0) : a + b < 0 :=
  Int.zero_add (0 : ℤ) ▸ Int.add_lt_add_of_lt_of_le ha hb
#align int.add_neg_of_neg_of_nonpos Int.add_neg_of_neg_of_nonpos
-/

#print Int.add_neg_of_nonpos_of_neg /-
protected theorem add_neg_of_nonpos_of_neg {a b : ℤ} (ha : a ≤ 0) (hb : b < 0) : a + b < 0 :=
  Int.zero_add (0 : ℤ) ▸ Int.add_lt_add_of_le_of_lt ha hb
#align int.add_neg_of_nonpos_of_neg Int.add_neg_of_nonpos_of_neg
-/

#print Int.lt_add_of_le_of_pos /-
protected theorem lt_add_of_le_of_pos {a b c : ℤ} (hbc : b ≤ c) (ha : 0 < a) : b < c + a :=
  Int.add_zero b ▸ Int.add_lt_add_of_le_of_lt hbc ha
#align int.lt_add_of_le_of_pos Int.lt_add_of_le_of_pos
-/

#print Int.sub_add_cancel /-
protected theorem sub_add_cancel (a b : ℤ) : a - b + b = a :=
  Int.neg_add_cancel_right a b
#align int.sub_add_cancel Int.sub_add_cancel
-/

#print Int.add_sub_cancel /-
protected theorem add_sub_cancel (a b : ℤ) : a + b - b = a :=
  Int.add_neg_cancel_right a b
#align int.add_sub_cancel Int.add_sub_cancel
-/

#print Int.add_sub_assoc /-
protected theorem add_sub_assoc (a b c : ℤ) : a + b - c = a + (b - c) := by
  rw [Int.sub_eq_add_neg, Int.add_assoc, ← Int.sub_eq_add_neg]
#align int.add_sub_assoc Int.add_sub_assoc
-/

#print Int.neg_le_neg /-
protected theorem neg_le_neg {a b : ℤ} (h : a ≤ b) : -b ≤ -a :=
  by
  have : 0 ≤ -a + b := Int.add_left_neg a ▸ Int.add_le_add_left h (-a)
  have : 0 + -b ≤ -a + b + -b := Int.add_le_add_right this (-b)
  rwa [Int.add_neg_cancel_right, Int.zero_add] at this
#align int.neg_le_neg Int.neg_le_neg
-/

#print Int.le_of_neg_le_neg /-
protected theorem le_of_neg_le_neg {a b : ℤ} (h : -b ≤ -a) : a ≤ b :=
  suffices - -a ≤ - -b by simp [Int.neg_neg] at this; assumption
  Int.neg_le_neg h
#align int.le_of_neg_le_neg Int.le_of_neg_le_neg
-/

#print Int.nonneg_of_neg_nonpos /-
protected theorem nonneg_of_neg_nonpos {a : ℤ} (h : -a ≤ 0) : 0 ≤ a :=
  have : -a ≤ -0 := by rwa [Int.neg_zero]
  Int.le_of_neg_le_neg this
#align int.nonneg_of_neg_nonpos Int.nonneg_of_neg_nonpos
-/

#print Int.neg_nonpos_of_nonneg /-
protected theorem neg_nonpos_of_nonneg {a : ℤ} (h : 0 ≤ a) : -a ≤ 0 :=
  by
  have : -a ≤ -0 := Int.neg_le_neg h
  rwa [Int.neg_zero] at this
#align int.neg_nonpos_of_nonneg Int.neg_nonpos_of_nonneg
-/

#print Int.nonpos_of_neg_nonneg /-
protected theorem nonpos_of_neg_nonneg {a : ℤ} (h : 0 ≤ -a) : a ≤ 0 :=
  have : -0 ≤ -a := by rwa [Int.neg_zero]
  Int.le_of_neg_le_neg this
#align int.nonpos_of_neg_nonneg Int.nonpos_of_neg_nonneg
-/

#print Int.neg_nonneg_of_nonpos /-
protected theorem neg_nonneg_of_nonpos {a : ℤ} (h : a ≤ 0) : 0 ≤ -a :=
  by
  have : -0 ≤ -a := Int.neg_le_neg h
  rwa [Int.neg_zero] at this
#align int.neg_nonneg_of_nonpos Int.neg_nonneg_of_nonpos
-/

#print Int.neg_lt_neg /-
protected theorem neg_lt_neg {a b : ℤ} (h : a < b) : -b < -a :=
  by
  have : 0 < -a + b := Int.add_left_neg a ▸ Int.add_lt_add_left h (-a)
  have : 0 + -b < -a + b + -b := Int.add_lt_add_right this (-b)
  rwa [Int.add_neg_cancel_right, Int.zero_add] at this
#align int.neg_lt_neg Int.neg_lt_neg
-/

#print Int.lt_of_neg_lt_neg /-
protected theorem lt_of_neg_lt_neg {a b : ℤ} (h : -b < -a) : a < b :=
  Int.neg_neg a ▸ Int.neg_neg b ▸ Int.neg_lt_neg h
#align int.lt_of_neg_lt_neg Int.lt_of_neg_lt_neg
-/

#print Int.pos_of_neg_neg /-
protected theorem pos_of_neg_neg {a : ℤ} (h : -a < 0) : 0 < a :=
  have : -a < -0 := by rwa [Int.neg_zero]
  Int.lt_of_neg_lt_neg this
#align int.pos_of_neg_neg Int.pos_of_neg_neg
-/

#print Int.neg_neg_of_pos /-
protected theorem neg_neg_of_pos {a : ℤ} (h : 0 < a) : -a < 0 :=
  by
  have : -a < -0 := Int.neg_lt_neg h
  rwa [Int.neg_zero] at this
#align int.neg_neg_of_pos Int.neg_neg_of_pos
-/

#print Int.neg_of_neg_pos /-
protected theorem neg_of_neg_pos {a : ℤ} (h : 0 < -a) : a < 0 :=
  have : -0 < -a := by rwa [Int.neg_zero]
  Int.lt_of_neg_lt_neg this
#align int.neg_of_neg_pos Int.neg_of_neg_pos
-/

#print Int.neg_pos_of_neg /-
protected theorem neg_pos_of_neg {a : ℤ} (h : a < 0) : 0 < -a :=
  by
  have : -0 < -a := Int.neg_lt_neg h
  rwa [Int.neg_zero] at this
#align int.neg_pos_of_neg Int.neg_pos_of_neg
-/

#print Int.le_neg_of_le_neg /-
protected theorem le_neg_of_le_neg {a b : ℤ} (h : a ≤ -b) : b ≤ -a :=
  by
  have h := Int.neg_le_neg h
  rwa [Int.neg_neg] at h
#align int.le_neg_of_le_neg Int.le_neg_of_le_neg
-/

#print Int.neg_le_of_neg_le /-
protected theorem neg_le_of_neg_le {a b : ℤ} (h : -a ≤ b) : -b ≤ a :=
  by
  have h := Int.neg_le_neg h
  rwa [Int.neg_neg] at h
#align int.neg_le_of_neg_le Int.neg_le_of_neg_le
-/

#print Int.lt_neg_of_lt_neg /-
protected theorem lt_neg_of_lt_neg {a b : ℤ} (h : a < -b) : b < -a :=
  by
  have h := Int.neg_lt_neg h
  rwa [Int.neg_neg] at h
#align int.lt_neg_of_lt_neg Int.lt_neg_of_lt_neg
-/

#print Int.neg_lt_of_neg_lt /-
protected theorem neg_lt_of_neg_lt {a b : ℤ} (h : -a < b) : -b < a :=
  by
  have h := Int.neg_lt_neg h
  rwa [Int.neg_neg] at h
#align int.neg_lt_of_neg_lt Int.neg_lt_of_neg_lt
-/

#print Int.sub_nonneg_of_le /-
protected theorem sub_nonneg_of_le {a b : ℤ} (h : b ≤ a) : 0 ≤ a - b :=
  by
  have h := Int.add_le_add_right h (-b)
  rwa [Int.add_right_neg] at h
#align int.sub_nonneg_of_le Int.sub_nonneg_of_le
-/

#print Int.le_of_sub_nonneg /-
protected theorem le_of_sub_nonneg {a b : ℤ} (h : 0 ≤ a - b) : b ≤ a :=
  by
  have h := Int.add_le_add_right h b
  rwa [Int.sub_add_cancel, Int.zero_add] at h
#align int.le_of_sub_nonneg Int.le_of_sub_nonneg
-/

#print Int.sub_nonpos_of_le /-
protected theorem sub_nonpos_of_le {a b : ℤ} (h : a ≤ b) : a - b ≤ 0 :=
  by
  have h := Int.add_le_add_right h (-b)
  rwa [Int.add_right_neg] at h
#align int.sub_nonpos_of_le Int.sub_nonpos_of_le
-/

#print Int.le_of_sub_nonpos /-
protected theorem le_of_sub_nonpos {a b : ℤ} (h : a - b ≤ 0) : a ≤ b :=
  by
  have h := Int.add_le_add_right h b
  rwa [Int.sub_add_cancel, Int.zero_add] at h
#align int.le_of_sub_nonpos Int.le_of_sub_nonpos
-/

#print Int.sub_pos_of_lt /-
protected theorem sub_pos_of_lt {a b : ℤ} (h : b < a) : 0 < a - b :=
  by
  have h := Int.add_lt_add_right h (-b)
  rwa [Int.add_right_neg] at h
#align int.sub_pos_of_lt Int.sub_pos_of_lt
-/

#print Int.lt_of_sub_pos /-
protected theorem lt_of_sub_pos {a b : ℤ} (h : 0 < a - b) : b < a :=
  by
  have h := Int.add_lt_add_right h b
  rwa [Int.sub_add_cancel, Int.zero_add] at h
#align int.lt_of_sub_pos Int.lt_of_sub_pos
-/

#print Int.sub_neg_of_lt /-
protected theorem sub_neg_of_lt {a b : ℤ} (h : a < b) : a - b < 0 :=
  by
  have h := Int.add_lt_add_right h (-b)
  rwa [Int.add_right_neg] at h
#align int.sub_neg_of_lt Int.sub_neg_of_lt
-/

#print Int.lt_of_sub_neg /-
protected theorem lt_of_sub_neg {a b : ℤ} (h : a - b < 0) : a < b :=
  by
  have h := Int.add_lt_add_right h b
  rwa [Int.sub_add_cancel, Int.zero_add] at h
#align int.lt_of_sub_neg Int.lt_of_sub_neg
-/

#print Int.add_le_of_le_neg_add /-
protected theorem add_le_of_le_neg_add {a b c : ℤ} (h : b ≤ -a + c) : a + b ≤ c :=
  by
  have h := Int.add_le_add_left h a
  rwa [Int.add_neg_cancel_left] at h
#align int.add_le_of_le_neg_add Int.add_le_of_le_neg_add
-/

#print Int.le_neg_add_of_add_le /-
protected theorem le_neg_add_of_add_le {a b c : ℤ} (h : a + b ≤ c) : b ≤ -a + c :=
  by
  have h := Int.add_le_add_left h (-a)
  rwa [Int.neg_add_cancel_left] at h
#align int.le_neg_add_of_add_le Int.le_neg_add_of_add_le
-/

#print Int.add_le_of_le_sub_left /-
protected theorem add_le_of_le_sub_left {a b c : ℤ} (h : b ≤ c - a) : a + b ≤ c :=
  by
  have h := Int.add_le_add_left h a
  rwa [← Int.add_sub_assoc, Int.add_comm a c, Int.add_sub_cancel] at h
#align int.add_le_of_le_sub_left Int.add_le_of_le_sub_left
-/

#print Int.le_sub_left_of_add_le /-
protected theorem le_sub_left_of_add_le {a b c : ℤ} (h : a + b ≤ c) : b ≤ c - a :=
  by
  have h := Int.add_le_add_right h (-a)
  rwa [Int.add_comm a b, Int.add_neg_cancel_right] at h
#align int.le_sub_left_of_add_le Int.le_sub_left_of_add_le
-/

#print Int.add_le_of_le_sub_right /-
protected theorem add_le_of_le_sub_right {a b c : ℤ} (h : a ≤ c - b) : a + b ≤ c :=
  by
  have h := Int.add_le_add_right h b
  rwa [Int.sub_add_cancel] at h
#align int.add_le_of_le_sub_right Int.add_le_of_le_sub_right
-/

#print Int.le_sub_right_of_add_le /-
protected theorem le_sub_right_of_add_le {a b c : ℤ} (h : a + b ≤ c) : a ≤ c - b :=
  by
  have h := Int.add_le_add_right h (-b)
  rwa [Int.add_neg_cancel_right] at h
#align int.le_sub_right_of_add_le Int.le_sub_right_of_add_le
-/

#print Int.le_add_of_neg_add_le /-
protected theorem le_add_of_neg_add_le {a b c : ℤ} (h : -b + a ≤ c) : a ≤ b + c :=
  by
  have h := Int.add_le_add_left h b
  rwa [Int.add_neg_cancel_left] at h
#align int.le_add_of_neg_add_le Int.le_add_of_neg_add_le
-/

#print Int.neg_add_le_of_le_add /-
protected theorem neg_add_le_of_le_add {a b c : ℤ} (h : a ≤ b + c) : -b + a ≤ c :=
  by
  have h := Int.add_le_add_left h (-b)
  rwa [Int.neg_add_cancel_left] at h
#align int.neg_add_le_of_le_add Int.neg_add_le_of_le_add
-/

#print Int.le_add_of_sub_left_le /-
protected theorem le_add_of_sub_left_le {a b c : ℤ} (h : a - b ≤ c) : a ≤ b + c :=
  by
  have h := Int.add_le_add_right h b
  rwa [Int.sub_add_cancel, Int.add_comm] at h
#align int.le_add_of_sub_left_le Int.le_add_of_sub_left_le
-/

#print Int.sub_left_le_of_le_add /-
protected theorem sub_left_le_of_le_add {a b c : ℤ} (h : a ≤ b + c) : a - b ≤ c :=
  by
  have h := Int.add_le_add_right h (-b)
  rwa [Int.add_comm b c, Int.add_neg_cancel_right] at h
#align int.sub_left_le_of_le_add Int.sub_left_le_of_le_add
-/

#print Int.le_add_of_sub_right_le /-
protected theorem le_add_of_sub_right_le {a b c : ℤ} (h : a - c ≤ b) : a ≤ b + c :=
  by
  have h := Int.add_le_add_right h c
  rwa [Int.sub_add_cancel] at h
#align int.le_add_of_sub_right_le Int.le_add_of_sub_right_le
-/

#print Int.sub_right_le_of_le_add /-
protected theorem sub_right_le_of_le_add {a b c : ℤ} (h : a ≤ b + c) : a - c ≤ b :=
  by
  have h := Int.add_le_add_right h (-c)
  rwa [Int.add_neg_cancel_right] at h
#align int.sub_right_le_of_le_add Int.sub_right_le_of_le_add
-/

#print Int.le_add_of_neg_add_le_left /-
protected theorem le_add_of_neg_add_le_left {a b c : ℤ} (h : -b + a ≤ c) : a ≤ b + c :=
  by
  rw [Int.add_comm] at h
  exact Int.le_add_of_sub_left_le h
#align int.le_add_of_neg_add_le_left Int.le_add_of_neg_add_le_left
-/

#print Int.neg_add_le_left_of_le_add /-
protected theorem neg_add_le_left_of_le_add {a b c : ℤ} (h : a ≤ b + c) : -b + a ≤ c :=
  by
  rw [Int.add_comm]
  exact Int.sub_left_le_of_le_add h
#align int.neg_add_le_left_of_le_add Int.neg_add_le_left_of_le_add
-/

#print Int.le_add_of_neg_add_le_right /-
protected theorem le_add_of_neg_add_le_right {a b c : ℤ} (h : -c + a ≤ b) : a ≤ b + c :=
  by
  rw [Int.add_comm] at h
  exact Int.le_add_of_sub_right_le h
#align int.le_add_of_neg_add_le_right Int.le_add_of_neg_add_le_right
-/

#print Int.neg_add_le_right_of_le_add /-
protected theorem neg_add_le_right_of_le_add {a b c : ℤ} (h : a ≤ b + c) : -c + a ≤ b :=
  by
  rw [Int.add_comm] at h
  exact Int.neg_add_le_left_of_le_add h
#align int.neg_add_le_right_of_le_add Int.neg_add_le_right_of_le_add
-/

#print Int.le_add_of_neg_le_sub_left /-
protected theorem le_add_of_neg_le_sub_left {a b c : ℤ} (h : -a ≤ b - c) : c ≤ a + b :=
  Int.le_add_of_neg_add_le_left (Int.add_le_of_le_sub_right h)
#align int.le_add_of_neg_le_sub_left Int.le_add_of_neg_le_sub_left
-/

#print Int.neg_le_sub_left_of_le_add /-
protected theorem neg_le_sub_left_of_le_add {a b c : ℤ} (h : c ≤ a + b) : -a ≤ b - c :=
  by
  have h := Int.le_neg_add_of_add_le (Int.sub_left_le_of_le_add h)
  rwa [Int.add_comm] at h
#align int.neg_le_sub_left_of_le_add Int.neg_le_sub_left_of_le_add
-/

#print Int.le_add_of_neg_le_sub_right /-
protected theorem le_add_of_neg_le_sub_right {a b c : ℤ} (h : -b ≤ a - c) : c ≤ a + b :=
  Int.le_add_of_sub_right_le (Int.add_le_of_le_sub_left h)
#align int.le_add_of_neg_le_sub_right Int.le_add_of_neg_le_sub_right
-/

#print Int.neg_le_sub_right_of_le_add /-
protected theorem neg_le_sub_right_of_le_add {a b c : ℤ} (h : c ≤ a + b) : -b ≤ a - c :=
  Int.le_sub_left_of_add_le (Int.sub_right_le_of_le_add h)
#align int.neg_le_sub_right_of_le_add Int.neg_le_sub_right_of_le_add
-/

#print Int.sub_le_of_sub_le /-
protected theorem sub_le_of_sub_le {a b c : ℤ} (h : a - b ≤ c) : a - c ≤ b :=
  Int.sub_left_le_of_le_add (Int.le_add_of_sub_right_le h)
#align int.sub_le_of_sub_le Int.sub_le_of_sub_le
-/

#print Int.sub_le_sub_left /-
protected theorem sub_le_sub_left {a b : ℤ} (h : a ≤ b) (c : ℤ) : c - b ≤ c - a :=
  Int.add_le_add_left (Int.neg_le_neg h) c
#align int.sub_le_sub_left Int.sub_le_sub_left
-/

#print Int.sub_le_sub_right /-
protected theorem sub_le_sub_right {a b : ℤ} (h : a ≤ b) (c : ℤ) : a - c ≤ b - c :=
  Int.add_le_add_right h (-c)
#align int.sub_le_sub_right Int.sub_le_sub_right
-/

#print Int.sub_le_sub /-
protected theorem sub_le_sub {a b c d : ℤ} (hab : a ≤ b) (hcd : c ≤ d) : a - d ≤ b - c :=
  Int.add_le_add hab (Int.neg_le_neg hcd)
#align int.sub_le_sub Int.sub_le_sub
-/

#print Int.add_lt_of_lt_neg_add /-
protected theorem add_lt_of_lt_neg_add {a b c : ℤ} (h : b < -a + c) : a + b < c :=
  by
  have h := Int.add_lt_add_left h a
  rwa [Int.add_neg_cancel_left] at h
#align int.add_lt_of_lt_neg_add Int.add_lt_of_lt_neg_add
-/

#print Int.lt_neg_add_of_add_lt /-
protected theorem lt_neg_add_of_add_lt {a b c : ℤ} (h : a + b < c) : b < -a + c :=
  by
  have h := Int.add_lt_add_left h (-a)
  rwa [Int.neg_add_cancel_left] at h
#align int.lt_neg_add_of_add_lt Int.lt_neg_add_of_add_lt
-/

#print Int.add_lt_of_lt_sub_left /-
protected theorem add_lt_of_lt_sub_left {a b c : ℤ} (h : b < c - a) : a + b < c :=
  by
  have h := Int.add_lt_add_left h a
  rwa [← Int.add_sub_assoc, Int.add_comm a c, Int.add_sub_cancel] at h
#align int.add_lt_of_lt_sub_left Int.add_lt_of_lt_sub_left
-/

#print Int.lt_sub_left_of_add_lt /-
protected theorem lt_sub_left_of_add_lt {a b c : ℤ} (h : a + b < c) : b < c - a :=
  by
  have h := Int.add_lt_add_right h (-a)
  rwa [Int.add_comm a b, Int.add_neg_cancel_right] at h
#align int.lt_sub_left_of_add_lt Int.lt_sub_left_of_add_lt
-/

#print Int.add_lt_of_lt_sub_right /-
protected theorem add_lt_of_lt_sub_right {a b c : ℤ} (h : a < c - b) : a + b < c :=
  by
  have h := Int.add_lt_add_right h b
  rwa [Int.sub_add_cancel] at h
#align int.add_lt_of_lt_sub_right Int.add_lt_of_lt_sub_right
-/

#print Int.lt_sub_right_of_add_lt /-
protected theorem lt_sub_right_of_add_lt {a b c : ℤ} (h : a + b < c) : a < c - b :=
  by
  have h := Int.add_lt_add_right h (-b)
  rwa [Int.add_neg_cancel_right] at h
#align int.lt_sub_right_of_add_lt Int.lt_sub_right_of_add_lt
-/

#print Int.lt_add_of_neg_add_lt /-
protected theorem lt_add_of_neg_add_lt {a b c : ℤ} (h : -b + a < c) : a < b + c :=
  by
  have h := Int.add_lt_add_left h b
  rwa [Int.add_neg_cancel_left] at h
#align int.lt_add_of_neg_add_lt Int.lt_add_of_neg_add_lt
-/

#print Int.neg_add_lt_of_lt_add /-
protected theorem neg_add_lt_of_lt_add {a b c : ℤ} (h : a < b + c) : -b + a < c :=
  by
  have h := Int.add_lt_add_left h (-b)
  rwa [Int.neg_add_cancel_left] at h
#align int.neg_add_lt_of_lt_add Int.neg_add_lt_of_lt_add
-/

#print Int.lt_add_of_sub_left_lt /-
protected theorem lt_add_of_sub_left_lt {a b c : ℤ} (h : a - b < c) : a < b + c :=
  by
  have h := Int.add_lt_add_right h b
  rwa [Int.sub_add_cancel, Int.add_comm] at h
#align int.lt_add_of_sub_left_lt Int.lt_add_of_sub_left_lt
-/

#print Int.sub_left_lt_of_lt_add /-
protected theorem sub_left_lt_of_lt_add {a b c : ℤ} (h : a < b + c) : a - b < c :=
  by
  have h := Int.add_lt_add_right h (-b)
  rwa [Int.add_comm b c, Int.add_neg_cancel_right] at h
#align int.sub_left_lt_of_lt_add Int.sub_left_lt_of_lt_add
-/

#print Int.lt_add_of_sub_right_lt /-
protected theorem lt_add_of_sub_right_lt {a b c : ℤ} (h : a - c < b) : a < b + c :=
  by
  have h := Int.add_lt_add_right h c
  rwa [Int.sub_add_cancel] at h
#align int.lt_add_of_sub_right_lt Int.lt_add_of_sub_right_lt
-/

#print Int.sub_right_lt_of_lt_add /-
protected theorem sub_right_lt_of_lt_add {a b c : ℤ} (h : a < b + c) : a - c < b :=
  by
  have h := Int.add_lt_add_right h (-c)
  rwa [Int.add_neg_cancel_right] at h
#align int.sub_right_lt_of_lt_add Int.sub_right_lt_of_lt_add
-/

#print Int.lt_add_of_neg_add_lt_left /-
protected theorem lt_add_of_neg_add_lt_left {a b c : ℤ} (h : -b + a < c) : a < b + c :=
  by
  rw [Int.add_comm] at h
  exact Int.lt_add_of_sub_left_lt h
#align int.lt_add_of_neg_add_lt_left Int.lt_add_of_neg_add_lt_left
-/

#print Int.neg_add_lt_left_of_lt_add /-
protected theorem neg_add_lt_left_of_lt_add {a b c : ℤ} (h : a < b + c) : -b + a < c :=
  by
  rw [Int.add_comm]
  exact Int.sub_left_lt_of_lt_add h
#align int.neg_add_lt_left_of_lt_add Int.neg_add_lt_left_of_lt_add
-/

#print Int.lt_add_of_neg_add_lt_right /-
protected theorem lt_add_of_neg_add_lt_right {a b c : ℤ} (h : -c + a < b) : a < b + c :=
  by
  rw [Int.add_comm] at h
  exact Int.lt_add_of_sub_right_lt h
#align int.lt_add_of_neg_add_lt_right Int.lt_add_of_neg_add_lt_right
-/

#print Int.neg_add_lt_right_of_lt_add /-
protected theorem neg_add_lt_right_of_lt_add {a b c : ℤ} (h : a < b + c) : -c + a < b :=
  by
  rw [Int.add_comm] at h
  exact Int.neg_add_lt_left_of_lt_add h
#align int.neg_add_lt_right_of_lt_add Int.neg_add_lt_right_of_lt_add
-/

#print Int.lt_add_of_neg_lt_sub_left /-
protected theorem lt_add_of_neg_lt_sub_left {a b c : ℤ} (h : -a < b - c) : c < a + b :=
  Int.lt_add_of_neg_add_lt_left (Int.add_lt_of_lt_sub_right h)
#align int.lt_add_of_neg_lt_sub_left Int.lt_add_of_neg_lt_sub_left
-/

#print Int.neg_lt_sub_left_of_lt_add /-
protected theorem neg_lt_sub_left_of_lt_add {a b c : ℤ} (h : c < a + b) : -a < b - c :=
  by
  have h := Int.lt_neg_add_of_add_lt (Int.sub_left_lt_of_lt_add h)
  rwa [Int.add_comm] at h
#align int.neg_lt_sub_left_of_lt_add Int.neg_lt_sub_left_of_lt_add
-/

#print Int.lt_add_of_neg_lt_sub_right /-
protected theorem lt_add_of_neg_lt_sub_right {a b c : ℤ} (h : -b < a - c) : c < a + b :=
  Int.lt_add_of_sub_right_lt (Int.add_lt_of_lt_sub_left h)
#align int.lt_add_of_neg_lt_sub_right Int.lt_add_of_neg_lt_sub_right
-/

#print Int.neg_lt_sub_right_of_lt_add /-
protected theorem neg_lt_sub_right_of_lt_add {a b c : ℤ} (h : c < a + b) : -b < a - c :=
  Int.lt_sub_left_of_add_lt (Int.sub_right_lt_of_lt_add h)
#align int.neg_lt_sub_right_of_lt_add Int.neg_lt_sub_right_of_lt_add
-/

#print Int.sub_lt_of_sub_lt /-
protected theorem sub_lt_of_sub_lt {a b c : ℤ} (h : a - b < c) : a - c < b :=
  Int.sub_left_lt_of_lt_add (Int.lt_add_of_sub_right_lt h)
#align int.sub_lt_of_sub_lt Int.sub_lt_of_sub_lt
-/

#print Int.sub_lt_sub_left /-
protected theorem sub_lt_sub_left {a b : ℤ} (h : a < b) (c : ℤ) : c - b < c - a :=
  Int.add_lt_add_left (Int.neg_lt_neg h) c
#align int.sub_lt_sub_left Int.sub_lt_sub_left
-/

#print Int.sub_lt_sub_right /-
protected theorem sub_lt_sub_right {a b : ℤ} (h : a < b) (c : ℤ) : a - c < b - c :=
  Int.add_lt_add_right h (-c)
#align int.sub_lt_sub_right Int.sub_lt_sub_right
-/

#print Int.sub_lt_sub /-
protected theorem sub_lt_sub {a b c d : ℤ} (hab : a < b) (hcd : c < d) : a - d < b - c :=
  Int.add_lt_add hab (Int.neg_lt_neg hcd)
#align int.sub_lt_sub Int.sub_lt_sub
-/

#print Int.sub_lt_sub_of_le_of_lt /-
protected theorem sub_lt_sub_of_le_of_lt {a b c d : ℤ} (hab : a ≤ b) (hcd : c < d) :
    a - d < b - c :=
  Int.add_lt_add_of_le_of_lt hab (Int.neg_lt_neg hcd)
#align int.sub_lt_sub_of_le_of_lt Int.sub_lt_sub_of_le_of_lt
-/

#print Int.sub_lt_sub_of_lt_of_le /-
protected theorem sub_lt_sub_of_lt_of_le {a b c d : ℤ} (hab : a < b) (hcd : c ≤ d) :
    a - d < b - c :=
  Int.add_lt_add_of_lt_of_le hab (Int.neg_le_neg hcd)
#align int.sub_lt_sub_of_lt_of_le Int.sub_lt_sub_of_lt_of_le
-/

#print Int.sub_le_self /-
protected theorem sub_le_self (a : ℤ) {b : ℤ} (h : 0 ≤ b) : a - b ≤ a :=
  calc
    a - b = a + -b := rfl
    _ ≤ a + 0 := (Int.add_le_add_left (Int.neg_nonpos_of_nonneg h) _)
    _ = a := by rw [Int.add_zero]

#align int.sub_le_self Int.sub_le_self
-/

#print Int.sub_lt_self /-
protected theorem sub_lt_self (a : ℤ) {b : ℤ} (h : 0 < b) : a - b < a :=
  calc
    a - b = a + -b := rfl
    _ < a + 0 := (Int.add_lt_add_left (Int.neg_neg_of_pos h) _)
    _ = a := by rw [Int.add_zero]

#align int.sub_lt_self Int.sub_lt_self
-/

#print Int.add_le_add_three /-
protected theorem add_le_add_three {a b c d e f : ℤ} (h₁ : a ≤ d) (h₂ : b ≤ e) (h₃ : c ≤ f) :
    a + b + c ≤ d + e + f := by
  apply le_trans
  apply Int.add_le_add
  apply Int.add_le_add
  assumption'
  apply le_refl
#align int.add_le_add_three Int.add_le_add_three
-/

end

/-! missing facts -/

#print Int.mul_lt_mul_of_pos_left /-
protected theorem mul_lt_mul_of_pos_left {a b c : ℤ} (h₁ : a < b) (h₂ : 0 < c) : c * a < c * b :=
  by
  have : 0 < b - a := Int.sub_pos_of_lt h₁
  have : 0 < c * (b - a) := Int.mul_pos h₂ this
  rw [Int.mul_sub] at this
  exact Int.lt_of_sub_pos this
#align int.mul_lt_mul_of_pos_left Int.mul_lt_mul_of_pos_left
-/

#print Int.mul_lt_mul_of_pos_right /-
protected theorem mul_lt_mul_of_pos_right {a b c : ℤ} (h₁ : a < b) (h₂ : 0 < c) : a * c < b * c :=
  by
  have : 0 < b - a := Int.sub_pos_of_lt h₁
  have : 0 < (b - a) * c := Int.mul_pos this h₂
  rw [Int.sub_mul] at this
  exact Int.lt_of_sub_pos this
#align int.mul_lt_mul_of_pos_right Int.mul_lt_mul_of_pos_right
-/

#print Int.mul_le_mul_of_nonneg_left /-
protected theorem mul_le_mul_of_nonneg_left {a b c : ℤ} (h₁ : a ≤ b) (h₂ : 0 ≤ c) : c * a ≤ c * b :=
  by
  by_cases hba : b ≤ a; · simp [le_antisymm hba h₁]
  by_cases hc0 : c ≤ 0; · simp [le_antisymm hc0 h₂, Int.zero_mul]
  exact
    (le_not_le_of_lt
        (Int.mul_lt_mul_of_pos_left (lt_of_le_not_le h₁ hba) (lt_of_le_not_le h₂ hc0))).left
#align int.mul_le_mul_of_nonneg_left Int.mul_le_mul_of_nonneg_left
-/

#print Int.mul_le_mul_of_nonneg_right /-
protected theorem mul_le_mul_of_nonneg_right {a b c : ℤ} (h₁ : a ≤ b) (h₂ : 0 ≤ c) :
    a * c ≤ b * c := by
  by_cases hba : b ≤ a; · simp [le_antisymm hba h₁]
  by_cases hc0 : c ≤ 0; · simp [le_antisymm hc0 h₂, Int.mul_zero]
  exact
    (le_not_le_of_lt
        (Int.mul_lt_mul_of_pos_right (lt_of_le_not_le h₁ hba) (lt_of_le_not_le h₂ hc0))).left
#align int.mul_le_mul_of_nonneg_right Int.mul_le_mul_of_nonneg_right
-/

#print Int.mul_le_mul /-
-- TODO: there are four variations, depending on which variables we assume to be nonneg
protected theorem mul_le_mul {a b c d : ℤ} (hac : a ≤ c) (hbd : b ≤ d) (nn_b : 0 ≤ b)
    (nn_c : 0 ≤ c) : a * b ≤ c * d :=
  calc
    a * b ≤ c * b := Int.mul_le_mul_of_nonneg_right hac nn_b
    _ ≤ c * d := Int.mul_le_mul_of_nonneg_left hbd nn_c

#align int.mul_le_mul Int.mul_le_mul
-/

#print Int.mul_nonpos_of_nonneg_of_nonpos /-
protected theorem mul_nonpos_of_nonneg_of_nonpos {a b : ℤ} (ha : 0 ≤ a) (hb : b ≤ 0) : a * b ≤ 0 :=
  by
  have h : a * b ≤ a * 0 := Int.mul_le_mul_of_nonneg_left hb ha
  rwa [Int.mul_zero] at h
#align int.mul_nonpos_of_nonneg_of_nonpos Int.mul_nonpos_of_nonneg_of_nonpos
-/

#print Int.mul_nonpos_of_nonpos_of_nonneg /-
protected theorem mul_nonpos_of_nonpos_of_nonneg {a b : ℤ} (ha : a ≤ 0) (hb : 0 ≤ b) : a * b ≤ 0 :=
  by
  have h : a * b ≤ 0 * b := Int.mul_le_mul_of_nonneg_right ha hb
  rwa [Int.zero_mul] at h
#align int.mul_nonpos_of_nonpos_of_nonneg Int.mul_nonpos_of_nonpos_of_nonneg
-/

#print Int.mul_lt_mul /-
protected theorem mul_lt_mul {a b c d : ℤ} (hac : a < c) (hbd : b ≤ d) (pos_b : 0 < b)
    (nn_c : 0 ≤ c) : a * b < c * d :=
  calc
    a * b < c * b := Int.mul_lt_mul_of_pos_right hac pos_b
    _ ≤ c * d := Int.mul_le_mul_of_nonneg_left hbd nn_c

#align int.mul_lt_mul Int.mul_lt_mul
-/

#print Int.mul_lt_mul' /-
protected theorem mul_lt_mul' {a b c d : ℤ} (h1 : a ≤ c) (h2 : b < d) (h3 : 0 ≤ b) (h4 : 0 < c) :
    a * b < c * d :=
  calc
    a * b ≤ c * b := Int.mul_le_mul_of_nonneg_right h1 h3
    _ < c * d := Int.mul_lt_mul_of_pos_left h2 h4

#align int.mul_lt_mul' Int.mul_lt_mul'
-/

#print Int.mul_neg_of_pos_of_neg /-
protected theorem mul_neg_of_pos_of_neg {a b : ℤ} (ha : 0 < a) (hb : b < 0) : a * b < 0 :=
  by
  have h : a * b < a * 0 := Int.mul_lt_mul_of_pos_left hb ha
  rwa [Int.mul_zero] at h
#align int.mul_neg_of_pos_of_neg Int.mul_neg_of_pos_of_neg
-/

#print Int.mul_neg_of_neg_of_pos /-
protected theorem mul_neg_of_neg_of_pos {a b : ℤ} (ha : a < 0) (hb : 0 < b) : a * b < 0 :=
  by
  have h : a * b < 0 * b := Int.mul_lt_mul_of_pos_right ha hb
  rwa [Int.zero_mul] at h
#align int.mul_neg_of_neg_of_pos Int.mul_neg_of_neg_of_pos
-/

#print Int.mul_le_mul_of_nonpos_right /-
protected theorem mul_le_mul_of_nonpos_right {a b c : ℤ} (h : b ≤ a) (hc : c ≤ 0) : a * c ≤ b * c :=
  have : -c ≥ 0 := Int.neg_nonneg_of_nonpos hc
  have : b * -c ≤ a * -c := Int.mul_le_mul_of_nonneg_right h this
  have : -(b * c) ≤ -(a * c) := by rwa [← Int.neg_mul_eq_mul_neg, ← Int.neg_mul_eq_mul_neg] at this
  Int.le_of_neg_le_neg this
#align int.mul_le_mul_of_nonpos_right Int.mul_le_mul_of_nonpos_right
-/

#print Int.mul_nonneg_of_nonpos_of_nonpos /-
protected theorem mul_nonneg_of_nonpos_of_nonpos {a b : ℤ} (ha : a ≤ 0) (hb : b ≤ 0) : 0 ≤ a * b :=
  by
  have : 0 * b ≤ a * b := Int.mul_le_mul_of_nonpos_right ha hb
  rwa [Int.zero_mul] at this
#align int.mul_nonneg_of_nonpos_of_nonpos Int.mul_nonneg_of_nonpos_of_nonpos
-/

#print Int.mul_lt_mul_of_neg_left /-
protected theorem mul_lt_mul_of_neg_left {a b c : ℤ} (h : b < a) (hc : c < 0) : c * a < c * b :=
  have : -c > 0 := Int.neg_pos_of_neg hc
  have : -c * b < -c * a := Int.mul_lt_mul_of_pos_left h this
  have : -(c * b) < -(c * a) := by rwa [← Int.neg_mul_eq_neg_mul, ← Int.neg_mul_eq_neg_mul] at this
  Int.lt_of_neg_lt_neg this
#align int.mul_lt_mul_of_neg_left Int.mul_lt_mul_of_neg_left
-/

#print Int.mul_lt_mul_of_neg_right /-
protected theorem mul_lt_mul_of_neg_right {a b c : ℤ} (h : b < a) (hc : c < 0) : a * c < b * c :=
  have : -c > 0 := Int.neg_pos_of_neg hc
  have : b * -c < a * -c := Int.mul_lt_mul_of_pos_right h this
  have : -(b * c) < -(a * c) := by rwa [← Int.neg_mul_eq_mul_neg, ← Int.neg_mul_eq_mul_neg] at this
  Int.lt_of_neg_lt_neg this
#align int.mul_lt_mul_of_neg_right Int.mul_lt_mul_of_neg_right
-/

#print Int.mul_pos_of_neg_of_neg /-
protected theorem mul_pos_of_neg_of_neg {a b : ℤ} (ha : a < 0) (hb : b < 0) : 0 < a * b :=
  by
  have : 0 * b < a * b := Int.mul_lt_mul_of_neg_right ha hb
  rwa [Int.zero_mul] at this
#align int.mul_pos_of_neg_of_neg Int.mul_pos_of_neg_of_neg
-/

#print Int.mul_self_le_mul_self /-
protected theorem mul_self_le_mul_self {a b : ℤ} (h1 : 0 ≤ a) (h2 : a ≤ b) : a * a ≤ b * b :=
  Int.mul_le_mul h2 h2 h1 (le_trans h1 h2)
#align int.mul_self_le_mul_self Int.mul_self_le_mul_self
-/

#print Int.mul_self_lt_mul_self /-
protected theorem mul_self_lt_mul_self {a b : ℤ} (h1 : 0 ≤ a) (h2 : a < b) : a * a < b * b :=
  Int.mul_lt_mul' (le_of_lt h2) h2 h1 (lt_of_le_of_lt h1 h2)
#align int.mul_self_lt_mul_self Int.mul_self_lt_mul_self
-/

/-! more facts specific to int -/

#print Int.ofNat_nonneg /-
theorem ofNat_nonneg (n : ℕ) : 0 ≤ ofNat n :=
  trivial
#align int.of_nat_nonneg Int.ofNat_nonneg
-/

#print Int.ofNat_succ_pos /-
theorem ofNat_succ_pos (n : Nat) : 0 < (Nat.succ n : ℤ) :=
  ofNat_lt_ofNat_of_lt (Nat.succ_pos _)
#align int.coe_succ_pos Int.ofNat_succ_pos
-/

#print Int.exists_eq_neg_ofNat /-
theorem exists_eq_neg_ofNat {a : ℤ} (H : a ≤ 0) : ∃ n : ℕ, a = -n :=
  let ⟨n, h⟩ := eq_ofNat_of_zero_le (Int.neg_nonneg_of_nonpos H)
  ⟨n, Int.eq_neg_of_eq_neg h.symm⟩
#align int.exists_eq_neg_of_nat Int.exists_eq_neg_ofNat
-/

#print Int.natAbs_of_nonneg /-
theorem natAbs_of_nonneg {a : ℤ} (H : 0 ≤ a) : (natAbs a : ℤ) = a :=
  match a, eq_ofNat_of_zero_le H with
  | _, ⟨n, rfl⟩ => rfl
#align int.nat_abs_of_nonneg Int.natAbs_of_nonneg
-/

#print Int.ofNat_natAbs_of_nonpos /-
theorem ofNat_natAbs_of_nonpos {a : ℤ} (H : a ≤ 0) : (natAbs a : ℤ) = -a := by
  rw [← nat_abs_neg, nat_abs_of_nonneg (Int.neg_nonneg_of_nonpos H)]
#align int.of_nat_nat_abs_of_nonpos Int.ofNat_natAbs_of_nonpos
-/

#print Int.lt_of_add_one_le /-
theorem lt_of_add_one_le {a b : ℤ} (H : a + 1 ≤ b) : a < b :=
  H
#align int.lt_of_add_one_le Int.lt_of_add_one_le
-/

#print Int.add_one_le_of_lt /-
theorem add_one_le_of_lt {a b : ℤ} (H : a < b) : a + 1 ≤ b :=
  H
#align int.add_one_le_of_lt Int.add_one_le_of_lt
-/

#print Int.lt_add_one_of_le /-
theorem lt_add_one_of_le {a b : ℤ} (H : a ≤ b) : a < b + 1 :=
  Int.add_le_add_right H 1
#align int.lt_add_one_of_le Int.lt_add_one_of_le
-/

#print Int.le_of_lt_add_one /-
theorem le_of_lt_add_one {a b : ℤ} (H : a < b + 1) : a ≤ b :=
  Int.le_of_add_le_add_right H
#align int.le_of_lt_add_one Int.le_of_lt_add_one
-/

#print Int.sub_one_lt_of_le /-
theorem sub_one_lt_of_le {a b : ℤ} (H : a ≤ b) : a - 1 < b :=
  Int.sub_right_lt_of_lt_add <| lt_add_one_of_le H
#align int.sub_one_lt_of_le Int.sub_one_lt_of_le
-/

#print Int.le_of_sub_one_lt /-
theorem le_of_sub_one_lt {a b : ℤ} (H : a - 1 < b) : a ≤ b :=
  le_of_lt_add_one <| Int.lt_add_of_sub_right_lt H
#align int.le_of_sub_one_lt Int.le_of_sub_one_lt
-/

#print Int.le_sub_one_of_lt /-
theorem le_sub_one_of_lt {a b : ℤ} (H : a < b) : a ≤ b - 1 :=
  Int.le_sub_right_of_add_le H
#align int.le_sub_one_of_lt Int.le_sub_one_of_lt
-/

#print Int.lt_of_le_sub_one /-
theorem lt_of_le_sub_one {a b : ℤ} (H : a ≤ b - 1) : a < b :=
  Int.add_le_of_le_sub_right H
#align int.lt_of_le_sub_one Int.lt_of_le_sub_one
-/

#print Int.sign_of_succ /-
theorem sign_of_succ (n : Nat) : sign (Nat.succ n) = 1 :=
  rfl
#align int.sign_of_succ Int.sign_of_succ
-/

#print Int.sign_eq_one_of_pos /-
theorem sign_eq_one_of_pos {a : ℤ} (h : 0 < a) : sign a = 1 :=
  match a, eq_succ_of_zero_lt h with
  | _, ⟨n, rfl⟩ => rfl
#align int.sign_eq_one_of_pos Int.sign_eq_one_of_pos
-/

#print Int.sign_eq_neg_one_of_neg /-
theorem sign_eq_neg_one_of_neg {a : ℤ} (h : a < 0) : sign a = -1 :=
  match a, eq_negSucc_of_lt_zero h with
  | _, ⟨n, rfl⟩ => rfl
#align int.sign_eq_neg_one_of_neg Int.sign_eq_neg_one_of_neg
-/

#print Int.eq_zero_of_sign_eq_zero /-
theorem eq_zero_of_sign_eq_zero : ∀ {a : ℤ}, sign a = 0 → a = 0
  | 0, _ => rfl
#align int.eq_zero_of_sign_eq_zero Int.eq_zero_of_sign_eq_zero
-/

#print Int.pos_of_sign_eq_one /-
theorem pos_of_sign_eq_one : ∀ {a : ℤ}, sign a = 1 → 0 < a
  | (n + 1 : ℕ), _ => ofNat_lt_ofNat_of_lt (Nat.succ_pos _)
#align int.pos_of_sign_eq_one Int.pos_of_sign_eq_one
-/

#print Int.neg_of_sign_eq_neg_one /-
theorem neg_of_sign_eq_neg_one : ∀ {a : ℤ}, sign a = -1 → a < 0
  | (n + 1 : ℕ), h => nomatch h
  | 0, h => nomatch h
  | -[n+1], _ => negSucc_lt_zero _
#align int.neg_of_sign_eq_neg_one Int.neg_of_sign_eq_neg_one
-/

#print Int.sign_eq_one_iff_pos /-
theorem sign_eq_one_iff_pos (a : ℤ) : sign a = 1 ↔ 0 < a :=
  ⟨pos_of_sign_eq_one, sign_eq_one_of_pos⟩
#align int.sign_eq_one_iff_pos Int.sign_eq_one_iff_pos
-/

#print Int.sign_eq_neg_one_iff_neg /-
theorem sign_eq_neg_one_iff_neg (a : ℤ) : sign a = -1 ↔ a < 0 :=
  ⟨neg_of_sign_eq_neg_one, sign_eq_neg_one_of_neg⟩
#align int.sign_eq_neg_one_iff_neg Int.sign_eq_neg_one_iff_neg
-/

#print Int.sign_eq_zero_iff_zero /-
theorem sign_eq_zero_iff_zero (a : ℤ) : sign a = 0 ↔ a = 0 :=
  ⟨eq_zero_of_sign_eq_zero, fun h => by rw [h, sign_zero]⟩
#align int.sign_eq_zero_iff_zero Int.sign_eq_zero_iff_zero
-/

#print Int.eq_zero_or_eq_zero_of_mul_eq_zero /-
protected theorem eq_zero_or_eq_zero_of_mul_eq_zero {a b : ℤ} (h : a * b = 0) : a = 0 ∨ b = 0 :=
  match lt_trichotomy 0 a with
  | Or.inl hlt₁ =>
    match lt_trichotomy 0 b with
    | Or.inl hlt₂ => by
      have : 0 < a * b := Int.mul_pos hlt₁ hlt₂
      rw [h] at this
      exact absurd this (lt_irrefl _)
    | Or.inr (Or.inl heq₂) => Or.inr heq₂.symm
    | Or.inr (Or.inr hgt₂) =>
      by
      have : 0 > a * b := Int.mul_neg_of_pos_of_neg hlt₁ hgt₂
      rw [h] at this
      exact absurd this (lt_irrefl _)
  | Or.inr (Or.inl heq₁) => Or.inl heq₁.symm
  | Or.inr (Or.inr hgt₁) =>
    match lt_trichotomy 0 b with
    | Or.inl hlt₂ => by
      have : 0 > a * b := Int.mul_neg_of_neg_of_pos hgt₁ hlt₂
      rw [h] at this
      exact absurd this (lt_irrefl _)
    | Or.inr (Or.inl heq₂) => Or.inr heq₂.symm
    | Or.inr (Or.inr hgt₂) =>
      by
      have : 0 < a * b := Int.mul_pos_of_neg_of_neg hgt₁ hgt₂
      rw [h] at this
      exact absurd this (lt_irrefl _)
#align int.eq_zero_or_eq_zero_of_mul_eq_zero Int.eq_zero_or_eq_zero_of_mul_eq_zero
-/

#print Int.eq_of_mul_eq_mul_right /-
protected theorem eq_of_mul_eq_mul_right {a b c : ℤ} (ha : a ≠ 0) (h : b * a = c * a) : b = c :=
  have : b * a - c * a = 0 := Int.sub_eq_zero_of_eq h
  have : (b - c) * a = 0 := by rw [Int.sub_mul, this]
  have : b - c = 0 := (Int.eq_zero_or_eq_zero_of_mul_eq_zero this).resolve_right ha
  Int.eq_of_sub_eq_zero this
#align int.eq_of_mul_eq_mul_right Int.eq_of_mul_eq_mul_right
-/

#print Int.eq_of_mul_eq_mul_left /-
protected theorem eq_of_mul_eq_mul_left {a b c : ℤ} (ha : a ≠ 0) (h : a * b = a * c) : b = c :=
  have : a * b - a * c = 0 := Int.sub_eq_zero_of_eq h
  have : a * (b - c) = 0 := by rw [Int.mul_sub, this]
  have : b - c = 0 := (Int.eq_zero_or_eq_zero_of_mul_eq_zero this).resolve_left ha
  Int.eq_of_sub_eq_zero this
#align int.eq_of_mul_eq_mul_left Int.eq_of_mul_eq_mul_left
-/

#print Int.eq_one_of_mul_eq_self_left /-
theorem eq_one_of_mul_eq_self_left {a b : ℤ} (Hpos : a ≠ 0) (H : b * a = a) : b = 1 :=
  Int.eq_of_mul_eq_mul_right Hpos (by rw [Int.one_mul, H])
#align int.eq_one_of_mul_eq_self_left Int.eq_one_of_mul_eq_self_left
-/

#print Int.eq_one_of_mul_eq_self_right /-
theorem eq_one_of_mul_eq_self_right {a b : ℤ} (Hpos : b ≠ 0) (H : b * a = b) : a = 1 :=
  Int.eq_of_mul_eq_mul_left Hpos (by rw [Int.mul_one, H])
#align int.eq_one_of_mul_eq_self_right Int.eq_one_of_mul_eq_self_right
-/

end Int