/-
Copyright (c) 2021 Yakov Pechersky. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yakov Pechersky

! This file was ported from Lean 3 source module algebra.tropical.basic
! leanprover-community/mathlib commit 00f4ab49e7d5139216e0b3daad15fffa504897ab
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Algebra.GroupPower.Order
import Mathbin.Algebra.Order.Monoid.WithTop
import Mathbin.Algebra.SmulWithZero
import Mathbin.Algebra.Order.Monoid.MinMax

/-!

# Tropical algebraic structures

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

This file defines algebraic structures of the (min-)tropical numbers, up to the tropical semiring.
Some basic lemmas about conversion from the base type `R` to `tropical R` are provided, as
well as the expected implementations of tropical addition and tropical multiplication.

## Main declarations

* `tropical R`: The type synonym of the tropical interpretation of `R`.
    If `[linear_order R]`, then addition on `R` is via `min`.
* `semiring (tropical R)`: A `linear_ordered_add_comm_monoid_with_top R`
    induces a `semiring (tropical R)`. If one solely has `[linear_ordered_add_comm_monoid R]`,
    then the "tropicalization of `R`" would be `tropical (with_top R)`.

## Implementation notes

The tropical structure relies on `has_top` and `min`. For the max-tropical numbers, use
`order_dual R`.

Inspiration was drawn from the implementation of `additive`/`multiplicative`/`opposite`,
where a type synonym is created with some barebones API, and quickly made irreducible.

Algebraic structures are provided with as few typeclass assumptions as possible, even though
most references rely on `semiring (tropical R)` for building up the whole theory.

## References followed

* https://arxiv.org/pdf/math/0408099.pdf
* https://www.mathenjeans.fr/sites/default/files/sujets/tropical_geometry_-_casagrande.pdf

-/

universe u v

variable (R : Type u)

#print Tropical /-
/-- The tropicalization of a type `R`. -/
def Tropical : Type u :=
  R
#align tropical Tropical
-/

variable {R}

namespace Tropical

#print Tropical.trop /-
/-- Reinterpret `x : R` as an element of `tropical R`.
See `tropical.trop_equiv` for the equivalence.
-/
@[pp_nodot]
def trop : R → Tropical R :=
  id
#align tropical.trop Tropical.trop
-/

#print Tropical.untrop /-
/-- Reinterpret `x : tropical R` as an element of `R`.
See `tropical.trop_equiv` for the equivalence. -/
@[pp_nodot]
def untrop : Tropical R → R :=
  id
#align tropical.untrop Tropical.untrop
-/

#print Tropical.trop_injective /-
theorem trop_injective : Function.Injective (trop : R → Tropical R) := fun _ _ => id
#align tropical.trop_injective Tropical.trop_injective
-/

#print Tropical.untrop_injective /-
theorem untrop_injective : Function.Injective (untrop : Tropical R → R) := fun _ _ => id
#align tropical.untrop_injective Tropical.untrop_injective
-/

#print Tropical.trop_inj_iff /-
@[simp]
theorem trop_inj_iff (x y : R) : trop x = trop y ↔ x = y :=
  Iff.rfl
#align tropical.trop_inj_iff Tropical.trop_inj_iff
-/

#print Tropical.untrop_inj_iff /-
@[simp]
theorem untrop_inj_iff (x y : Tropical R) : untrop x = untrop y ↔ x = y :=
  Iff.rfl
#align tropical.untrop_inj_iff Tropical.untrop_inj_iff
-/

#print Tropical.trop_untrop /-
@[simp]
theorem trop_untrop (x : Tropical R) : trop (untrop x) = x :=
  rfl
#align tropical.trop_untrop Tropical.trop_untrop
-/

#print Tropical.untrop_trop /-
@[simp]
theorem untrop_trop (x : R) : untrop (trop x) = x :=
  rfl
#align tropical.untrop_trop Tropical.untrop_trop
-/

#print Tropical.leftInverse_trop /-
theorem leftInverse_trop : Function.LeftInverse (trop : R → Tropical R) untrop :=
  trop_untrop
#align tropical.left_inverse_trop Tropical.leftInverse_trop
-/

#print Tropical.rightInverse_trop /-
theorem rightInverse_trop : Function.RightInverse (trop : R → Tropical R) untrop :=
  trop_untrop
#align tropical.right_inverse_trop Tropical.rightInverse_trop
-/

#print Tropical.tropEquiv /-
/-- Reinterpret `x : R` as an element of `tropical R`.
See `tropical.trop_order_iso` for the order-preserving equivalence. -/
def tropEquiv : R ≃ Tropical R where
  toFun := trop
  invFun := untrop
  left_inv := untrop_trop
  right_inv := trop_untrop
#align tropical.trop_equiv Tropical.tropEquiv
-/

#print Tropical.tropEquiv_coe_fn /-
@[simp]
theorem tropEquiv_coe_fn : (tropEquiv : R → Tropical R) = trop :=
  rfl
#align tropical.trop_equiv_coe_fn Tropical.tropEquiv_coe_fn
-/

#print Tropical.tropEquiv_symm_coe_fn /-
@[simp]
theorem tropEquiv_symm_coe_fn : (tropEquiv.symm : Tropical R → R) = untrop :=
  rfl
#align tropical.trop_equiv_symm_coe_fn Tropical.tropEquiv_symm_coe_fn
-/

#print Tropical.trop_eq_iff_eq_untrop /-
theorem trop_eq_iff_eq_untrop {x : R} {y} : trop x = y ↔ x = untrop y :=
  tropEquiv.apply_eq_iff_eq_symm_apply
#align tropical.trop_eq_iff_eq_untrop Tropical.trop_eq_iff_eq_untrop
-/

#print Tropical.untrop_eq_iff_eq_trop /-
theorem untrop_eq_iff_eq_trop {x} {y : R} : untrop x = y ↔ x = trop y :=
  tropEquiv.symm.apply_eq_iff_eq_symm_apply
#align tropical.untrop_eq_iff_eq_trop Tropical.untrop_eq_iff_eq_trop
-/

#print Tropical.injective_trop /-
theorem injective_trop : Function.Injective (trop : R → Tropical R) :=
  tropEquiv.Injective
#align tropical.injective_trop Tropical.injective_trop
-/

#print Tropical.injective_untrop /-
theorem injective_untrop : Function.Injective (untrop : Tropical R → R) :=
  tropEquiv.symm.Injective
#align tropical.injective_untrop Tropical.injective_untrop
-/

#print Tropical.surjective_trop /-
theorem surjective_trop : Function.Surjective (trop : R → Tropical R) :=
  tropEquiv.Surjective
#align tropical.surjective_trop Tropical.surjective_trop
-/

#print Tropical.surjective_untrop /-
theorem surjective_untrop : Function.Surjective (untrop : Tropical R → R) :=
  tropEquiv.symm.Surjective
#align tropical.surjective_untrop Tropical.surjective_untrop
-/

instance [Inhabited R] : Inhabited (Tropical R) :=
  ⟨trop default⟩

#print Tropical.tropRec /-
/-- Recursing on a `x' : tropical R` is the same as recursing on an `x : R` reinterpreted
as a term of `tropical R` via `trop x`. -/
@[simp]
def tropRec {F : ∀ X : Tropical R, Sort v} (h : ∀ X, F (trop X)) : ∀ X, F X := fun X => h (untrop X)
#align tropical.trop_rec Tropical.tropRec
-/

instance [DecidableEq R] : DecidableEq (Tropical R) := fun x y =>
  decidable_of_iff _ injective_untrop.eq_iff

section Order

instance [LE R] : LE (Tropical R) where le x y := untrop x ≤ untrop y

#print Tropical.untrop_le_iff /-
@[simp]
theorem untrop_le_iff [LE R] {x y : Tropical R} : untrop x ≤ untrop y ↔ x ≤ y :=
  Iff.rfl
#align tropical.untrop_le_iff Tropical.untrop_le_iff
-/

#print Tropical.decidableLE /-
instance decidableLE [LE R] [DecidableRel ((· ≤ ·) : R → R → Prop)] :
    DecidableRel ((· ≤ ·) : Tropical R → Tropical R → Prop) := fun x y =>
  ‹DecidableRel (· ≤ ·)› (untrop x) (untrop y)
#align tropical.decidable_le Tropical.decidableLE
-/

instance [LT R] : LT (Tropical R) where lt x y := untrop x < untrop y

#print Tropical.untrop_lt_iff /-
@[simp]
theorem untrop_lt_iff [LT R] {x y : Tropical R} : untrop x < untrop y ↔ x < y :=
  Iff.rfl
#align tropical.untrop_lt_iff Tropical.untrop_lt_iff
-/

#print Tropical.decidableLT /-
instance decidableLT [LT R] [DecidableRel ((· < ·) : R → R → Prop)] :
    DecidableRel ((· < ·) : Tropical R → Tropical R → Prop) := fun x y =>
  ‹DecidableRel (· < ·)› (untrop x) (untrop y)
#align tropical.decidable_lt Tropical.decidableLT
-/

instance [Preorder R] : Preorder (Tropical R) :=
  { Tropical.hasLe, Tropical.hasLt with
    le_refl := fun _ => le_rfl
    le_trans := fun _ _ _ h h' => le_trans h h'
    lt_iff_le_not_le := fun _ _ => lt_iff_le_not_le }

#print Tropical.tropOrderIso /-
/-- Reinterpret `x : R` as an element of `tropical R`, preserving the order. -/
def tropOrderIso [Preorder R] : R ≃o Tropical R :=
  { tropEquiv with map_rel_iff' := fun _ _ => untrop_le_iff }
#align tropical.trop_order_iso Tropical.tropOrderIso
-/

/- warning: tropical.trop_order_iso_coe_fn -> Tropical.tropOrderIso_coe_fn is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : Preorder.{u1} R], Eq.{succ u1} ((fun (_x : RelIso.{u1, u1} R (Tropical.{u1} R) (LE.le.{u1} R (Preorder.toLE.{u1} R _inst_1)) (LE.le.{u1} (Tropical.{u1} R) (Tropical.hasLe.{u1} R (Preorder.toLE.{u1} R _inst_1)))) => R -> (Tropical.{u1} R)) (Tropical.tropOrderIso.{u1} R _inst_1)) (coeFn.{succ u1, succ u1} (OrderIso.{u1, u1} R (Tropical.{u1} R) (Preorder.toLE.{u1} R _inst_1) (Tropical.hasLe.{u1} R (Preorder.toLE.{u1} R _inst_1))) (fun (_x : RelIso.{u1, u1} R (Tropical.{u1} R) (LE.le.{u1} R (Preorder.toLE.{u1} R _inst_1)) (LE.le.{u1} (Tropical.{u1} R) (Tropical.hasLe.{u1} R (Preorder.toLE.{u1} R _inst_1)))) => R -> (Tropical.{u1} R)) (RelIso.hasCoeToFun.{u1, u1} R (Tropical.{u1} R) (LE.le.{u1} R (Preorder.toLE.{u1} R _inst_1)) (LE.le.{u1} (Tropical.{u1} R) (Tropical.hasLe.{u1} R (Preorder.toLE.{u1} R _inst_1)))) (Tropical.tropOrderIso.{u1} R _inst_1)) (Tropical.trop.{u1} R)
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : Preorder.{u1} R], Eq.{succ u1} (forall (a : R), (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : R) => Tropical.{u1} R) a) (FunLike.coe.{succ u1, succ u1, succ u1} (Function.Embedding.{succ u1, succ u1} R (Tropical.{u1} R)) R (fun (_x : R) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : R) => Tropical.{u1} R) _x) (EmbeddingLike.toFunLike.{succ u1, succ u1, succ u1} (Function.Embedding.{succ u1, succ u1} R (Tropical.{u1} R)) R (Tropical.{u1} R) (Function.instEmbeddingLikeEmbedding.{succ u1, succ u1} R (Tropical.{u1} R))) (RelEmbedding.toEmbedding.{u1, u1} R (Tropical.{u1} R) (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1281 : R) (x._@.Mathlib.Order.Hom.Basic._hyg.1283 : R) => LE.le.{u1} R (Preorder.toLE.{u1} R _inst_1) x._@.Mathlib.Order.Hom.Basic._hyg.1281 x._@.Mathlib.Order.Hom.Basic._hyg.1283) (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1296 : Tropical.{u1} R) (x._@.Mathlib.Order.Hom.Basic._hyg.1298 : Tropical.{u1} R) => LE.le.{u1} (Tropical.{u1} R) (Tropical.instLETropical.{u1} R (Preorder.toLE.{u1} R _inst_1)) x._@.Mathlib.Order.Hom.Basic._hyg.1296 x._@.Mathlib.Order.Hom.Basic._hyg.1298) (RelIso.toRelEmbedding.{u1, u1} R (Tropical.{u1} R) (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1281 : R) (x._@.Mathlib.Order.Hom.Basic._hyg.1283 : R) => LE.le.{u1} R (Preorder.toLE.{u1} R _inst_1) x._@.Mathlib.Order.Hom.Basic._hyg.1281 x._@.Mathlib.Order.Hom.Basic._hyg.1283) (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1296 : Tropical.{u1} R) (x._@.Mathlib.Order.Hom.Basic._hyg.1298 : Tropical.{u1} R) => LE.le.{u1} (Tropical.{u1} R) (Tropical.instLETropical.{u1} R (Preorder.toLE.{u1} R _inst_1)) x._@.Mathlib.Order.Hom.Basic._hyg.1296 x._@.Mathlib.Order.Hom.Basic._hyg.1298) (Tropical.tropOrderIso.{u1} R _inst_1)))) (Tropical.trop.{u1} R)
Case conversion may be inaccurate. Consider using '#align tropical.trop_order_iso_coe_fn Tropical.tropOrderIso_coe_fnₓ'. -/
@[simp]
theorem tropOrderIso_coe_fn [Preorder R] : (tropOrderIso : R → Tropical R) = trop :=
  rfl
#align tropical.trop_order_iso_coe_fn Tropical.tropOrderIso_coe_fn

/- warning: tropical.trop_order_iso_symm_coe_fn -> Tropical.tropOrderIso_symm_coe_fn is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : Preorder.{u1} R], Eq.{succ u1} ((fun (_x : RelIso.{u1, u1} (Tropical.{u1} R) R (LE.le.{u1} (Tropical.{u1} R) (Tropical.hasLe.{u1} R (Preorder.toLE.{u1} R _inst_1))) (LE.le.{u1} R (Preorder.toLE.{u1} R _inst_1))) => (Tropical.{u1} R) -> R) (OrderIso.symm.{u1, u1} R (Tropical.{u1} R) (Preorder.toLE.{u1} R _inst_1) (Tropical.hasLe.{u1} R (Preorder.toLE.{u1} R _inst_1)) (Tropical.tropOrderIso.{u1} R _inst_1))) (coeFn.{succ u1, succ u1} (OrderIso.{u1, u1} (Tropical.{u1} R) R (Tropical.hasLe.{u1} R (Preorder.toLE.{u1} R _inst_1)) (Preorder.toLE.{u1} R _inst_1)) (fun (_x : RelIso.{u1, u1} (Tropical.{u1} R) R (LE.le.{u1} (Tropical.{u1} R) (Tropical.hasLe.{u1} R (Preorder.toLE.{u1} R _inst_1))) (LE.le.{u1} R (Preorder.toLE.{u1} R _inst_1))) => (Tropical.{u1} R) -> R) (RelIso.hasCoeToFun.{u1, u1} (Tropical.{u1} R) R (LE.le.{u1} (Tropical.{u1} R) (Tropical.hasLe.{u1} R (Preorder.toLE.{u1} R _inst_1))) (LE.le.{u1} R (Preorder.toLE.{u1} R _inst_1))) (OrderIso.symm.{u1, u1} R (Tropical.{u1} R) (Preorder.toLE.{u1} R _inst_1) (Tropical.hasLe.{u1} R (Preorder.toLE.{u1} R _inst_1)) (Tropical.tropOrderIso.{u1} R _inst_1))) (Tropical.untrop.{u1} R)
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : Preorder.{u1} R], Eq.{succ u1} (forall (a : Tropical.{u1} R), (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : Tropical.{u1} R) => R) a) (FunLike.coe.{succ u1, succ u1, succ u1} (Function.Embedding.{succ u1, succ u1} (Tropical.{u1} R) R) (Tropical.{u1} R) (fun (_x : Tropical.{u1} R) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : Tropical.{u1} R) => R) _x) (EmbeddingLike.toFunLike.{succ u1, succ u1, succ u1} (Function.Embedding.{succ u1, succ u1} (Tropical.{u1} R) R) (Tropical.{u1} R) R (Function.instEmbeddingLikeEmbedding.{succ u1, succ u1} (Tropical.{u1} R) R)) (RelEmbedding.toEmbedding.{u1, u1} (Tropical.{u1} R) R (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1281 : Tropical.{u1} R) (x._@.Mathlib.Order.Hom.Basic._hyg.1283 : Tropical.{u1} R) => LE.le.{u1} (Tropical.{u1} R) (Tropical.instLETropical.{u1} R (Preorder.toLE.{u1} R _inst_1)) x._@.Mathlib.Order.Hom.Basic._hyg.1281 x._@.Mathlib.Order.Hom.Basic._hyg.1283) (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1296 : R) (x._@.Mathlib.Order.Hom.Basic._hyg.1298 : R) => LE.le.{u1} R (Preorder.toLE.{u1} R _inst_1) x._@.Mathlib.Order.Hom.Basic._hyg.1296 x._@.Mathlib.Order.Hom.Basic._hyg.1298) (RelIso.toRelEmbedding.{u1, u1} (Tropical.{u1} R) R (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1281 : Tropical.{u1} R) (x._@.Mathlib.Order.Hom.Basic._hyg.1283 : Tropical.{u1} R) => LE.le.{u1} (Tropical.{u1} R) (Tropical.instLETropical.{u1} R (Preorder.toLE.{u1} R _inst_1)) x._@.Mathlib.Order.Hom.Basic._hyg.1281 x._@.Mathlib.Order.Hom.Basic._hyg.1283) (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1296 : R) (x._@.Mathlib.Order.Hom.Basic._hyg.1298 : R) => LE.le.{u1} R (Preorder.toLE.{u1} R _inst_1) x._@.Mathlib.Order.Hom.Basic._hyg.1296 x._@.Mathlib.Order.Hom.Basic._hyg.1298) (OrderIso.symm.{u1, u1} R (Tropical.{u1} R) (Preorder.toLE.{u1} R _inst_1) (Tropical.instLETropical.{u1} R (Preorder.toLE.{u1} R _inst_1)) (Tropical.tropOrderIso.{u1} R _inst_1))))) (Tropical.untrop.{u1} R)
Case conversion may be inaccurate. Consider using '#align tropical.trop_order_iso_symm_coe_fn Tropical.tropOrderIso_symm_coe_fnₓ'. -/
@[simp]
theorem tropOrderIso_symm_coe_fn [Preorder R] : (tropOrderIso.symm : Tropical R → R) = untrop :=
  rfl
#align tropical.trop_order_iso_symm_coe_fn Tropical.tropOrderIso_symm_coe_fn

/- warning: tropical.trop_monotone -> Tropical.trop_monotone is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : Preorder.{u1} R], Monotone.{u1, u1} R (Tropical.{u1} R) _inst_1 (Tropical.preorder.{u1} R _inst_1) (Tropical.trop.{u1} R)
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : Preorder.{u1} R], Monotone.{u1, u1} R (Tropical.{u1} R) _inst_1 (Tropical.instPreorderTropical.{u1} R _inst_1) (Tropical.trop.{u1} R)
Case conversion may be inaccurate. Consider using '#align tropical.trop_monotone Tropical.trop_monotoneₓ'. -/
theorem trop_monotone [Preorder R] : Monotone (trop : R → Tropical R) := fun _ _ => id
#align tropical.trop_monotone Tropical.trop_monotone

/- warning: tropical.untrop_monotone -> Tropical.untrop_monotone is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : Preorder.{u1} R], Monotone.{u1, u1} (Tropical.{u1} R) R (Tropical.preorder.{u1} R _inst_1) _inst_1 (Tropical.untrop.{u1} R)
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : Preorder.{u1} R], Monotone.{u1, u1} (Tropical.{u1} R) R (Tropical.instPreorderTropical.{u1} R _inst_1) _inst_1 (Tropical.untrop.{u1} R)
Case conversion may be inaccurate. Consider using '#align tropical.untrop_monotone Tropical.untrop_monotoneₓ'. -/
theorem untrop_monotone [Preorder R] : Monotone (untrop : Tropical R → R) := fun _ _ => id
#align tropical.untrop_monotone Tropical.untrop_monotone

instance [PartialOrder R] : PartialOrder (Tropical R) :=
  { Tropical.preorder with le_antisymm := fun _ _ h h' => untrop_injective (le_antisymm h h') }

instance [Top R] : Zero (Tropical R) :=
  ⟨trop ⊤⟩

instance [Top R] : Top (Tropical R) :=
  ⟨0⟩

#print Tropical.untrop_zero /-
@[simp]
theorem untrop_zero [Top R] : untrop (0 : Tropical R) = ⊤ :=
  rfl
#align tropical.untrop_zero Tropical.untrop_zero
-/

#print Tropical.trop_top /-
@[simp]
theorem trop_top [Top R] : trop (⊤ : R) = 0 :=
  rfl
#align tropical.trop_top Tropical.trop_top
-/

#print Tropical.trop_coe_ne_zero /-
@[simp]
theorem trop_coe_ne_zero (x : R) : trop (x : WithTop R) ≠ 0 :=
  fun.
#align tropical.trop_coe_ne_zero Tropical.trop_coe_ne_zero
-/

#print Tropical.zero_ne_trop_coe /-
@[simp]
theorem zero_ne_trop_coe (x : R) : (0 : Tropical (WithTop R)) ≠ trop x :=
  fun.
#align tropical.zero_ne_trop_coe Tropical.zero_ne_trop_coe
-/

/- warning: tropical.le_zero -> Tropical.le_zero is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LE.{u1} R] [_inst_2 : OrderTop.{u1} R _inst_1] (x : Tropical.{u1} R), LE.le.{u1} (Tropical.{u1} R) (Tropical.hasLe.{u1} R _inst_1) x (OfNat.ofNat.{u1} (Tropical.{u1} R) 0 (OfNat.mk.{u1} (Tropical.{u1} R) 0 (Zero.zero.{u1} (Tropical.{u1} R) (Tropical.hasZero.{u1} R (OrderTop.toHasTop.{u1} R _inst_1 _inst_2)))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LE.{u1} R] [_inst_2 : OrderTop.{u1} R _inst_1] (x : Tropical.{u1} R), LE.le.{u1} (Tropical.{u1} R) (Tropical.instLETropical.{u1} R _inst_1) x (OfNat.ofNat.{u1} (Tropical.{u1} R) 0 (Zero.toOfNat0.{u1} (Tropical.{u1} R) (Tropical.instZeroTropical.{u1} R (OrderTop.toTop.{u1} R _inst_1 _inst_2))))
Case conversion may be inaccurate. Consider using '#align tropical.le_zero Tropical.le_zeroₓ'. -/
@[simp]
theorem le_zero [LE R] [OrderTop R] (x : Tropical R) : x ≤ 0 :=
  le_top
#align tropical.le_zero Tropical.le_zero

instance [LE R] [OrderTop R] : OrderTop (Tropical R) :=
  { Tropical.hasTop with le_top := fun _ => le_top }

variable [LinearOrder R]

/-- Tropical addition is the minimum of two underlying elements of `R`. -/
instance : Add (Tropical R) :=
  ⟨fun x y => trop (min (untrop x) (untrop y))⟩

instance : AddCommSemigroup (Tropical R)
    where
  add := (· + ·)
  add_assoc _ _ _ := untrop_injective (min_assoc _ _ _)
  add_comm _ _ := untrop_injective (min_comm _ _)

/- warning: tropical.untrop_add -> Tropical.untrop_add is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] (x : Tropical.{u1} R) (y : Tropical.{u1} R), Eq.{succ u1} R (Tropical.untrop.{u1} R (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.hasAdd.{u1} R _inst_1)) x y)) (LinearOrder.min.{u1} R _inst_1 (Tropical.untrop.{u1} R x) (Tropical.untrop.{u1} R y))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] (x : Tropical.{u1} R) (y : Tropical.{u1} R), Eq.{succ u1} R (Tropical.untrop.{u1} R (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.instAddTropical.{u1} R _inst_1)) x y)) (Min.min.{u1} R (LinearOrder.toMin.{u1} R _inst_1) (Tropical.untrop.{u1} R x) (Tropical.untrop.{u1} R y))
Case conversion may be inaccurate. Consider using '#align tropical.untrop_add Tropical.untrop_addₓ'. -/
@[simp]
theorem untrop_add (x y : Tropical R) : untrop (x + y) = min (untrop x) (untrop y) :=
  rfl
#align tropical.untrop_add Tropical.untrop_add

/- warning: tropical.trop_min -> Tropical.trop_min is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] (x : R) (y : R), Eq.{succ u1} (Tropical.{u1} R) (Tropical.trop.{u1} R (LinearOrder.min.{u1} R _inst_1 x y)) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.hasAdd.{u1} R _inst_1)) (Tropical.trop.{u1} R x) (Tropical.trop.{u1} R y))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] (x : R) (y : R), Eq.{succ u1} (Tropical.{u1} R) (Tropical.trop.{u1} R (Min.min.{u1} R (LinearOrder.toMin.{u1} R _inst_1) x y)) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.instAddTropical.{u1} R _inst_1)) (Tropical.trop.{u1} R x) (Tropical.trop.{u1} R y))
Case conversion may be inaccurate. Consider using '#align tropical.trop_min Tropical.trop_minₓ'. -/
@[simp]
theorem trop_min (x y : R) : trop (min x y) = trop x + trop y :=
  rfl
#align tropical.trop_min Tropical.trop_min

/- warning: tropical.trop_inf -> Tropical.trop_inf is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] (x : R) (y : R), Eq.{succ u1} (Tropical.{u1} R) (Tropical.trop.{u1} R (Inf.inf.{u1} R (SemilatticeInf.toHasInf.{u1} R (Lattice.toSemilatticeInf.{u1} R (LinearOrder.toLattice.{u1} R _inst_1))) x y)) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.hasAdd.{u1} R _inst_1)) (Tropical.trop.{u1} R x) (Tropical.trop.{u1} R y))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] (x : R) (y : R), Eq.{succ u1} (Tropical.{u1} R) (Tropical.trop.{u1} R (Inf.inf.{u1} R (Lattice.toInf.{u1} R (DistribLattice.toLattice.{u1} R (instDistribLattice.{u1} R _inst_1))) x y)) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.instAddTropical.{u1} R _inst_1)) (Tropical.trop.{u1} R x) (Tropical.trop.{u1} R y))
Case conversion may be inaccurate. Consider using '#align tropical.trop_inf Tropical.trop_infₓ'. -/
@[simp]
theorem trop_inf (x y : R) : trop (x ⊓ y) = trop x + trop y :=
  rfl
#align tropical.trop_inf Tropical.trop_inf

/- warning: tropical.trop_add_def -> Tropical.trop_add_def is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] (x : Tropical.{u1} R) (y : Tropical.{u1} R), Eq.{succ u1} (Tropical.{u1} R) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.hasAdd.{u1} R _inst_1)) x y) (Tropical.trop.{u1} R (LinearOrder.min.{u1} R _inst_1 (Tropical.untrop.{u1} R x) (Tropical.untrop.{u1} R y)))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] (x : Tropical.{u1} R) (y : Tropical.{u1} R), Eq.{succ u1} (Tropical.{u1} R) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.instAddTropical.{u1} R _inst_1)) x y) (Tropical.trop.{u1} R (Min.min.{u1} R (LinearOrder.toMin.{u1} R _inst_1) (Tropical.untrop.{u1} R x) (Tropical.untrop.{u1} R y)))
Case conversion may be inaccurate. Consider using '#align tropical.trop_add_def Tropical.trop_add_defₓ'. -/
theorem trop_add_def (x y : Tropical R) : x + y = trop (min (untrop x) (untrop y)) :=
  rfl
#align tropical.trop_add_def Tropical.trop_add_def

instance : LinearOrder (Tropical R) :=
  {
    Tropical.partialOrder with
    le_total := fun a b => le_total (untrop a) (untrop b)
    decidableLe := Tropical.decidableLE
    decidableLt := Tropical.decidableLT
    DecidableEq := Tropical.decidableEq
    max := fun a b => trop (max (untrop a) (untrop b))
    max_def := by
      ext (x y)
      rw [maxDefault, max_def, apply_ite trop, trop_untrop, trop_untrop,
        if_congr untrop_le_iff rfl rfl]
    min := (· + ·)
    min_def := by
      ext (x y)
      rw [trop_add_def, minDefault, min_def, apply_ite trop, trop_untrop, trop_untrop,
        if_congr untrop_le_iff rfl rfl] }

/- warning: tropical.untrop_sup -> Tropical.untrop_sup is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] (x : Tropical.{u1} R) (y : Tropical.{u1} R), Eq.{succ u1} R (Tropical.untrop.{u1} R (Sup.sup.{u1} (Tropical.{u1} R) (SemilatticeSup.toHasSup.{u1} (Tropical.{u1} R) (Lattice.toSemilatticeSup.{u1} (Tropical.{u1} R) (LinearOrder.toLattice.{u1} (Tropical.{u1} R) (Tropical.linearOrder.{u1} R _inst_1)))) x y)) (Sup.sup.{u1} R (SemilatticeSup.toHasSup.{u1} R (Lattice.toSemilatticeSup.{u1} R (LinearOrder.toLattice.{u1} R _inst_1))) (Tropical.untrop.{u1} R x) (Tropical.untrop.{u1} R y))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] (x : Tropical.{u1} R) (y : Tropical.{u1} R), Eq.{succ u1} R (Tropical.untrop.{u1} R (Sup.sup.{u1} (Tropical.{u1} R) (SemilatticeSup.toSup.{u1} (Tropical.{u1} R) (Lattice.toSemilatticeSup.{u1} (Tropical.{u1} R) (DistribLattice.toLattice.{u1} (Tropical.{u1} R) (instDistribLattice.{u1} (Tropical.{u1} R) (Tropical.instLinearOrderTropical.{u1} R _inst_1))))) x y)) (Sup.sup.{u1} R (SemilatticeSup.toSup.{u1} R (Lattice.toSemilatticeSup.{u1} R (DistribLattice.toLattice.{u1} R (instDistribLattice.{u1} R _inst_1)))) (Tropical.untrop.{u1} R x) (Tropical.untrop.{u1} R y))
Case conversion may be inaccurate. Consider using '#align tropical.untrop_sup Tropical.untrop_supₓ'. -/
@[simp]
theorem untrop_sup (x y : Tropical R) : untrop (x ⊔ y) = untrop x ⊔ untrop y :=
  rfl
#align tropical.untrop_sup Tropical.untrop_sup

/- warning: tropical.untrop_max -> Tropical.untrop_max is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] (x : Tropical.{u1} R) (y : Tropical.{u1} R), Eq.{succ u1} R (Tropical.untrop.{u1} R (LinearOrder.max.{u1} (Tropical.{u1} R) (Tropical.linearOrder.{u1} R _inst_1) x y)) (LinearOrder.max.{u1} R _inst_1 (Tropical.untrop.{u1} R x) (Tropical.untrop.{u1} R y))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] (x : Tropical.{u1} R) (y : Tropical.{u1} R), Eq.{succ u1} R (Tropical.untrop.{u1} R (Max.max.{u1} (Tropical.{u1} R) (LinearOrder.toMax.{u1} (Tropical.{u1} R) (Tropical.instLinearOrderTropical.{u1} R _inst_1)) x y)) (Max.max.{u1} R (LinearOrder.toMax.{u1} R _inst_1) (Tropical.untrop.{u1} R x) (Tropical.untrop.{u1} R y))
Case conversion may be inaccurate. Consider using '#align tropical.untrop_max Tropical.untrop_maxₓ'. -/
@[simp]
theorem untrop_max (x y : Tropical R) : untrop (max x y) = max (untrop x) (untrop y) :=
  rfl
#align tropical.untrop_max Tropical.untrop_max

/- warning: tropical.min_eq_add -> Tropical.min_eq_add is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R], Eq.{succ u1} ((Tropical.{u1} R) -> (Tropical.{u1} R) -> (Tropical.{u1} R)) (LinearOrder.min.{u1} (Tropical.{u1} R) (Tropical.linearOrder.{u1} R _inst_1)) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.hasAdd.{u1} R _inst_1)))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R], Eq.{succ u1} ((Tropical.{u1} R) -> (Tropical.{u1} R) -> (Tropical.{u1} R)) (Min.min.{u1} (Tropical.{u1} R) (LinearOrder.toMin.{u1} (Tropical.{u1} R) (Tropical.instLinearOrderTropical.{u1} R _inst_1))) (fun (x._@.Mathlib.Algebra.Tropical.Basic._hyg.1534 : Tropical.{u1} R) (x._@.Mathlib.Algebra.Tropical.Basic._hyg.1536 : Tropical.{u1} R) => HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.instAddTropical.{u1} R _inst_1)) x._@.Mathlib.Algebra.Tropical.Basic._hyg.1534 x._@.Mathlib.Algebra.Tropical.Basic._hyg.1536)
Case conversion may be inaccurate. Consider using '#align tropical.min_eq_add Tropical.min_eq_addₓ'. -/
@[simp]
theorem min_eq_add : (min : Tropical R → Tropical R → Tropical R) = (· + ·) :=
  rfl
#align tropical.min_eq_add Tropical.min_eq_add

/- warning: tropical.inf_eq_add -> Tropical.inf_eq_add is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R], Eq.{succ u1} ((Tropical.{u1} R) -> (Tropical.{u1} R) -> (Tropical.{u1} R)) (Inf.inf.{u1} (Tropical.{u1} R) (SemilatticeInf.toHasInf.{u1} (Tropical.{u1} R) (Lattice.toSemilatticeInf.{u1} (Tropical.{u1} R) (LinearOrder.toLattice.{u1} (Tropical.{u1} R) (Tropical.linearOrder.{u1} R _inst_1))))) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.hasAdd.{u1} R _inst_1)))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R], Eq.{succ u1} ((Tropical.{u1} R) -> (Tropical.{u1} R) -> (Tropical.{u1} R)) (fun (x._@.Mathlib.Algebra.Tropical.Basic._hyg.1570 : Tropical.{u1} R) (x._@.Mathlib.Algebra.Tropical.Basic._hyg.1572 : Tropical.{u1} R) => Inf.inf.{u1} (Tropical.{u1} R) (Lattice.toInf.{u1} (Tropical.{u1} R) (DistribLattice.toLattice.{u1} (Tropical.{u1} R) (instDistribLattice.{u1} (Tropical.{u1} R) (Tropical.instLinearOrderTropical.{u1} R _inst_1)))) x._@.Mathlib.Algebra.Tropical.Basic._hyg.1570 x._@.Mathlib.Algebra.Tropical.Basic._hyg.1572) (fun (x._@.Mathlib.Algebra.Tropical.Basic._hyg.1585 : Tropical.{u1} R) (x._@.Mathlib.Algebra.Tropical.Basic._hyg.1587 : Tropical.{u1} R) => HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.instAddTropical.{u1} R _inst_1)) x._@.Mathlib.Algebra.Tropical.Basic._hyg.1585 x._@.Mathlib.Algebra.Tropical.Basic._hyg.1587)
Case conversion may be inaccurate. Consider using '#align tropical.inf_eq_add Tropical.inf_eq_addₓ'. -/
@[simp]
theorem inf_eq_add : ((· ⊓ ·) : Tropical R → Tropical R → Tropical R) = (· + ·) :=
  rfl
#align tropical.inf_eq_add Tropical.inf_eq_add

/- warning: tropical.trop_max_def -> Tropical.trop_max_def is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] (x : Tropical.{u1} R) (y : Tropical.{u1} R), Eq.{succ u1} (Tropical.{u1} R) (LinearOrder.max.{u1} (Tropical.{u1} R) (Tropical.linearOrder.{u1} R _inst_1) x y) (Tropical.trop.{u1} R (LinearOrder.max.{u1} R _inst_1 (Tropical.untrop.{u1} R x) (Tropical.untrop.{u1} R y)))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] (x : Tropical.{u1} R) (y : Tropical.{u1} R), Eq.{succ u1} (Tropical.{u1} R) (Max.max.{u1} (Tropical.{u1} R) (LinearOrder.toMax.{u1} (Tropical.{u1} R) (Tropical.instLinearOrderTropical.{u1} R _inst_1)) x y) (Tropical.trop.{u1} R (Max.max.{u1} R (LinearOrder.toMax.{u1} R _inst_1) (Tropical.untrop.{u1} R x) (Tropical.untrop.{u1} R y)))
Case conversion may be inaccurate. Consider using '#align tropical.trop_max_def Tropical.trop_max_defₓ'. -/
theorem trop_max_def (x y : Tropical R) : max x y = trop (max (untrop x) (untrop y)) :=
  rfl
#align tropical.trop_max_def Tropical.trop_max_def

/- warning: tropical.trop_sup_def -> Tropical.trop_sup_def is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] (x : Tropical.{u1} R) (y : Tropical.{u1} R), Eq.{succ u1} (Tropical.{u1} R) (Sup.sup.{u1} (Tropical.{u1} R) (SemilatticeSup.toHasSup.{u1} (Tropical.{u1} R) (Lattice.toSemilatticeSup.{u1} (Tropical.{u1} R) (LinearOrder.toLattice.{u1} (Tropical.{u1} R) (Tropical.linearOrder.{u1} R _inst_1)))) x y) (Tropical.trop.{u1} R (Sup.sup.{u1} R (SemilatticeSup.toHasSup.{u1} R (Lattice.toSemilatticeSup.{u1} R (LinearOrder.toLattice.{u1} R _inst_1))) (Tropical.untrop.{u1} R x) (Tropical.untrop.{u1} R y)))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] (x : Tropical.{u1} R) (y : Tropical.{u1} R), Eq.{succ u1} (Tropical.{u1} R) (Sup.sup.{u1} (Tropical.{u1} R) (SemilatticeSup.toSup.{u1} (Tropical.{u1} R) (Lattice.toSemilatticeSup.{u1} (Tropical.{u1} R) (DistribLattice.toLattice.{u1} (Tropical.{u1} R) (instDistribLattice.{u1} (Tropical.{u1} R) (Tropical.instLinearOrderTropical.{u1} R _inst_1))))) x y) (Tropical.trop.{u1} R (Sup.sup.{u1} R (SemilatticeSup.toSup.{u1} R (Lattice.toSemilatticeSup.{u1} R (DistribLattice.toLattice.{u1} R (instDistribLattice.{u1} R _inst_1)))) (Tropical.untrop.{u1} R x) (Tropical.untrop.{u1} R y)))
Case conversion may be inaccurate. Consider using '#align tropical.trop_sup_def Tropical.trop_sup_defₓ'. -/
theorem trop_sup_def (x y : Tropical R) : x ⊔ y = trop (untrop x ⊔ untrop y) :=
  rfl
#align tropical.trop_sup_def Tropical.trop_sup_def

/- warning: tropical.add_eq_left -> Tropical.add_eq_left is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] {{x : Tropical.{u1} R}} {{y : Tropical.{u1} R}}, (LE.le.{u1} (Tropical.{u1} R) (Tropical.hasLe.{u1} R (Preorder.toLE.{u1} R (PartialOrder.toPreorder.{u1} R (SemilatticeInf.toPartialOrder.{u1} R (Lattice.toSemilatticeInf.{u1} R (LinearOrder.toLattice.{u1} R _inst_1)))))) x y) -> (Eq.{succ u1} (Tropical.{u1} R) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.hasAdd.{u1} R _inst_1)) x y) x)
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] {{x : Tropical.{u1} R}} {{y : Tropical.{u1} R}}, (LE.le.{u1} (Tropical.{u1} R) (Tropical.instLETropical.{u1} R (Preorder.toLE.{u1} R (PartialOrder.toPreorder.{u1} R (SemilatticeInf.toPartialOrder.{u1} R (Lattice.toSemilatticeInf.{u1} R (DistribLattice.toLattice.{u1} R (instDistribLattice.{u1} R _inst_1))))))) x y) -> (Eq.{succ u1} (Tropical.{u1} R) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.instAddTropical.{u1} R _inst_1)) x y) x)
Case conversion may be inaccurate. Consider using '#align tropical.add_eq_left Tropical.add_eq_leftₓ'. -/
@[simp]
theorem add_eq_left ⦃x y : Tropical R⦄ (h : x ≤ y) : x + y = x :=
  untrop_injective (by simpa using h)
#align tropical.add_eq_left Tropical.add_eq_left

/- warning: tropical.add_eq_right -> Tropical.add_eq_right is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] {{x : Tropical.{u1} R}} {{y : Tropical.{u1} R}}, (LE.le.{u1} (Tropical.{u1} R) (Tropical.hasLe.{u1} R (Preorder.toLE.{u1} R (PartialOrder.toPreorder.{u1} R (SemilatticeInf.toPartialOrder.{u1} R (Lattice.toSemilatticeInf.{u1} R (LinearOrder.toLattice.{u1} R _inst_1)))))) y x) -> (Eq.{succ u1} (Tropical.{u1} R) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.hasAdd.{u1} R _inst_1)) x y) y)
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] {{x : Tropical.{u1} R}} {{y : Tropical.{u1} R}}, (LE.le.{u1} (Tropical.{u1} R) (Tropical.instLETropical.{u1} R (Preorder.toLE.{u1} R (PartialOrder.toPreorder.{u1} R (SemilatticeInf.toPartialOrder.{u1} R (Lattice.toSemilatticeInf.{u1} R (DistribLattice.toLattice.{u1} R (instDistribLattice.{u1} R _inst_1))))))) y x) -> (Eq.{succ u1} (Tropical.{u1} R) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.instAddTropical.{u1} R _inst_1)) x y) y)
Case conversion may be inaccurate. Consider using '#align tropical.add_eq_right Tropical.add_eq_rightₓ'. -/
@[simp]
theorem add_eq_right ⦃x y : Tropical R⦄ (h : y ≤ x) : x + y = y :=
  untrop_injective (by simpa using h)
#align tropical.add_eq_right Tropical.add_eq_right

/- warning: tropical.add_eq_left_iff -> Tropical.add_eq_left_iff is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] {x : Tropical.{u1} R} {y : Tropical.{u1} R}, Iff (Eq.{succ u1} (Tropical.{u1} R) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.hasAdd.{u1} R _inst_1)) x y) x) (LE.le.{u1} (Tropical.{u1} R) (Tropical.hasLe.{u1} R (Preorder.toLE.{u1} R (PartialOrder.toPreorder.{u1} R (SemilatticeInf.toPartialOrder.{u1} R (Lattice.toSemilatticeInf.{u1} R (LinearOrder.toLattice.{u1} R _inst_1)))))) x y)
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] {x : Tropical.{u1} R} {y : Tropical.{u1} R}, Iff (Eq.{succ u1} (Tropical.{u1} R) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.instAddTropical.{u1} R _inst_1)) x y) x) (LE.le.{u1} (Tropical.{u1} R) (Tropical.instLETropical.{u1} R (Preorder.toLE.{u1} R (PartialOrder.toPreorder.{u1} R (SemilatticeInf.toPartialOrder.{u1} R (Lattice.toSemilatticeInf.{u1} R (DistribLattice.toLattice.{u1} R (instDistribLattice.{u1} R _inst_1))))))) x y)
Case conversion may be inaccurate. Consider using '#align tropical.add_eq_left_iff Tropical.add_eq_left_iffₓ'. -/
theorem add_eq_left_iff {x y : Tropical R} : x + y = x ↔ x ≤ y := by
  rw [trop_add_def, trop_eq_iff_eq_untrop, ← untrop_le_iff, min_eq_left_iff]
#align tropical.add_eq_left_iff Tropical.add_eq_left_iff

/- warning: tropical.add_eq_right_iff -> Tropical.add_eq_right_iff is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] {x : Tropical.{u1} R} {y : Tropical.{u1} R}, Iff (Eq.{succ u1} (Tropical.{u1} R) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.hasAdd.{u1} R _inst_1)) x y) y) (LE.le.{u1} (Tropical.{u1} R) (Tropical.hasLe.{u1} R (Preorder.toLE.{u1} R (PartialOrder.toPreorder.{u1} R (SemilatticeInf.toPartialOrder.{u1} R (Lattice.toSemilatticeInf.{u1} R (LinearOrder.toLattice.{u1} R _inst_1)))))) y x)
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] {x : Tropical.{u1} R} {y : Tropical.{u1} R}, Iff (Eq.{succ u1} (Tropical.{u1} R) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.instAddTropical.{u1} R _inst_1)) x y) y) (LE.le.{u1} (Tropical.{u1} R) (Tropical.instLETropical.{u1} R (Preorder.toLE.{u1} R (PartialOrder.toPreorder.{u1} R (SemilatticeInf.toPartialOrder.{u1} R (Lattice.toSemilatticeInf.{u1} R (DistribLattice.toLattice.{u1} R (instDistribLattice.{u1} R _inst_1))))))) y x)
Case conversion may be inaccurate. Consider using '#align tropical.add_eq_right_iff Tropical.add_eq_right_iffₓ'. -/
theorem add_eq_right_iff {x y : Tropical R} : x + y = y ↔ y ≤ x := by
  rw [trop_add_def, trop_eq_iff_eq_untrop, ← untrop_le_iff, min_eq_right_iff]
#align tropical.add_eq_right_iff Tropical.add_eq_right_iff

/- warning: tropical.add_self -> Tropical.add_self is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] (x : Tropical.{u1} R), Eq.{succ u1} (Tropical.{u1} R) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.hasAdd.{u1} R _inst_1)) x x) x
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] (x : Tropical.{u1} R), Eq.{succ u1} (Tropical.{u1} R) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.instAddTropical.{u1} R _inst_1)) x x) x
Case conversion may be inaccurate. Consider using '#align tropical.add_self Tropical.add_selfₓ'. -/
@[simp]
theorem add_self (x : Tropical R) : x + x = x :=
  untrop_injective (min_eq_right le_rfl)
#align tropical.add_self Tropical.add_self

/- warning: tropical.bit0 -> Tropical.bit0 is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] (x : Tropical.{u1} R), Eq.{succ u1} (Tropical.{u1} R) (bit0.{u1} (Tropical.{u1} R) (Tropical.hasAdd.{u1} R _inst_1) x) x
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] (x : Tropical.{u1} R), Eq.{succ u1} (Tropical.{u1} R) (bit0.{u1} (Tropical.{u1} R) (Tropical.instAddTropical.{u1} R _inst_1) x) x
Case conversion may be inaccurate. Consider using '#align tropical.bit0 Tropical.bit0ₓ'. -/
@[simp]
theorem bit0 (x : Tropical R) : bit0 x = x :=
  add_self x
#align tropical.bit0 Tropical.bit0

/- warning: tropical.add_eq_iff -> Tropical.add_eq_iff is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] {x : Tropical.{u1} R} {y : Tropical.{u1} R} {z : Tropical.{u1} R}, Iff (Eq.{succ u1} (Tropical.{u1} R) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.hasAdd.{u1} R _inst_1)) x y) z) (Or (And (Eq.{succ u1} (Tropical.{u1} R) x z) (LE.le.{u1} (Tropical.{u1} R) (Tropical.hasLe.{u1} R (Preorder.toLE.{u1} R (PartialOrder.toPreorder.{u1} R (SemilatticeInf.toPartialOrder.{u1} R (Lattice.toSemilatticeInf.{u1} R (LinearOrder.toLattice.{u1} R _inst_1)))))) x y)) (And (Eq.{succ u1} (Tropical.{u1} R) y z) (LE.le.{u1} (Tropical.{u1} R) (Tropical.hasLe.{u1} R (Preorder.toLE.{u1} R (PartialOrder.toPreorder.{u1} R (SemilatticeInf.toPartialOrder.{u1} R (Lattice.toSemilatticeInf.{u1} R (LinearOrder.toLattice.{u1} R _inst_1)))))) y x)))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] {x : Tropical.{u1} R} {y : Tropical.{u1} R} {z : Tropical.{u1} R}, Iff (Eq.{succ u1} (Tropical.{u1} R) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.instAddTropical.{u1} R _inst_1)) x y) z) (Or (And (Eq.{succ u1} (Tropical.{u1} R) x z) (LE.le.{u1} (Tropical.{u1} R) (Tropical.instLETropical.{u1} R (Preorder.toLE.{u1} R (PartialOrder.toPreorder.{u1} R (SemilatticeInf.toPartialOrder.{u1} R (Lattice.toSemilatticeInf.{u1} R (DistribLattice.toLattice.{u1} R (instDistribLattice.{u1} R _inst_1))))))) x y)) (And (Eq.{succ u1} (Tropical.{u1} R) y z) (LE.le.{u1} (Tropical.{u1} R) (Tropical.instLETropical.{u1} R (Preorder.toLE.{u1} R (PartialOrder.toPreorder.{u1} R (SemilatticeInf.toPartialOrder.{u1} R (Lattice.toSemilatticeInf.{u1} R (DistribLattice.toLattice.{u1} R (instDistribLattice.{u1} R _inst_1))))))) y x)))
Case conversion may be inaccurate. Consider using '#align tropical.add_eq_iff Tropical.add_eq_iffₓ'. -/
theorem add_eq_iff {x y z : Tropical R} : x + y = z ↔ x = z ∧ x ≤ y ∨ y = z ∧ y ≤ x :=
  by
  rw [trop_add_def, trop_eq_iff_eq_untrop]
  simp [min_eq_iff]
#align tropical.add_eq_iff Tropical.add_eq_iff

/- warning: tropical.add_eq_zero_iff -> Tropical.add_eq_zero_iff is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] {a : Tropical.{u1} (WithTop.{u1} R)} {b : Tropical.{u1} (WithTop.{u1} R)}, Iff (Eq.{succ u1} (Tropical.{u1} (WithTop.{u1} R)) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} (WithTop.{u1} R)) (Tropical.{u1} (WithTop.{u1} R)) (Tropical.{u1} (WithTop.{u1} R)) (instHAdd.{u1} (Tropical.{u1} (WithTop.{u1} R)) (Tropical.hasAdd.{u1} (WithTop.{u1} R) (WithTop.linearOrder.{u1} R _inst_1))) a b) (OfNat.ofNat.{u1} (Tropical.{u1} (WithTop.{u1} R)) 0 (OfNat.mk.{u1} (Tropical.{u1} (WithTop.{u1} R)) 0 (Zero.zero.{u1} (Tropical.{u1} (WithTop.{u1} R)) (Tropical.hasZero.{u1} (WithTop.{u1} R) (WithTop.hasTop.{u1} R)))))) (And (Eq.{succ u1} (Tropical.{u1} (WithTop.{u1} R)) a (OfNat.ofNat.{u1} (Tropical.{u1} (WithTop.{u1} R)) 0 (OfNat.mk.{u1} (Tropical.{u1} (WithTop.{u1} R)) 0 (Zero.zero.{u1} (Tropical.{u1} (WithTop.{u1} R)) (Tropical.hasZero.{u1} (WithTop.{u1} R) (WithTop.hasTop.{u1} R)))))) (Eq.{succ u1} (Tropical.{u1} (WithTop.{u1} R)) b (OfNat.ofNat.{u1} (Tropical.{u1} (WithTop.{u1} R)) 0 (OfNat.mk.{u1} (Tropical.{u1} (WithTop.{u1} R)) 0 (Zero.zero.{u1} (Tropical.{u1} (WithTop.{u1} R)) (Tropical.hasZero.{u1} (WithTop.{u1} R) (WithTop.hasTop.{u1} R)))))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] {a : Tropical.{u1} (WithTop.{u1} R)} {b : Tropical.{u1} (WithTop.{u1} R)}, Iff (Eq.{succ u1} (Tropical.{u1} (WithTop.{u1} R)) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} (WithTop.{u1} R)) (Tropical.{u1} (WithTop.{u1} R)) (Tropical.{u1} (WithTop.{u1} R)) (instHAdd.{u1} (Tropical.{u1} (WithTop.{u1} R)) (Tropical.instAddTropical.{u1} (WithTop.{u1} R) (WithTop.linearOrder.{u1} R _inst_1))) a b) (OfNat.ofNat.{u1} (Tropical.{u1} (WithTop.{u1} R)) 0 (Zero.toOfNat0.{u1} (Tropical.{u1} (WithTop.{u1} R)) (Tropical.instZeroTropical.{u1} (WithTop.{u1} R) (WithTop.top.{u1} R))))) (And (Eq.{succ u1} (Tropical.{u1} (WithTop.{u1} R)) a (OfNat.ofNat.{u1} (Tropical.{u1} (WithTop.{u1} R)) 0 (Zero.toOfNat0.{u1} (Tropical.{u1} (WithTop.{u1} R)) (Tropical.instZeroTropical.{u1} (WithTop.{u1} R) (WithTop.top.{u1} R))))) (Eq.{succ u1} (Tropical.{u1} (WithTop.{u1} R)) b (OfNat.ofNat.{u1} (Tropical.{u1} (WithTop.{u1} R)) 0 (Zero.toOfNat0.{u1} (Tropical.{u1} (WithTop.{u1} R)) (Tropical.instZeroTropical.{u1} (WithTop.{u1} R) (WithTop.top.{u1} R))))))
Case conversion may be inaccurate. Consider using '#align tropical.add_eq_zero_iff Tropical.add_eq_zero_iffₓ'. -/
@[simp]
theorem add_eq_zero_iff {a b : Tropical (WithTop R)} : a + b = 0 ↔ a = 0 ∧ b = 0 :=
  by
  rw [add_eq_iff]
  constructor
  · rintro (⟨rfl, h⟩ | ⟨rfl, h⟩)
    · exact ⟨rfl, le_antisymm (le_zero _) h⟩
    · exact ⟨le_antisymm (le_zero _) h, rfl⟩
  · rintro ⟨rfl, rfl⟩
    simp
#align tropical.add_eq_zero_iff Tropical.add_eq_zero_iff

instance [OrderTop R] : AddCommMonoid (Tropical R) :=
  { Tropical.hasZero,
    Tropical.addCommSemigroup with
    zero_add := fun _ => untrop_injective (min_top_left _)
    add_zero := fun _ => untrop_injective (min_top_right _) }

end Order

section Monoid

/-- Tropical multiplication is the addition in the underlying `R`. -/
instance [Add R] : Mul (Tropical R) :=
  ⟨fun x y => trop (untrop x + untrop y)⟩

#print Tropical.trop_add /-
@[simp]
theorem trop_add [Add R] (x y : R) : trop (x + y) = trop x * trop y :=
  rfl
#align tropical.trop_add Tropical.trop_add
-/

#print Tropical.untrop_mul /-
@[simp]
theorem untrop_mul [Add R] (x y : Tropical R) : untrop (x * y) = untrop x + untrop y :=
  rfl
#align tropical.untrop_mul Tropical.untrop_mul
-/

#print Tropical.trop_mul_def /-
theorem trop_mul_def [Add R] (x y : Tropical R) : x * y = trop (untrop x + untrop y) :=
  rfl
#align tropical.trop_mul_def Tropical.trop_mul_def
-/

instance [Zero R] : One (Tropical R) :=
  ⟨trop 0⟩

#print Tropical.trop_zero /-
@[simp]
theorem trop_zero [Zero R] : trop (0 : R) = 1 :=
  rfl
#align tropical.trop_zero Tropical.trop_zero
-/

#print Tropical.untrop_one /-
@[simp]
theorem untrop_one [Zero R] : untrop (1 : Tropical R) = 0 :=
  rfl
#align tropical.untrop_one Tropical.untrop_one
-/

instance [LinearOrder R] [OrderTop R] [Zero R] : AddMonoidWithOne (Tropical R) :=
  { Tropical.hasOne,
    Tropical.addCommMonoid with
    natCast := fun n => if n = 0 then 0 else 1
    natCast_zero := rfl
    natCast_succ := fun n => (untrop_inj_iff _ _).1 (by cases n <;> simp [Nat.cast]) }

instance [Zero R] : Nontrivial (Tropical (WithTop R)) :=
  ⟨⟨0, 1, trop_injective.Ne WithTop.top_ne_coe⟩⟩

instance [Neg R] : Inv (Tropical R) :=
  ⟨fun x => trop (-untrop x)⟩

#print Tropical.untrop_inv /-
@[simp]
theorem untrop_inv [Neg R] (x : Tropical R) : untrop x⁻¹ = -untrop x :=
  rfl
#align tropical.untrop_inv Tropical.untrop_inv
-/

instance [Sub R] : Div (Tropical R) :=
  ⟨fun x y => trop (untrop x - untrop y)⟩

#print Tropical.untrop_div /-
@[simp]
theorem untrop_div [Sub R] (x y : Tropical R) : untrop (x / y) = untrop x - untrop y :=
  rfl
#align tropical.untrop_div Tropical.untrop_div
-/

instance [AddSemigroup R] : Semigroup (Tropical R)
    where
  mul := (· * ·)
  mul_assoc _ _ _ := untrop_injective (add_assoc _ _ _)

instance [AddCommSemigroup R] : CommSemigroup (Tropical R) :=
  { Tropical.semigroup with mul_comm := fun _ _ => untrop_injective (add_comm _ _) }

instance {α : Type _} [SMul α R] : Pow (Tropical R) α where pow x n := trop <| n • untrop x

/- warning: tropical.untrop_pow -> Tropical.untrop_pow is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {α : Type.{u2}} [_inst_1 : SMul.{u2, u1} α R] (x : Tropical.{u1} R) (n : α), Eq.{succ u1} R (Tropical.untrop.{u1} R (HPow.hPow.{u1, u2, u1} (Tropical.{u1} R) α (Tropical.{u1} R) (instHPow.{u1, u2} (Tropical.{u1} R) α (Tropical.hasPow.{u1, u2} R α _inst_1)) x n)) (SMul.smul.{u2, u1} α R _inst_1 n (Tropical.untrop.{u1} R x))
but is expected to have type
  forall {R : Type.{u2}} {α : Type.{u1}} [_inst_1 : SMul.{u1, u2} α R] (x : Tropical.{u2} R) (n : α), Eq.{succ u2} R (Tropical.untrop.{u2} R (HPow.hPow.{u2, u1, u2} (Tropical.{u2} R) α (Tropical.{u2} R) (instHPow.{u2, u1} (Tropical.{u2} R) α (Tropical.instPowTropical.{u2, u1} R α _inst_1)) x n)) (HSMul.hSMul.{u1, u2, u2} α R R (instHSMul.{u1, u2} α R _inst_1) n (Tropical.untrop.{u2} R x))
Case conversion may be inaccurate. Consider using '#align tropical.untrop_pow Tropical.untrop_powₓ'. -/
@[simp]
theorem untrop_pow {α : Type _} [SMul α R] (x : Tropical R) (n : α) :
    untrop (x ^ n) = n • untrop x :=
  rfl
#align tropical.untrop_pow Tropical.untrop_pow

/- warning: tropical.trop_smul -> Tropical.trop_smul is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {α : Type.{u2}} [_inst_1 : SMul.{u2, u1} α R] (x : R) (n : α), Eq.{succ u1} (Tropical.{u1} R) (Tropical.trop.{u1} R (SMul.smul.{u2, u1} α R _inst_1 n x)) (HPow.hPow.{u1, u2, u1} (Tropical.{u1} R) α (Tropical.{u1} R) (instHPow.{u1, u2} (Tropical.{u1} R) α (Tropical.hasPow.{u1, u2} R α _inst_1)) (Tropical.trop.{u1} R x) n)
but is expected to have type
  forall {R : Type.{u2}} {α : Type.{u1}} [_inst_1 : SMul.{u1, u2} α R] (x : R) (n : α), Eq.{succ u2} (Tropical.{u2} R) (Tropical.trop.{u2} R (HSMul.hSMul.{u1, u2, u2} α R R (instHSMul.{u1, u2} α R _inst_1) n x)) (HPow.hPow.{u2, u1, u2} (Tropical.{u2} R) α (Tropical.{u2} R) (instHPow.{u2, u1} (Tropical.{u2} R) α (Tropical.instPowTropical.{u2, u1} R α _inst_1)) (Tropical.trop.{u2} R x) n)
Case conversion may be inaccurate. Consider using '#align tropical.trop_smul Tropical.trop_smulₓ'. -/
@[simp]
theorem trop_smul {α : Type _} [SMul α R] (x : R) (n : α) : trop (n • x) = trop x ^ n :=
  rfl
#align tropical.trop_smul Tropical.trop_smul

instance [AddZeroClass R] : MulOneClass (Tropical R)
    where
  one := 1
  mul := (· * ·)
  one_mul _ := untrop_injective <| zero_add _
  mul_one _ := untrop_injective <| add_zero _

instance [AddMonoid R] : Monoid (Tropical R) :=
  { Tropical.mulOneClass,
    Tropical.semigroup with
    npow := fun n x => x ^ n
    npow_zero := fun _ => untrop_injective <| zero_smul _ _
    npow_succ := fun _ _ => untrop_injective <| succ_nsmul _ _ }

#print Tropical.trop_nsmul /-
@[simp]
theorem trop_nsmul [AddMonoid R] (x : R) (n : ℕ) : trop (n • x) = trop x ^ n :=
  rfl
#align tropical.trop_nsmul Tropical.trop_nsmul
-/

instance [AddCommMonoid R] : CommMonoid (Tropical R) :=
  { Tropical.monoid, Tropical.commSemigroup with }

instance [AddGroup R] : Group (Tropical R) :=
  { Tropical.monoid with
    inv := Inv.inv
    mul_left_inv := fun _ => untrop_injective <| add_left_neg _
    zpow := fun n x => trop <| n • untrop x
    zpow_zero' := fun _ => untrop_injective <| zero_zsmul _
    zpow_succ' := fun _ _ => untrop_injective <| AddGroup.zsmul_succ' _ _
    zpow_neg' := fun _ _ => untrop_injective <| AddGroup.zsmul_neg' _ _ }

instance [AddCommGroup R] : CommGroup (Tropical R) :=
  { Tropical.group with mul_comm := fun _ _ => untrop_injective (add_comm _ _) }

#print Tropical.untrop_zpow /-
@[simp]
theorem untrop_zpow [AddGroup R] (x : Tropical R) (n : ℤ) : untrop (x ^ n) = n • untrop x :=
  rfl
#align tropical.untrop_zpow Tropical.untrop_zpow
-/

#print Tropical.trop_zsmul /-
@[simp]
theorem trop_zsmul [AddGroup R] (x : R) (n : ℤ) : trop (n • x) = trop x ^ n :=
  rfl
#align tropical.trop_zsmul Tropical.trop_zsmul
-/

end Monoid

section Distrib

#print Tropical.covariant_mul /-
instance covariant_mul [LE R] [Add R] [CovariantClass R R (· + ·) (· ≤ ·)] :
    CovariantClass (Tropical R) (Tropical R) (· * ·) (· ≤ ·) :=
  ⟨fun x y z h => add_le_add_left h _⟩
#align tropical.covariant_mul Tropical.covariant_mul
-/

#print Tropical.covariant_swap_mul /-
instance covariant_swap_mul [LE R] [Add R] [CovariantClass R R (Function.swap (· + ·)) (· ≤ ·)] :
    CovariantClass (Tropical R) (Tropical R) (Function.swap (· * ·)) (· ≤ ·) :=
  ⟨fun x y z h => add_le_add_right h _⟩
#align tropical.covariant_swap_mul Tropical.covariant_swap_mul
-/

/- warning: tropical.covariant_add -> Tropical.covariant_add is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R], CovariantClass.{u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.hasAdd.{u1} R _inst_1))) (LE.le.{u1} (Tropical.{u1} R) (Tropical.hasLe.{u1} R (Preorder.toLE.{u1} R (PartialOrder.toPreorder.{u1} R (SemilatticeInf.toPartialOrder.{u1} R (Lattice.toSemilatticeInf.{u1} R (LinearOrder.toLattice.{u1} R _inst_1)))))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R], CovariantClass.{u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (fun (x._@.Mathlib.Algebra.Tropical.Basic._hyg.3331 : Tropical.{u1} R) (x._@.Mathlib.Algebra.Tropical.Basic._hyg.3333 : Tropical.{u1} R) => HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.instAddTropical.{u1} R _inst_1)) x._@.Mathlib.Algebra.Tropical.Basic._hyg.3331 x._@.Mathlib.Algebra.Tropical.Basic._hyg.3333) (fun (x._@.Mathlib.Algebra.Tropical.Basic._hyg.3346 : Tropical.{u1} R) (x._@.Mathlib.Algebra.Tropical.Basic._hyg.3348 : Tropical.{u1} R) => LE.le.{u1} (Tropical.{u1} R) (Tropical.instLETropical.{u1} R (Preorder.toLE.{u1} R (PartialOrder.toPreorder.{u1} R (SemilatticeInf.toPartialOrder.{u1} R (Lattice.toSemilatticeInf.{u1} R (DistribLattice.toLattice.{u1} R (instDistribLattice.{u1} R _inst_1))))))) x._@.Mathlib.Algebra.Tropical.Basic._hyg.3346 x._@.Mathlib.Algebra.Tropical.Basic._hyg.3348)
Case conversion may be inaccurate. Consider using '#align tropical.covariant_add Tropical.covariant_addₓ'. -/
instance covariant_add [LinearOrder R] : CovariantClass (Tropical R) (Tropical R) (· + ·) (· ≤ ·) :=
  ⟨fun x y z h => by
    cases' le_total x y with hx hy
    · rw [add_eq_left hx, add_eq_left (hx.trans h)]
    · rw [add_eq_right hy]
      cases' le_total x z with hx hx
      · rwa [add_eq_left hx]
      · rwa [add_eq_right hx]⟩
#align tropical.covariant_add Tropical.covariant_add

#print Tropical.covariant_mul_lt /-
instance covariant_mul_lt [LT R] [Add R] [CovariantClass R R (· + ·) (· < ·)] :
    CovariantClass (Tropical R) (Tropical R) (· * ·) (· < ·) :=
  ⟨fun x y z h => add_lt_add_left h _⟩
#align tropical.covariant_mul_lt Tropical.covariant_mul_lt
-/

#print Tropical.covariant_swap_mul_lt /-
instance covariant_swap_mul_lt [Preorder R] [Add R]
    [CovariantClass R R (Function.swap (· + ·)) (· < ·)] :
    CovariantClass (Tropical R) (Tropical R) (Function.swap (· * ·)) (· < ·) :=
  ⟨fun x y z h => add_lt_add_right h _⟩
#align tropical.covariant_swap_mul_lt Tropical.covariant_swap_mul_lt
-/

instance [LinearOrder R] [Add R] [CovariantClass R R (· + ·) (· ≤ ·)]
    [CovariantClass R R (Function.swap (· + ·)) (· ≤ ·)] : Distrib (Tropical R)
    where
  mul := (· * ·)
  add := (· + ·)
  left_distrib _ _ _ := untrop_injective (min_add_add_left _ _ _).symm
  right_distrib _ _ _ := untrop_injective (min_add_add_right _ _ _).symm

/- warning: tropical.add_pow -> Tropical.add_pow is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] [_inst_2 : AddMonoid.{u1} R] [_inst_3 : CovariantClass.{u1, u1} R R (HAdd.hAdd.{u1, u1, u1} R R R (instHAdd.{u1} R (AddZeroClass.toHasAdd.{u1} R (AddMonoid.toAddZeroClass.{u1} R _inst_2)))) (LE.le.{u1} R (Preorder.toLE.{u1} R (PartialOrder.toPreorder.{u1} R (SemilatticeInf.toPartialOrder.{u1} R (Lattice.toSemilatticeInf.{u1} R (LinearOrder.toLattice.{u1} R _inst_1))))))] [_inst_4 : CovariantClass.{u1, u1} R R (Function.swap.{succ u1, succ u1, succ u1} R R (fun (ᾰ : R) (ᾰ : R) => R) (HAdd.hAdd.{u1, u1, u1} R R R (instHAdd.{u1} R (AddZeroClass.toHasAdd.{u1} R (AddMonoid.toAddZeroClass.{u1} R _inst_2))))) (LE.le.{u1} R (Preorder.toLE.{u1} R (PartialOrder.toPreorder.{u1} R (SemilatticeInf.toPartialOrder.{u1} R (Lattice.toSemilatticeInf.{u1} R (LinearOrder.toLattice.{u1} R _inst_1))))))] (x : Tropical.{u1} R) (y : Tropical.{u1} R) (n : Nat), Eq.{succ u1} (Tropical.{u1} R) (HPow.hPow.{u1, 0, u1} (Tropical.{u1} R) Nat (Tropical.{u1} R) (instHPow.{u1, 0} (Tropical.{u1} R) Nat (Tropical.hasPow.{u1, 0} R Nat (AddMonoid.SMul.{u1} R _inst_2))) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.hasAdd.{u1} R _inst_1)) x y) n) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.hasAdd.{u1} R _inst_1)) (HPow.hPow.{u1, 0, u1} (Tropical.{u1} R) Nat (Tropical.{u1} R) (instHPow.{u1, 0} (Tropical.{u1} R) Nat (Tropical.hasPow.{u1, 0} R Nat (AddMonoid.SMul.{u1} R _inst_2))) x n) (HPow.hPow.{u1, 0, u1} (Tropical.{u1} R) Nat (Tropical.{u1} R) (instHPow.{u1, 0} (Tropical.{u1} R) Nat (Tropical.hasPow.{u1, 0} R Nat (AddMonoid.SMul.{u1} R _inst_2))) y n))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrder.{u1} R] [_inst_2 : AddMonoid.{u1} R] [_inst_3 : CovariantClass.{u1, u1} R R (fun (x._@.Mathlib.Algebra.Tropical.Basic._hyg.3906 : R) (x._@.Mathlib.Algebra.Tropical.Basic._hyg.3908 : R) => HAdd.hAdd.{u1, u1, u1} R R R (instHAdd.{u1} R (AddZeroClass.toAdd.{u1} R (AddMonoid.toAddZeroClass.{u1} R _inst_2))) x._@.Mathlib.Algebra.Tropical.Basic._hyg.3906 x._@.Mathlib.Algebra.Tropical.Basic._hyg.3908) (fun (x._@.Mathlib.Algebra.Tropical.Basic._hyg.3921 : R) (x._@.Mathlib.Algebra.Tropical.Basic._hyg.3923 : R) => LE.le.{u1} R (Preorder.toLE.{u1} R (PartialOrder.toPreorder.{u1} R (SemilatticeInf.toPartialOrder.{u1} R (Lattice.toSemilatticeInf.{u1} R (DistribLattice.toLattice.{u1} R (instDistribLattice.{u1} R _inst_1)))))) x._@.Mathlib.Algebra.Tropical.Basic._hyg.3921 x._@.Mathlib.Algebra.Tropical.Basic._hyg.3923)] [_inst_4 : CovariantClass.{u1, u1} R R (Function.swap.{succ u1, succ u1, succ u1} R R (fun (ᾰ : R) (ᾰ : R) => R) (fun (x._@.Mathlib.Algebra.Tropical.Basic._hyg.3943 : R) (x._@.Mathlib.Algebra.Tropical.Basic._hyg.3945 : R) => HAdd.hAdd.{u1, u1, u1} R R R (instHAdd.{u1} R (AddZeroClass.toAdd.{u1} R (AddMonoid.toAddZeroClass.{u1} R _inst_2))) x._@.Mathlib.Algebra.Tropical.Basic._hyg.3943 x._@.Mathlib.Algebra.Tropical.Basic._hyg.3945)) (fun (x._@.Mathlib.Algebra.Tropical.Basic._hyg.3958 : R) (x._@.Mathlib.Algebra.Tropical.Basic._hyg.3960 : R) => LE.le.{u1} R (Preorder.toLE.{u1} R (PartialOrder.toPreorder.{u1} R (SemilatticeInf.toPartialOrder.{u1} R (Lattice.toSemilatticeInf.{u1} R (DistribLattice.toLattice.{u1} R (instDistribLattice.{u1} R _inst_1)))))) x._@.Mathlib.Algebra.Tropical.Basic._hyg.3958 x._@.Mathlib.Algebra.Tropical.Basic._hyg.3960)] (x : Tropical.{u1} R) (y : Tropical.{u1} R) (n : Nat), Eq.{succ u1} (Tropical.{u1} R) (HPow.hPow.{u1, 0, u1} (Tropical.{u1} R) Nat (Tropical.{u1} R) (instHPow.{u1, 0} (Tropical.{u1} R) Nat (Tropical.instPowTropical.{u1, 0} R Nat (AddMonoid.SMul.{u1} R _inst_2))) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.instAddTropical.{u1} R _inst_1)) x y) n) (HAdd.hAdd.{u1, u1, u1} (Tropical.{u1} R) (Tropical.{u1} R) (Tropical.{u1} R) (instHAdd.{u1} (Tropical.{u1} R) (Tropical.instAddTropical.{u1} R _inst_1)) (HPow.hPow.{u1, 0, u1} (Tropical.{u1} R) Nat (Tropical.{u1} R) (instHPow.{u1, 0} (Tropical.{u1} R) Nat (Tropical.instPowTropical.{u1, 0} R Nat (AddMonoid.SMul.{u1} R _inst_2))) x n) (HPow.hPow.{u1, 0, u1} (Tropical.{u1} R) Nat (Tropical.{u1} R) (instHPow.{u1, 0} (Tropical.{u1} R) Nat (Tropical.instPowTropical.{u1, 0} R Nat (AddMonoid.SMul.{u1} R _inst_2))) y n))
Case conversion may be inaccurate. Consider using '#align tropical.add_pow Tropical.add_powₓ'. -/
@[simp]
theorem add_pow [LinearOrder R] [AddMonoid R] [CovariantClass R R (· + ·) (· ≤ ·)]
    [CovariantClass R R (Function.swap (· + ·)) (· ≤ ·)] (x y : Tropical R) (n : ℕ) :
    (x + y) ^ n = x ^ n + y ^ n := by
  cases' le_total x y with h h
  · rw [add_eq_left h, add_eq_left (pow_le_pow_of_le_left' h _)]
  · rw [add_eq_right h, add_eq_right (pow_le_pow_of_le_left' h _)]
#align tropical.add_pow Tropical.add_pow

end Distrib

section Semiring

variable [LinearOrderedAddCommMonoidWithTop R]

instance : CommSemiring (Tropical R) :=
  { Tropical.addMonoidWithOne, Tropical.distrib, Tropical.addCommMonoid,
    Tropical.commMonoid with
    zero_mul := fun _ => untrop_injective (top_add _)
    mul_zero := fun _ => untrop_injective (add_top _) }

/- warning: tropical.succ_nsmul -> Tropical.succ_nsmul is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_2 : LinearOrder.{u1} R] [_inst_3 : OrderTop.{u1} R (Preorder.toLE.{u1} R (PartialOrder.toPreorder.{u1} R (SemilatticeInf.toPartialOrder.{u1} R (Lattice.toSemilatticeInf.{u1} R (LinearOrder.toLattice.{u1} R _inst_2)))))] (x : Tropical.{u1} R) (n : Nat), Eq.{succ u1} (Tropical.{u1} R) (SMul.smul.{0, u1} Nat (Tropical.{u1} R) (AddMonoid.SMul.{u1} (Tropical.{u1} R) (AddCommMonoid.toAddMonoid.{u1} (Tropical.{u1} R) (Tropical.addCommMonoid.{u1} R _inst_2 _inst_3))) (HAdd.hAdd.{0, 0, 0} Nat Nat Nat (instHAdd.{0} Nat Nat.hasAdd) n (OfNat.ofNat.{0} Nat 1 (OfNat.mk.{0} Nat 1 (One.one.{0} Nat Nat.hasOne)))) x) x
but is expected to have type
  forall {R : Type.{u1}} [_inst_2 : LinearOrder.{u1} R] [_inst_3 : OrderTop.{u1} R (Preorder.toLE.{u1} R (PartialOrder.toPreorder.{u1} R (SemilatticeInf.toPartialOrder.{u1} R (Lattice.toSemilatticeInf.{u1} R (DistribLattice.toLattice.{u1} R (instDistribLattice.{u1} R _inst_2))))))] (x : Tropical.{u1} R) (n : Nat), Eq.{succ u1} (Tropical.{u1} R) (HSMul.hSMul.{0, u1, u1} Nat (Tropical.{u1} R) (Tropical.{u1} R) (instHSMul.{0, u1} Nat (Tropical.{u1} R) (AddMonoid.SMul.{u1} (Tropical.{u1} R) (AddCommMonoid.toAddMonoid.{u1} (Tropical.{u1} R) (Tropical.instAddCommMonoidTropical.{u1} R _inst_2 _inst_3)))) (HAdd.hAdd.{0, 0, 0} Nat Nat Nat (instHAdd.{0} Nat instAddNat) n (OfNat.ofNat.{0} Nat 1 (instOfNatNat 1))) x) x
Case conversion may be inaccurate. Consider using '#align tropical.succ_nsmul Tropical.succ_nsmulₓ'. -/
@[simp]
theorem succ_nsmul {R} [LinearOrder R] [OrderTop R] (x : Tropical R) (n : ℕ) : (n + 1) • x = x :=
  by
  induction' n with n IH
  · simp
  · rw [add_nsmul, IH, one_nsmul, add_self]
#align tropical.succ_nsmul Tropical.succ_nsmul

/- warning: tropical.mul_eq_zero_iff -> Tropical.mul_eq_zero_iff is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_2 : LinearOrderedAddCommMonoid.{u1} R] {a : Tropical.{u1} (WithTop.{u1} R)} {b : Tropical.{u1} (WithTop.{u1} R)}, Iff (Eq.{succ u1} (Tropical.{u1} (WithTop.{u1} R)) (HMul.hMul.{u1, u1, u1} (Tropical.{u1} (WithTop.{u1} R)) (Tropical.{u1} (WithTop.{u1} R)) (Tropical.{u1} (WithTop.{u1} R)) (instHMul.{u1} (Tropical.{u1} (WithTop.{u1} R)) (Tropical.hasMul.{u1} (WithTop.{u1} R) (WithTop.add.{u1} R (AddZeroClass.toHasAdd.{u1} R (AddMonoid.toAddZeroClass.{u1} R (AddCommMonoid.toAddMonoid.{u1} R (OrderedAddCommMonoid.toAddCommMonoid.{u1} R (LinearOrderedAddCommMonoid.toOrderedAddCommMonoid.{u1} R _inst_2)))))))) a b) (OfNat.ofNat.{u1} (Tropical.{u1} (WithTop.{u1} R)) 0 (OfNat.mk.{u1} (Tropical.{u1} (WithTop.{u1} R)) 0 (Zero.zero.{u1} (Tropical.{u1} (WithTop.{u1} R)) (Tropical.hasZero.{u1} (WithTop.{u1} R) (WithTop.hasTop.{u1} R)))))) (Or (Eq.{succ u1} (Tropical.{u1} (WithTop.{u1} R)) a (OfNat.ofNat.{u1} (Tropical.{u1} (WithTop.{u1} R)) 0 (OfNat.mk.{u1} (Tropical.{u1} (WithTop.{u1} R)) 0 (Zero.zero.{u1} (Tropical.{u1} (WithTop.{u1} R)) (Tropical.hasZero.{u1} (WithTop.{u1} R) (WithTop.hasTop.{u1} R)))))) (Eq.{succ u1} (Tropical.{u1} (WithTop.{u1} R)) b (OfNat.ofNat.{u1} (Tropical.{u1} (WithTop.{u1} R)) 0 (OfNat.mk.{u1} (Tropical.{u1} (WithTop.{u1} R)) 0 (Zero.zero.{u1} (Tropical.{u1} (WithTop.{u1} R)) (Tropical.hasZero.{u1} (WithTop.{u1} R) (WithTop.hasTop.{u1} R)))))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_2 : LinearOrderedAddCommMonoid.{u1} R] {a : Tropical.{u1} (WithTop.{u1} R)} {b : Tropical.{u1} (WithTop.{u1} R)}, Iff (Eq.{succ u1} (Tropical.{u1} (WithTop.{u1} R)) (HMul.hMul.{u1, u1, u1} (Tropical.{u1} (WithTop.{u1} R)) (Tropical.{u1} (WithTop.{u1} R)) (Tropical.{u1} (WithTop.{u1} R)) (instHMul.{u1} (Tropical.{u1} (WithTop.{u1} R)) (Tropical.instMulTropical.{u1} (WithTop.{u1} R) (WithTop.add.{u1} R (AddZeroClass.toAdd.{u1} R (AddMonoid.toAddZeroClass.{u1} R (AddCommMonoid.toAddMonoid.{u1} R (LinearOrderedAddCommMonoid.toAddCommMonoid.{u1} R _inst_2))))))) a b) (OfNat.ofNat.{u1} (Tropical.{u1} (WithTop.{u1} R)) 0 (Zero.toOfNat0.{u1} (Tropical.{u1} (WithTop.{u1} R)) (Tropical.instZeroTropical.{u1} (WithTop.{u1} R) (WithTop.top.{u1} R))))) (Or (Eq.{succ u1} (Tropical.{u1} (WithTop.{u1} R)) a (OfNat.ofNat.{u1} (Tropical.{u1} (WithTop.{u1} R)) 0 (Zero.toOfNat0.{u1} (Tropical.{u1} (WithTop.{u1} R)) (Tropical.instZeroTropical.{u1} (WithTop.{u1} R) (WithTop.top.{u1} R))))) (Eq.{succ u1} (Tropical.{u1} (WithTop.{u1} R)) b (OfNat.ofNat.{u1} (Tropical.{u1} (WithTop.{u1} R)) 0 (Zero.toOfNat0.{u1} (Tropical.{u1} (WithTop.{u1} R)) (Tropical.instZeroTropical.{u1} (WithTop.{u1} R) (WithTop.top.{u1} R))))))
Case conversion may be inaccurate. Consider using '#align tropical.mul_eq_zero_iff Tropical.mul_eq_zero_iffₓ'. -/
-- TODO: find/create the right classes to make this hold (for enat, ennreal, etc)
-- Requires `zero_eq_bot` to be true
-- lemma add_eq_zero_iff {a b : tropical R} :
--   a + b = 1 ↔ a = 1 ∨ b = 1 := sorry
@[simp]
theorem mul_eq_zero_iff {R : Type _} [LinearOrderedAddCommMonoid R] {a b : Tropical (WithTop R)} :
    a * b = 0 ↔ a = 0 ∨ b = 0 := by simp [← untrop_inj_iff, WithTop.add_eq_top]
#align tropical.mul_eq_zero_iff Tropical.mul_eq_zero_iff

instance {R : Type _} [LinearOrderedAddCommMonoid R] : NoZeroDivisors (Tropical (WithTop R)) :=
  ⟨fun _ _ => mul_eq_zero_iff.mp⟩

end Semiring

end Tropical


/-
Copyright (c) 2022 Moritz Doll. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Moritz Doll
-/
import analysis.locally_convex.basic
import topology.bornology.basic
import topology.algebra.uniform_group
import analysis.locally_convex.balanced_core_hull

/-!
# Von Neumann Boundedness

This file defines natural or von Neumann bounded sets and proves elementary properties.

## Main declarations

* `bornology.is_vonN_bounded`: A set `s` is von Neumann-bounded if every neighborhood of zero
absorbs `s`.
* `bornology.vonN_bornology`: The bornology made of the von Neumann-bounded sets.

## Main results

* `bornology.is_vonN_bounded_of_topological_space_le`: A coarser topology admits more
von Neumann-bounded sets.

## References

* [Bourbaki, *Topological Vector Spaces*][bourbaki1987]

-/

variables {𝕜 E ι : Type*}

open filter
open_locale topological_space pointwise

namespace bornology

section semi_normed_ring

section has_zero

variables (𝕜)
variables [semi_normed_ring 𝕜] [has_smul 𝕜 E] [has_zero E]
variables [topological_space E]

/-- A set `s` is von Neumann bounded if every neighborhood of 0 absorbs `s`. -/
def is_vonN_bounded (s : set E) : Prop := ∀ ⦃V⦄, V ∈ 𝓝 (0 : E) → absorbs 𝕜 V s

variables (E)

@[simp] lemma is_vonN_bounded_empty : is_vonN_bounded 𝕜 (∅ : set E) :=
λ _ _, absorbs_empty

variables {𝕜 E}

lemma is_vonN_bounded_iff (s : set E) : is_vonN_bounded 𝕜 s ↔ ∀ V ∈ 𝓝 (0 : E), absorbs 𝕜 V s :=
iff.rfl

lemma _root_.filter.has_basis.is_vonN_bounded_basis_iff {q : ι → Prop} {s : ι → set E} {A : set E}
  (h : (𝓝 (0 : E)).has_basis q s) :
  is_vonN_bounded 𝕜 A ↔ ∀ i (hi : q i), absorbs 𝕜 (s i) A :=
begin
  refine ⟨λ hA i hi, hA (h.mem_of_mem hi), λ hA V hV, _⟩,
  rcases h.mem_iff.mp hV with ⟨i, hi, hV⟩,
  exact (hA i hi).mono_left hV,
end

/-- Subsets of bounded sets are bounded. -/
lemma is_vonN_bounded.subset {s₁ s₂ : set E} (h : s₁ ⊆ s₂) (hs₂ : is_vonN_bounded 𝕜 s₂) :
  is_vonN_bounded 𝕜 s₁ :=
λ V hV, (hs₂ hV).mono_right h

/-- The union of two bounded sets is bounded. -/
lemma is_vonN_bounded.union {s₁ s₂ : set E} (hs₁ : is_vonN_bounded 𝕜 s₁)
  (hs₂ : is_vonN_bounded 𝕜 s₂) :
  is_vonN_bounded 𝕜 (s₁ ∪ s₂) :=
λ V hV, (hs₁ hV).union (hs₂ hV)

end has_zero

end semi_normed_ring

section multiple_topologies

variables [semi_normed_ring 𝕜] [add_comm_group E] [module 𝕜 E]

/-- If a topology `t'` is coarser than `t`, then any set `s` that is bounded with respect to
`t` is bounded with respect to `t'`. -/
lemma is_vonN_bounded.of_topological_space_le {t t' : topological_space E} (h : t ≤ t') {s : set E}
  (hs : @is_vonN_bounded 𝕜 E _ _ _ t s) : @is_vonN_bounded 𝕜 E _ _ _ t' s :=
λ V hV, hs $ (le_iff_nhds t t').mp h 0 hV

end multiple_topologies

section image

variables {𝕜₁ 𝕜₂ F : Type*} [normed_division_ring 𝕜₁] [normed_division_ring 𝕜₂]
  [add_comm_group E] [module 𝕜₁ E] [add_comm_group F] [module 𝕜₂ F]
  [topological_space E] [topological_space F]

/-- A continuous linear image of a bounded set is bounded. -/
lemma is_vonN_bounded.image {σ : 𝕜₁ →+* 𝕜₂} [ring_hom_surjective σ] [ring_hom_isometric σ]
  {s : set E} (hs : is_vonN_bounded 𝕜₁ s) (f : E →SL[σ] F) :
  is_vonN_bounded 𝕜₂ (f '' s) :=
begin
  let σ' := ring_equiv.of_bijective σ ⟨σ.injective, σ.is_surjective⟩,
  have σ_iso : isometry σ := add_monoid_hom_class.isometry_of_norm σ
    (λ x, ring_hom_isometric.is_iso),
  have σ'_symm_iso : isometry σ'.symm := σ_iso.right_inv σ'.right_inv,
  have f_tendsto_zero := f.continuous.tendsto 0,
  rw map_zero at f_tendsto_zero,
  intros V hV,
  rcases hs (f_tendsto_zero hV) with ⟨r, hrpos, hr⟩,
  refine ⟨r, hrpos, λ a ha, _⟩,
  rw ← σ'.apply_symm_apply a,
  have hanz : a ≠ 0 := norm_pos_iff.mp (hrpos.trans_le ha),
  have : σ'.symm a ≠ 0 := (ring_hom.map_ne_zero σ'.symm.to_ring_hom).mpr hanz,
  change _ ⊆ σ _ • _,
  rw [set.image_subset_iff, f.preimage_smul_setₛₗ this.is_unit],
  refine hr (σ'.symm a) _,
  rwa σ'_symm_iso.norm_map_of_map_zero (map_zero _)
end

end image

section normed_field

variables [normed_field 𝕜] [add_comm_group E] [module 𝕜 E]
variables [topological_space E] [has_continuous_smul 𝕜 E]

/-- Singletons are bounded. -/
lemma is_vonN_bounded_singleton (x : E) : is_vonN_bounded 𝕜 ({x} : set E) :=
λ V hV, (absorbent_nhds_zero hV).absorbs

/-- The union of all bounded set is the whole space. -/
lemma is_vonN_bounded_covers : ⋃₀ (set_of (is_vonN_bounded 𝕜)) = (set.univ : set E) :=
set.eq_univ_iff_forall.mpr (λ x, set.mem_sUnion.mpr
  ⟨{x}, is_vonN_bounded_singleton _, set.mem_singleton _⟩)

variables (𝕜 E)

/-- The von Neumann bornology defined by the von Neumann bounded sets.

Note that this is not registered as an instance, in order to avoid diamonds with the
metric bornology.-/
@[reducible] -- See note [reducible non-instances]
def vonN_bornology : bornology E :=
bornology.of_bounded (set_of (is_vonN_bounded 𝕜)) (is_vonN_bounded_empty 𝕜 E)
  (λ _ hs _ ht, hs.subset ht) (λ _ hs _, hs.union) is_vonN_bounded_singleton

variables {E}

@[simp] lemma is_bounded_iff_is_vonN_bounded {s : set E} :
  @is_bounded _ (vonN_bornology 𝕜 E) s ↔ is_vonN_bounded 𝕜 s :=
is_bounded_of_bounded_iff _

end normed_field

end bornology

section uniform_add_group

variables [nondiscrete_normed_field 𝕜] [add_comm_group E] [module 𝕜 E]
variables [uniform_space E] [uniform_add_group E] [has_continuous_smul 𝕜 E]
variables [regular_space E]

lemma totally_bounded.is_vonN_bounded {s : set E} (hs : totally_bounded s) :
  bornology.is_vonN_bounded 𝕜 s :=
begin
  rw totally_bounded_iff_subset_finite_Union_nhds_zero at hs,
  intros U hU,
  have h : filter.tendsto (λ (x : E × E), x.fst + x.snd) (𝓝 (0,0)) (𝓝 ((0 : E) + (0 : E))) :=
    tendsto_add,
  rw add_zero at h,
  have h' := (nhds_basis_closed_balanced 𝕜 E).prod (nhds_basis_closed_balanced 𝕜 E),
  simp_rw [←nhds_prod_eq, id.def] at h',
  rcases h.basis_left h' U hU with ⟨x, hx, h''⟩,
  rcases hs x.snd hx.2.1 with ⟨t, ht, hs⟩,
  refine absorbs.mono_right _ hs,
  rw ht.absorbs_Union,
  have hx_fstsnd : x.fst + x.snd ⊆ U,
  { intros z hz,
    rcases set.mem_add.mp hz with ⟨z1, z2, hz1, hz2, hz⟩,
    have hz' : (z1, z2) ∈ x.fst ×ˢ x.snd := ⟨hz1, hz2⟩,
    simpa only [hz] using h'' hz' },
  refine λ y hy, absorbs.mono_left _ hx_fstsnd,
  rw [←set.singleton_vadd, vadd_eq_add],
  exact (absorbent_nhds_zero hx.1.1).absorbs.add hx.2.2.2.absorbs_self,
end

end uniform_add_group


variable U: Type
variables A B C: U → Prop

section
  example: (∀x, A x → B x) → ((∀x, A x) → (∀x, B x)) :=
    assume h,
    assume all_Ax,
    assume x,
    have Ax: A x, from all_Ax x,
    have Ax_imp_Bx: A x → B x , from h x,
    show B x, from Ax_imp_Bx Ax
end

section
  example (all_Ax_or_Bx: ∀x, A x ∨ B x) (all_nAy: ∀y, ¬A y):
  ∀x, B x :=
    assume x,
    have Ax_or_Bx: A x ∨ B x, from all_Ax_or_Bx x,
    have nAx: ¬A x, from all_nAy x,
    have h₁: A x → B x, from assume Ax: A x, false.elim (nAx Ax),
    have h₂: B x → B x, from assume Bx: B x, Bx,
    or.elim Ax_or_Bx h₁ h₂
end

section
  example: (∃x, A x) ∨ (∃x, B x) → ∃x, A x ∨ B x :=
    assume h,
    have h₁: (∃x, A x) → ∃x, A x ∨ B x, from
      assume h_ex,
      exists.elim h_ex $
        assume x (Ax: A x),
        have A x ∨ B x, from or.inl Ax,
        exists.intro x this,
    have h₂: (∃x, B x) → ∃x, A x ∨ B x, from
      assume h_ex,
      exists.elim h_ex $
        assume x (Bx: B x),
        have A x ∨ B x, from or.inr Bx,
        exists.intro x this,
    or.elim h h₁ h₂
end

section
  example (ex_A_and_B: ∃x, A x ∧ B x) (all_A_and_B_imp_C: ∀x, A x ∧ B x → C x)
  : ∃x, A x ∧ C x :=
    exists.elim ex_A_and_B $
      assume x (Ax_and_Bx: A x ∧ B x),
      have Ax_and_Bx_imp_Cx: A x ∧ B x → C x, from all_A_and_B_imp_C x,
      have Cx: C x, from Ax_and_Bx_imp_Cx Ax_and_Bx,
      have Ax: A x, from and.left Ax_and_Bx,
      have Ax_and_Cx: A x ∧ C x, from and.intro Ax Cx,
      exists.intro x Ax_and_Cx
end

section
  variable P: U → Prop
  variable T: U → U → Prop

  example (h: ∀x y, P x → ¬T y x): ∀x y, T y x → ¬P x :=
    assume x y,
    assume Tyx,
    show ¬P x, from
      assume Px,
      have Px_imp_nTyx: P x → ¬T y x, from h x y,
      have nTyx: ¬T y x, from Px_imp_nTyx Px,
      show false, from nTyx Tyx

  example (h: ∀x y, T y x → ¬P x): ∀x y, P x → ¬T y x :=
    assume x y,
    assume Px,
    show ¬T y x, from
      assume Tyx,
      have Tyx_imp_nPx: T y x → ¬P x, from h x y,
      have nPx: ¬P x, from Tyx_imp_nPx Tyx,
      show false, from nPx Px
end

section
  variables Y H: U → Prop

  variable h₁: ∀x, Y x ∧ H x → B x
  variable h₂: ∀x, A x → H x
  variable h₃: ∃x, Y x ∧ A x

  example: ∃x, B x :=
    exists.elim h₃ $
      assume x (Yx_and_Ax: Y x ∧ A x),
      have Yx: Y x, from and.left Yx_and_Ax,
      have Ax: A x, from and.right Yx_and_Ax,
      have Hx: H x, from h₂ x Ax,
      have Y x ∧ H x, from and.intro Yx Hx,
      have Bx: B x, from h₁ x this,
      exists.intro x Bx
end

section

  example: ∀(x:U) y z, x = z → z = y → x = y :=
   assume x y z (h₁: x = z) (h₂: z = y),
   calc
    x = z: h₁
    ... = y: by rw h₂
end

section
  variables x y : U
  variable h₁: ∀(x: U), x = x
  variable h₂: ∀(u:U) v w, u = w → v = w → u = v

  example: x = y → y = x :=
    assume h,
    have y = y, from h₁ y,
    show y = x, from (h₂ y x y) ‹y = y› h
end

section
  example: (¬∃x,A x ∧ B x) ↔ (∀x,A x → ¬B x) :=
    have h₁: (¬∃x,A x ∧ B x) → (∀x,A x → ¬B x), from
      assume h,
      assume x,
      assume Ax,
      show ¬B x, from
        assume Bx,
        have Ax_and_Bx: A x ∧ B x, from and.intro Ax Bx,
        have ∃x, A x ∧ B x, from exists.intro x Ax_and_Bx,
        show false, from h this,
    have h₂: (∀x,A x → ¬B x) → (¬∃x,A x ∧ B x) , from
      assume h,
      show ¬∃x,A x ∧ B x, from
        assume h_ex,
        show false, from exists.elim h_ex $
          assume x (Ax_and_Bx: A x ∧ B x),
          have Ax: A x, from and.left Ax_and_Bx,
          have Bx: B x, from and.right Ax_and_Bx,
          have Ax_imp_nBx: A x → ¬B x, from h x,
          have nBx: ¬B x, from Ax_imp_nBx Ax,
          show false, from nBx Bx,
    iff.intro h₁ h₂
end

section
  open classical

  example: (¬∀x, A x → B x) ↔ (∃x, A x ∧ ¬B x) :=
    have h₁: (¬∀x, A x → B x) → (∃x, A x ∧ ¬B x), from
      assume h,
      show ∃x, A x ∧ ¬B x, from by_contradiction $
        assume h_nex: ¬∃x, A x ∧ ¬B x,
        show false, from
          have ∀x, A x → B x, from
            assume x,
            assume Ax,
            show B x, from by_contradiction $
              assume nBx,
              have A x ∧ ¬B x, from and.intro Ax nBx,
              have h_ex: ∃x, A x ∧ ¬B x, from exists.intro x this,
              show false, from h_nex h_ex,
          show false, from h this,
    have h₂: (∃x, A x ∧ ¬B x) → (¬∀x, A x → B x) :=
      assume h,
      assume h_all,
      show false, from
        exists.elim h $
          assume x (Ax_and_nBx: A x ∧ ¬B x),
          have Ax_imp_Bx: A x → B x, from h_all x,
          have A x, from and.left Ax_and_nBx,
          have Bx: B x, from Ax_imp_Bx this,
          have nBx: ¬B x, from and.right Ax_and_nBx,
          show false, from nBx Bx,
    iff.intro h₁ h₂
end

section
  example(h:∃x, A x ∧ ∀y, A y → y = x): ∃x, A x ∧ ∀y,∀z, A y ∧ A z → y = z :=
    exists.elim h $
      assume x (h₁: A x ∧ ∀y, A y → y = x),
      have Ax: A x, from and.left h₁,
      have all_A_imp_eq_x: ∀y, A y → y = x, from and.right h₁,
      have ∀y,∀z, A y ∧ A z → y = z, from
        assume (y:U) (z:U) (Ay_and_Az: A y ∧ A z),
        have Ay_imp_y_eq_x: A y → y = x, from all_A_imp_eq_x y,
        have Az_imp_z_eq_x: A z → z = x, from all_A_imp_eq_x z,
        have A y, from and.left Ay_and_Az,
        have y_eq_x: y = x, from Ay_imp_y_eq_x this,
        have A z, from and.right Ay_and_Az,
        have z_eq_x: z = x, from Az_imp_z_eq_x this,
        show y = z, by rw [y_eq_x, z_eq_x],
      exists.intro x (and.intro Ax this)

  example(h:∃x, A x ∧ ∀y,∀z, A y ∧ A z → y = z): ∃x, A x ∧ ∀y, A y → y = x :=
    exists.elim h $
      assume x (h₁: A x ∧ ∀y,∀z, A y ∧ A z → y = z),
      have Ax: A x, from and.left h₁,
      have h₂: ∀y,∀z, A y ∧ A z → y = z, from and.right h₁,
      have ∀y, A y → y = x, from
        assume y Ay,
        have A y ∧ A x → y = x, from h₂ y x,
        show y = x, from this (and.intro Ay Ax),
      exists.intro x (and.intro Ax this)
end


/-
Copyright (c) 2018 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro, Chris Hughes

! This file was ported from Lean 3 source module ring_theory.euclidean_domain
! leanprover-community/mathlib commit 70fd9563a21e7b963887c9360bd29b2393e6225a
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathlib.Algebra.GCDMonoid.Basic
import Mathlib.Algebra.EuclideanDomain.Basic
import Mathlib.RingTheory.Ideal.Basic
import Mathlib.RingTheory.PrincipalIdealDomain

/-!
# Lemmas about Euclidean domains

Various about Euclidean domains are proved; all of them seem to be true
more generally for principal ideal domains, so these lemmas should
probably be reproved in more generality and this file perhaps removed?

## Tags

euclidean domain
-/

noncomputable section

open Classical

open EuclideanDomain Set Ideal

section GCDMonoid

variable {R : Type _} [EuclideanDomain R] [GCDMonoid R]

theorem gcd_ne_zero_of_left (p q : R) (hp : p ≠ 0) : GCDMonoid.gcd p q ≠ 0 := fun h =>
  hp <| eq_zero_of_zero_dvd (h ▸ gcd_dvd_left p q)
#align gcd_ne_zero_of_left gcd_ne_zero_of_left

theorem gcd_ne_zero_of_right (p q : R) (hp : q ≠ 0) : GCDMonoid.gcd p q ≠ 0 := fun h =>
  hp <| eq_zero_of_zero_dvd (h ▸ gcd_dvd_right p q)
#align gcd_ne_zero_of_right gcd_ne_zero_of_right

theorem left_div_gcd_ne_zero {p q : R} (hp : p ≠ 0) : p / GCDMonoid.gcd p q ≠ 0 := by
  obtain ⟨r, hr⟩ := GCDMonoid.gcd_dvd_left p q
  obtain ⟨pq0, r0⟩ : GCDMonoid.gcd p q ≠ 0 ∧ r ≠ 0 := mul_ne_zero_iff.mp (hr ▸ hp)
  nth_rw 1 [hr]
  rw [mul_comm, EuclideanDomain.mul_div_cancel _ pq0]
  exact r0
#align left_div_gcd_ne_zero left_div_gcd_ne_zero

theorem right_div_gcd_ne_zero {p q : R} (hq : q ≠ 0) : q / GCDMonoid.gcd p q ≠ 0 := by
  obtain ⟨r, hr⟩ := GCDMonoid.gcd_dvd_right p q
  obtain ⟨pq0, r0⟩ : GCDMonoid.gcd p q ≠ 0 ∧ r ≠ 0 := mul_ne_zero_iff.mp (hr ▸ hq)
  nth_rw 1 [hr]
  rw [mul_comm, EuclideanDomain.mul_div_cancel _ pq0]
  exact r0
#align right_div_gcd_ne_zero right_div_gcd_ne_zero

end GCDMonoid

namespace EuclideanDomain

/-- Create a `GCDMonoid` whose `gcd_monoid.gcd` matches `EuclideanDomain.gcd`. -/
def gcdMonoid (R) [EuclideanDomain R] : GCDMonoid R where
  gcd := gcd
  lcm := lcm
  gcd_dvd_left := gcd_dvd_left
  gcd_dvd_right := gcd_dvd_right
  dvd_gcd := dvd_gcd
  gcd_mul_lcm a b := by rw [EuclideanDomain.gcd_mul_lcm]
  lcm_zero_left := lcm_zero_left
  lcm_zero_right := lcm_zero_right
#align euclidean_domain.gcd_monoid EuclideanDomain.gcdMonoid

variable {α : Type _} [EuclideanDomain α] [DecidableEq α]

theorem span_gcd {α} [EuclideanDomain α] (x y : α) :
    span ({gcd x y} : Set α) = span ({x, y} : Set α) :=
  letI := EuclideanDomain.gcdMonoid α
  _root_.span_gcd x y
#align euclidean_domain.span_gcd EuclideanDomain.span_gcd

theorem gcd_isUnit_iff {α} [EuclideanDomain α] {x y : α} : IsUnit (gcd x y) ↔ IsCoprime x y :=
  letI := EuclideanDomain.gcdMonoid α
  _root_.gcd_isUnit_iff x y
#align euclidean_domain.gcd_is_unit_iff EuclideanDomain.gcd_isUnit_iff

-- this should be proved for UFDs surely?
theorem isCoprime_of_dvd {α} [EuclideanDomain α] {x y : α} (nonzero : ¬(x = 0 ∧ y = 0))
    (H : ∀ z ∈ nonunits α, z ≠ 0 → z ∣ x → ¬z ∣ y) : IsCoprime x y :=
  letI := EuclideanDomain.gcdMonoid α
  _root_.isCoprime_of_dvd x y nonzero H
#align euclidean_domain.is_coprime_of_dvd EuclideanDomain.isCoprime_of_dvd

-- this should be proved for UFDs surely?
theorem dvd_or_coprime {α} [EuclideanDomain α] (x y : α) (h : Irreducible x) :
    x ∣ y ∨ IsCoprime x y :=
  letI := EuclideanDomain.gcdMonoid α
  _root_.dvd_or_coprime x y h
#align euclidean_domain.dvd_or_coprime EuclideanDomain.dvd_or_coprime

end EuclideanDomain


/-
Copyright (c) 2022 Michael Stoll. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Michael Geißer, Michael Stoll

! This file was ported from Lean 3 source module number_theory.diophantine_approximation
! leanprover-community/mathlib commit 9956c3806d0f9553e5c6e6af68970563a1619cd1
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Tactic.Basic
import Mathbin.Data.Real.Irrational
import Mathbin.Combinatorics.Pigeonhole

/-!
# Diophantine Approximation

This file gives proofs of various versions of **Dirichlet's approximation theorem**
and its important consequence that when `ξ` is an irrational real number, then there are
infinitely many rationals `x/y` (in lowest terms) such that `|ξ - x/y| < 1/y^2`.

The proof is based on the pigeonhole principle.

## Main statements

The main results are three variants of Dirichlet's approximation theorem:
* `real.exists_int_int_abs_mul_sub_le`, which states that for all real `ξ` and natural `0 < n`,
  there are integers `j` and `k` with `0 < k ≤ n` and `|k*ξ - j| ≤ 1/(n+1)`,
* `real.exists_nat_abs_mul_sub_round_le`, which replaces `j` by `round(k*ξ)` and uses
  a natural number `k`,
* `real.exists_rat_abs_sub_le_and_denom_le`, which says that there is a rational number `q`
  satisfying `|ξ - q| ≤ 1/((n+1)*q.denom)` and `q.denom ≤ n`,

and
* `real.infinite_rat_abs_sub_lt_one_div_denom_sq_of_irrational`, which states that
  for irrational `ξ`, the set `{q : ℚ | |ξ - q| < 1/q.denom^2}` is infinite.

We also show a converse,
* `rat.finite_rat_abs_sub_lt_one_div_denom_sq`, which states that the set above is finite
  when `ξ` is a rational number.

Both statements are combined to give an equivalence,
`real.infinite_rat_abs_sub_lt_one_div_denom_sq_iff_irrational`.

## Implementation notes

We use the namespace `real` for the results on real numbers and `rat` for the results
on rational numbers.

## References

<https://en.wikipedia.org/wiki/Dirichlet%27s_approximation_theorem>

## Tags

Diophantine approximation, Dirichlet's approximation theorem
-/

namespace Real

section Dirichlet

/-!
### Dirichlet's approximation theorem

We show that for any real number `ξ` and positive natural `n`, there is a fraction `q`
such that `q.denom ≤ n` and `|ξ - q| ≤ 1/((n+1)*q.denom)`.
-/

open Finset Int

/-- *Dirichlet's approximation theorem:*
For any real number `ξ` and positive natural `n`, there are integers `j` and `k`,
with `0 < k ≤ n` and `|k*ξ - j| ≤ 1/(n+1)`.

See also `real.exists_nat_abs_mul_sub_round_le`. -/
theorem exists_int_int_abs_mul_sub_le (ξ : ℝ) {n : ℕ} (n_pos : 0 < n) :
    ∃ j k : ℤ, 0 < k ∧ k ≤ n ∧ |↑k * ξ - j| ≤ 1 / (n + 1) :=
  by
  let f : ℤ → ℤ := fun m => ⌊fract (ξ * m) * (n + 1)⌋
  have hn : 0 < (n : ℝ) + 1 := by exact_mod_cast Nat.succ_pos _
  have hfu := fun m : ℤ => mul_lt_of_lt_one_left hn <| fract_lt_one (ξ * ↑m)
  conv in |_| ≤ _ => rw [mul_comm, le_div_iff hn, ← abs_of_pos hn, ← abs_mul]
  let D := Icc (0 : ℤ) n
  by_cases H : ∃ m ∈ D, f m = n
  · obtain ⟨m, hm, hf⟩ := H
    have hf' : ((n : ℤ) : ℝ) ≤ fract (ξ * m) * (n + 1) := hf ▸ floor_le (fract (ξ * m) * (n + 1))
    have hm₀ : 0 < m :=
      by
      have hf₀ : f 0 = 0 := by
        simp only [floor_eq_zero_iff, algebraMap.coe_zero, MulZeroClass.mul_zero, fract_zero,
          MulZeroClass.zero_mul, Set.left_mem_Ico, zero_lt_one]
      refine' Ne.lt_of_le (fun h => n_pos.ne _) (mem_Icc.mp hm).1
      exact_mod_cast hf₀.symm.trans (h.symm ▸ hf : f 0 = n)
    refine' ⟨⌊ξ * m⌋ + 1, m, hm₀, (mem_Icc.mp hm).2, _⟩
    rw [cast_add, ← sub_sub, sub_mul, cast_one, one_mul, abs_le]
    refine'
      ⟨le_sub_iff_add_le.mpr _, sub_le_iff_le_add.mpr <| le_of_lt <| (hfu m).trans <| lt_one_add _⟩
    simpa only [neg_add_cancel_comm_assoc] using hf'
  · simp_rw [not_exists] at H
    have hD : (Ico (0 : ℤ) n).card < D.card :=
      by
      rw [card_Icc, card_Ico]
      exact lt_add_one n
    have hfu' : ∀ m, f m ≤ n := fun m => lt_add_one_iff.mp (floor_lt.mpr (by exact_mod_cast hfu m))
    have hwd : ∀ m : ℤ, m ∈ D → f m ∈ Ico (0 : ℤ) n := fun x hx =>
      mem_Ico.mpr
        ⟨floor_nonneg.mpr (mul_nonneg (fract_nonneg (ξ * x)) hn.le), Ne.lt_of_le (H x hx) (hfu' x)⟩
    have : ∃ (x : ℤ)(hx : x ∈ D)(y : ℤ)(hy : y ∈ D), x < y ∧ f x = f y :=
      by
      obtain ⟨x, hx, y, hy, x_ne_y, hxy⟩ := exists_ne_map_eq_of_card_lt_of_maps_to hD hwd
      rcases lt_trichotomy x y with (h | h | h)
      exacts[⟨x, hx, y, hy, h, hxy⟩, False.elim (x_ne_y h), ⟨y, hy, x, hx, h, hxy.symm⟩]
    obtain ⟨x, hx, y, hy, x_lt_y, hxy⟩ := this
    refine'
      ⟨⌊ξ * y⌋ - ⌊ξ * x⌋, y - x, sub_pos_of_lt x_lt_y,
        sub_le_iff_le_add.mpr <| le_add_of_le_of_nonneg (mem_Icc.mp hy).2 (mem_Icc.mp hx).1, _⟩
    convert_to|fract (ξ * y) * (n + 1) - fract (ξ * x) * (n + 1)| ≤ 1
    · congr
      push_cast
      simp only [fract]
      ring
    exact (abs_sub_lt_one_of_floor_eq_floor hxy.symm).le
#align real.exists_int_int_abs_mul_sub_le Real.exists_int_int_abs_mul_sub_le

/-- *Dirichlet's approximation theorem:*
For any real number `ξ` and positive natural `n`, there is a natural number `k`,
with `0 < k ≤ n` such that `|k*ξ - round(k*ξ)| ≤ 1/(n+1)`.
-/
theorem exists_nat_abs_mul_sub_round_le (ξ : ℝ) {n : ℕ} (n_pos : 0 < n) :
    ∃ k : ℕ, 0 < k ∧ k ≤ n ∧ |↑k * ξ - round (↑k * ξ)| ≤ 1 / (n + 1) :=
  by
  obtain ⟨j, k, hk₀, hk₁, h⟩ := exists_int_int_abs_mul_sub_le ξ n_pos
  have hk := to_nat_of_nonneg hk₀.le
  rw [← hk] at hk₀ hk₁ h
  exact ⟨k.to_nat, coe_nat_pos.mp hk₀, nat.cast_le.mp hk₁, (round_le (↑k.to_nat * ξ) j).trans h⟩
#align real.exists_nat_abs_mul_sub_round_le Real.exists_nat_abs_mul_sub_round_le

/-- *Dirichlet's approximation theorem:*
For any real number `ξ` and positive natural `n`, there is a fraction `q`
such that `q.denom ≤ n` and `|ξ - q| ≤ 1/((n+1)*q.denom)`. -/
theorem exists_rat_abs_sub_le_and_den_le (ξ : ℝ) {n : ℕ} (n_pos : 0 < n) :
    ∃ q : ℚ, |ξ - q| ≤ 1 / ((n + 1) * q.den) ∧ q.den ≤ n :=
  by
  obtain ⟨j, k, hk₀, hk₁, h⟩ := exists_int_int_abs_mul_sub_le ξ n_pos
  have hk₀' : (0 : ℝ) < k := int.cast_pos.mpr hk₀
  have hden : ((j / k : ℚ).den : ℤ) ≤ k :=
    by
    convert le_of_dvd hk₀ (Rat.den_dvd j k)
    exact Rat.coe_int_div_eq_divInt
  refine' ⟨j / k, _, nat.cast_le.mp (hden.trans hk₁)⟩
  rw [← div_div, le_div_iff (nat.cast_pos.mpr <| Rat.pos _ : (0 : ℝ) < _)]
  refine' (mul_le_mul_of_nonneg_left (int.cast_le.mpr hden : _ ≤ (k : ℝ)) (abs_nonneg _)).trans _
  rwa [← abs_of_pos hk₀', Rat.cast_div, Rat.cast_coe_int, Rat.cast_coe_int, ← abs_mul, sub_mul,
    div_mul_cancel _ hk₀'.ne', mul_comm]
#align real.exists_rat_abs_sub_le_and_denom_le Real.exists_rat_abs_sub_le_and_den_le

end Dirichlet

section RatApprox

/-!
### Infinitely many good approximations to irrational numbers

We show that an irrational real number `ξ` has infinitely many "good rational approximations",
i.e., fractions `x/y` in lowest terms such that `|ξ - x/y| < 1/y^2`.
-/

open Set

/-- Given any rational approximation `q` to the irrational real number `ξ`, there is
a good rational approximation `q'` such that `|ξ - q'| < |ξ - q|`. -/
theorem exists_rat_abs_sub_lt_and_lt_of_irrational {ξ : ℝ} (hξ : Irrational ξ) (q : ℚ) :
    ∃ q' : ℚ, |ξ - q'| < 1 / q'.den ^ 2 ∧ |ξ - q'| < |ξ - q| :=
  by
  have h := abs_pos.mpr (sub_ne_zero.mpr <| Irrational.ne_rat hξ q)
  obtain ⟨m, hm⟩ := exists_nat_gt (1 / |ξ - q|)
  have m_pos : (0 : ℝ) < m := (one_div_pos.mpr h).trans hm
  obtain ⟨q', hbd, hden⟩ := exists_rat_abs_sub_le_and_denom_le ξ (nat.cast_pos.mp m_pos)
  have den_pos : (0 : ℝ) < q'.denom := nat.cast_pos.mpr q'.pos
  have md_pos := mul_pos (add_pos m_pos zero_lt_one) den_pos
  refine'
    ⟨q', lt_of_le_of_lt hbd _,
      lt_of_le_of_lt hbd <|
        (one_div_lt md_pos h).mpr <|
          hm.trans <|
            lt_of_lt_of_le (lt_add_one _) <|
              (le_mul_iff_one_le_right <| add_pos m_pos zero_lt_one).mpr <| by
                exact_mod_cast (q'.pos : 1 ≤ q'.denom)⟩
  rw [sq, one_div_lt_one_div md_pos (mul_pos den_pos den_pos), mul_lt_mul_right den_pos]
  exact lt_add_of_le_of_pos (nat.cast_le.mpr hden) zero_lt_one
#align real.exists_rat_abs_sub_lt_and_lt_of_irrational Real.exists_rat_abs_sub_lt_and_lt_of_irrational

/-- If `ξ` is an irrational real number, then there are infinitely many good
rational approximations to `ξ`. -/
theorem infinite_rat_abs_sub_lt_one_div_den_sq_of_irrational {ξ : ℝ} (hξ : Irrational ξ) :
    { q : ℚ | |ξ - q| < 1 / q.den ^ 2 }.Infinite :=
  by
  refine' Or.resolve_left (Set.finite_or_infinite _) fun h => _
  obtain ⟨q, _, hq⟩ :=
    exists_min_image { q : ℚ | |ξ - q| < 1 / q.den ^ 2 } (fun q => |ξ - q|) h
      ⟨⌊ξ⌋, by simp [abs_of_nonneg, Int.fract_lt_one]⟩
  obtain ⟨q', hmem, hbetter⟩ := exists_rat_abs_sub_lt_and_lt_of_irrational hξ q
  exact lt_irrefl _ (lt_of_le_of_lt (hq q' hmem) hbetter)
#align real.infinite_rat_abs_sub_lt_one_div_denom_sq_of_irrational Real.infinite_rat_abs_sub_lt_one_div_den_sq_of_irrational

end RatApprox

end Real

namespace Rat

/-!
### Finitely many good approximations to rational numbers

We now show that a rational number `ξ` has only finitely many good rational
approximations.
-/

open Set

/-- If `ξ` is rational, then the good rational approximations to `ξ` have bounded
numerator and denominator. -/
theorem den_le_and_le_num_le_of_sub_lt_one_div_den_sq {ξ q : ℚ} (h : |ξ - q| < 1 / q.den ^ 2) :
    q.den ≤ ξ.den ∧ ⌈ξ * q.den⌉ - 1 ≤ q.num ∧ q.num ≤ ⌊ξ * q.den⌋ + 1 :=
  by
  have hq₀ : (0 : ℚ) < q.denom := nat.cast_pos.mpr q.pos
  replace h : |ξ * q.denom - q.num| < 1 / q.denom
  · rw [← mul_lt_mul_right hq₀] at h
    conv_lhs at h => rw [← abs_of_pos hq₀, ← abs_mul, sub_mul, mul_denom_eq_num]
    rwa [sq, div_mul, mul_div_cancel_left _ hq₀.ne'] at h
  constructor
  · rcases eq_or_ne ξ q with (rfl | H)
    · exact le_rfl
    · have hξ₀ : (0 : ℚ) < ξ.denom := nat.cast_pos.mpr ξ.pos
      rw [← Rat.num_div_den ξ, div_mul_eq_mul_div, div_sub' _ _ _ hξ₀.ne', abs_div, abs_of_pos hξ₀,
        div_lt_iff hξ₀, div_mul_comm, mul_one] at h
      refine' nat.cast_le.mp ((one_lt_div hq₀).mp <| lt_of_le_of_lt _ h).le
      norm_cast
      rw [mul_comm _ q.num]
      exact Int.one_le_abs (sub_ne_zero_of_ne <| mt rat.eq_iff_mul_eq_mul.mpr H)
  · obtain ⟨h₁, h₂⟩ :=
      abs_sub_lt_iff.mp
        (h.trans_le <|
          (one_div_le zero_lt_one hq₀).mp <| (@one_div_one ℚ _).symm ▸ nat.cast_le.mpr q.pos)
    rw [sub_lt_iff_lt_add, add_comm] at h₁ h₂
    rw [← sub_lt_iff_lt_add] at h₂
    norm_cast  at h₁ h₂
    exact
      ⟨sub_le_iff_le_add.mpr (int.ceil_le.mpr h₁.le), sub_le_iff_le_add.mp (int.le_floor.mpr h₂.le)⟩
#align rat.denom_le_and_le_num_le_of_sub_lt_one_div_denom_sq Rat.den_le_and_le_num_le_of_sub_lt_one_div_den_sq

/- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
/-- A rational number has only finitely many good rational approximations. -/
theorem finite_rat_abs_sub_lt_one_div_den_sq (ξ : ℚ) : { q : ℚ | |ξ - q| < 1 / q.den ^ 2 }.Finite :=
  by
  let f : ℚ → ℤ × ℕ := fun q => (q.num, q.den)
  set s := { q : ℚ | |ξ - q| < 1 / q.den ^ 2 }
  have hinj : Function.Injective f := by
    intro a b hab
    simp only [Prod.mk.inj_iff] at hab
    rw [← Rat.num_div_den a, ← Rat.num_div_den b, hab.1, hab.2]
  have H : f '' s ⊆ ⋃ (y : ℕ) (hy : y ∈ Ioc 0 ξ.denom), Icc (⌈ξ * y⌉ - 1) (⌊ξ * y⌋ + 1) ×ˢ {y} :=
    by
    intro xy hxy
    simp only [mem_image, mem_set_of_eq] at hxy
    obtain ⟨q, hq₁, hq₂⟩ := hxy
    obtain ⟨hd, hn⟩ := denom_le_and_le_num_le_of_sub_lt_one_div_denom_sq hq₁
    simp_rw [mem_Union]
    refine' ⟨q.denom, set.mem_Ioc.mpr ⟨q.pos, hd⟩, _⟩
    simp only [prod_singleton, mem_image, mem_Icc, (congr_arg Prod.snd (Eq.symm hq₂)).trans rfl]
    exact ⟨q.num, hn, hq₂⟩
  refine' finite.of_finite_image (finite.subset _ H) (inj_on_of_injective hinj s)
  exact finite.bUnion (finite_Ioc _ _) fun x hx => finite.prod (finite_Icc _ _) (finite_singleton _)
#align rat.finite_rat_abs_sub_lt_one_div_denom_sq Rat.finite_rat_abs_sub_lt_one_div_den_sq

end Rat

/-- The set of good rational approximations to a real number `ξ` is infinite if and only if
`ξ` is irrational. -/
theorem Real.infinite_rat_abs_sub_lt_one_div_den_sq_iff_irrational (ξ : ℝ) :
    { q : ℚ | |ξ - q| < 1 / q.den ^ 2 }.Infinite ↔ Irrational ξ :=
  by
  refine'
    ⟨fun h => (irrational_iff_ne_rational ξ).mpr fun a b H => set.not_infinite.mpr _ h,
      Real.infinite_rat_abs_sub_lt_one_div_den_sq_of_irrational⟩
  convert Rat.finite_rat_abs_sub_lt_one_div_den_sq ((a : ℚ) / b)
  ext q
  rw [H, (by push_cast : (1 : ℝ) / q.denom ^ 2 = (1 / q.denom ^ 2 : ℚ))]
  norm_cast
#align real.infinite_rat_abs_sub_lt_one_div_denom_sq_iff_irrational Real.infinite_rat_abs_sub_lt_one_div_den_sq_iff_irrational