/-
Copyright (c) 2019 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johan Commelin, Bhavik Mehta

! This file was ported from Lean 3 source module category_theory.over
! leanprover-community/mathlib commit 8a318021995877a44630c898d0b2bc376fceef3b
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathlib.CategoryTheory.StructuredArrow
import Mathlib.CategoryTheory.PUnit
import Mathlib.CategoryTheory.Functor.ReflectsIso
import Mathlib.CategoryTheory.Functor.EpiMono

/-!
# Over and under categories

Over (and under) categories are special cases of comma categories.
* If `L` is the identity functor and `R` is a constant functor, then `Comma L R` is the "slice" or
  "over" category over the object `R` maps to.
* Conversely, if `L` is a constant functor and `R` is the identity functor, then `Comma L R` is the
  "coslice" or "under" category under the object `L` maps to.

## Tags

Comma, Slice, Coslice, Over, Under
-/

namespace CategoryTheory

universe v₁ v₂ u₁ u₂

-- morphism levels before object levels. See note [CategoryTheory universes].
variable {T : Type u₁} [Category.{v₁} T]

/-- The over category has as objects arrows in `T` with codomain `X` and as morphisms commutative
triangles.

See <https://stacks.math.columbia.edu/tag/001G>.
-/
def Over (X : T) :=
  CostructuredArrow (𝟭 T) X
#align category_theory.over CategoryTheory.Over

instance (X : T) : Category (Over X) := commaCategory

-- Satisfying the inhabited linter
instance Over.inhabited [Inhabited T] : Inhabited (Over (default : T))
    where default :=
    { left := default
      right := default
      hom := 𝟙 _ }
#align category_theory.over.inhabited CategoryTheory.Over.inhabited

namespace Over

variable {X : T}

@[ext]
theorem OverMorphism.ext {X : T} {U V : Over X} {f g : U ⟶ V} (h : f.left = g.left) : f = g := by
  let ⟨_,b,_⟩ := f
  let ⟨_,e,_⟩ := g
  congr
  simp only [eq_iff_true_of_subsingleton]

#align category_theory.over.over_morphism.ext CategoryTheory.Over.OverMorphism.ext

-- @[simp] : Porting note : simp can prove this
theorem over_right (U : Over X) : U.right = ⟨⟨⟩⟩ := by simp only
#align category_theory.over.over_right CategoryTheory.Over.over_right

@[simp]
theorem id_left (U : Over X) : CommaMorphism.left (𝟙 U) = 𝟙 U.left :=
  rfl
#align category_theory.over.id_left CategoryTheory.Over.id_left

@[simp]
theorem comp_left (a b c : Over X) (f : a ⟶ b) (g : b ⟶ c) : (f ≫ g).left = f.left ≫ g.left :=
  rfl
#align category_theory.over.comp_left CategoryTheory.Over.comp_left

@[reassoc (attr := simp)]
theorem w {A B : Over X} (f : A ⟶ B) : f.left ≫ B.hom = A.hom := by have := f.w; aesop_cat
#align category_theory.over.w CategoryTheory.Over.w

/-- To give an object in the over category, it suffices to give a morphism with codomain `X`. -/
@[simps! left hom]
def mk {X Y : T} (f : Y ⟶ X) : Over X :=
  CostructuredArrow.mk f
#align category_theory.over.mk CategoryTheory.Over.mk

/-- We can set up a coercion from arrows with codomain `X` to `over X`. This most likely should not
    be a global instance, but it is sometimes useful. -/
def coeFromHom {X Y : T} : Coe (Y ⟶ X) (Over X) where coe := mk
#align category_theory.over.coe_from_hom CategoryTheory.Over.coeFromHom

section

attribute [local instance] coeFromHom

@[simp]
theorem coe_hom {X Y : T} (f : Y ⟶ X) : (f : Over X).hom = f :=
  rfl
#align category_theory.over.coe_hom CategoryTheory.Over.coe_hom

end

/-- To give a morphism in the over category, it suffices to give an arrow fitting in a commutative
    triangle. -/
@[simps!]
def homMk {U V : Over X} (f : U.left ⟶ V.left) (w : f ≫ V.hom = U.hom := by aesop_cat) : U ⟶ V :=
  CostructuredArrow.homMk f w
#align category_theory.over.hom_mk CategoryTheory.Over.homMk

-- Porting note: simp solves this; simpNF still sees them after `-simp` (?)
attribute [-simp, nolint simpNF] homMk_right_down_down

/-- Construct an isomorphism in the over category given isomorphisms of the objects whose forward
direction gives a commutative triangle.
-/
@[simps!]
def isoMk {f g : Over X} (hl : f.left ≅ g.left) (hw : hl.hom ≫ g.hom = f.hom := by aesop_cat) :
    f ≅ g :=
  CostructuredArrow.isoMk hl hw
#align category_theory.over.iso_mk CategoryTheory.Over.isoMk

-- Porting note: simp solves this; simpNF still sees them after `-simp` (?)
attribute [-simp, nolint simpNF] isoMk_hom_right_down_down isoMk_inv_right_down_down

section

variable (X)

/-- The forgetful functor mapping an arrow to its domain.

See <https://stacks.math.columbia.edu/tag/001G>.
-/
def forget : Over X ⥤ T :=
  Comma.fst _ _
#align category_theory.over.forget CategoryTheory.Over.forget

end

@[simp]
theorem forget_obj {U : Over X} : (forget X).obj U = U.left :=
  rfl
#align category_theory.over.forget_obj CategoryTheory.Over.forget_obj

@[simp]
theorem forget_map {U V : Over X} {f : U ⟶ V} : (forget X).map f = f.left :=
  rfl
#align category_theory.over.forget_map CategoryTheory.Over.forget_map

/-- The natural cocone over the forgetful functor `Over X ⥤ T` with cocone point `X`. -/
@[simps]
def forgetCocone (X : T) : Limits.Cocone (forget X) :=
  { pt := X
    ι := { app := Comma.hom } }
#align category_theory.over.forget_cocone CategoryTheory.Over.forgetCocone

/-- A morphism `f : X ⟶ Y` induces a functor `Over X ⥤ Over Y` in the obvious way.

See <https://stacks.math.columbia.edu/tag/001G>.
-/
def map {Y : T} (f : X ⟶ Y) : Over X ⥤ Over Y :=
  Comma.mapRight _ <| Discrete.natTrans fun _ => f
#align category_theory.over.map CategoryTheory.Over.map

section

variable {Y : T} {f : X ⟶ Y} {U V : Over X} {g : U ⟶ V}

@[simp]
theorem map_obj_left : ((map f).obj U).left = U.left :=
  rfl
#align category_theory.over.map_obj_left CategoryTheory.Over.map_obj_left

@[simp]
theorem map_obj_hom : ((map f).obj U).hom = U.hom ≫ f :=
  rfl
#align category_theory.over.map_obj_hom CategoryTheory.Over.map_obj_hom

@[simp]
theorem map_map_left : ((map f).map g).left = g.left :=
  rfl
#align category_theory.over.map_map_left CategoryTheory.Over.map_map_left

/-- Mapping by the identity morphism is just the identity functor. -/
def mapId : map (𝟙 Y) ≅ 𝟭 _ :=
  NatIso.ofComponents (fun X => isoMk (Iso.refl _) (by aesop_cat)) (by aesop_cat)
#align category_theory.over.map_id CategoryTheory.Over.mapId

/-- Mapping by the composite morphism `f ≫ g` is the same as mapping by `f` then by `g`. -/
def mapComp {Y Z : T} (f : X ⟶ Y) (g : Y ⟶ Z) : map (f ≫ g) ≅ map f ⋙ map g :=
  NatIso.ofComponents (fun X => isoMk (Iso.refl _) (by aesop_cat)) (by aesop_cat)
#align category_theory.over.map_comp CategoryTheory.Over.mapComp

end

instance forget_reflects_iso : ReflectsIsomorphisms (forget X) where
  reflects {Y Z} f t := by
    let g :Z ⟶  Y := Over.homMk (inv ((forget X).map f))
      ((asIso ((forget X).map f)).inv_comp_eq.2 (Over.w f).symm)
    dsimp [forget] at t
    refine ⟨⟨g, ⟨?_,?_⟩⟩⟩
    repeat (ext; simp)
#align category_theory.over.forget_reflects_iso CategoryTheory.Over.forget_reflects_iso

instance forget_faithful : Faithful (forget X) where
#align category_theory.over.forget_faithful CategoryTheory.Over.forget_faithful

-- TODO: Show the converse holds if `T` has binary products.
/--
If `k.left` is an epimorphism, then `k` is an epimorphism. In other words, `Over.forget X` reflects
epimorphisms.
The converse does not hold without additional assumptions on the underlying category, see
`CategoryTheory.Over.epi_left_of_epi`.
-/
theorem epi_of_epi_left {f g : Over X} (k : f ⟶ g) [hk : Epi k.left] : Epi k :=
  (forget X).epi_of_epi_map hk
#align category_theory.over.epi_of_epi_left CategoryTheory.Over.epi_of_epi_left

/--
If `k.left` is a monomorphism, then `k` is a monomorphism. In other words, `Over.forget X` reflects
monomorphisms.
The converse of `CategoryTheory.Over.mono_left_of_mono`.

This lemma is not an instance, to avoid loops in type class inference.
-/
theorem mono_of_mono_left {f g : Over X} (k : f ⟶ g) [hk : Mono k.left] : Mono k :=
  (forget X).mono_of_mono_map hk
#align category_theory.over.mono_of_mono_left CategoryTheory.Over.mono_of_mono_left

/--
If `k` is a monomorphism, then `k.left` is a monomorphism. In other words, `Over.forget X` preserves
monomorphisms.
The converse of `CategoryTheory.Over.mono_of_mono_left`.
-/
instance mono_left_of_mono {f g : Over X} (k : f ⟶ g) [Mono k] : Mono k.left := by
  refine' ⟨fun { Y : T } l m a => _⟩
  let l' : mk (m ≫ f.hom) ⟶ f := homMk l (by
        dsimp; rw [← Over.w k, ←Category.assoc, congrArg (· ≫ g.hom) a, Category.assoc])
  suffices l' = (homMk m : mk (m ≫ f.hom) ⟶  f) by apply congrArg CommaMorphism.left this
  rw [← cancel_mono k]
  ext
  apply a
#align category_theory.over.mono_left_of_mono CategoryTheory.Over.mono_left_of_mono

section IteratedSlice

variable (f : Over X)

/-- Given f : Y ⟶ X, this is the obvious functor from (T/X)/f to T/Y -/
@[simps]
def iteratedSliceForward : Over f ⥤ Over f.left
    where
  obj α := Over.mk α.hom.left
  map κ := Over.homMk κ.left.left (by dsimp; rw [← Over.w κ]; rfl)
#align category_theory.over.iterated_slice_forward CategoryTheory.Over.iteratedSliceForward

/-- Given f : Y ⟶ X, this is the obvious functor from T/Y to (T/X)/f -/
@[simps]
def iteratedSliceBackward : Over f.left ⥤ Over f
    where
  obj g := mk (homMk g.hom : mk (g.hom ≫ f.hom) ⟶ f)
  map α := homMk (homMk α.left (w_assoc α f.hom)) (OverMorphism.ext (w α))
#align category_theory.over.iterated_slice_backward CategoryTheory.Over.iteratedSliceBackward

/-- Given f : Y ⟶ X, we have an equivalence between (T/X)/f and T/Y -/
@[simps]
def iteratedSliceEquiv : Over f ≌ Over f.left
    where
  functor := iteratedSliceForward f
  inverse := iteratedSliceBackward f
  unitIso :=
    NatIso.ofComponents (fun g => Over.isoMk (Over.isoMk (Iso.refl _)
      (by aesop_cat)) (by aesop_cat)) fun g => by ext; dsimp; simp
  counitIso :=
    NatIso.ofComponents (fun g => Over.isoMk (Iso.refl _) (by aesop_cat)) fun g =>
      by ext; dsimp; simp
#align category_theory.over.iterated_slice_equiv CategoryTheory.Over.iteratedSliceEquiv

theorem iteratedSliceForward_forget :
    iteratedSliceForward f ⋙ forget f.left = forget f ⋙ forget X :=
  rfl
#align category_theory.over.iterated_slice_forward_forget CategoryTheory.Over.iteratedSliceForward_forget

theorem iteratedSliceBackward_forget_forget :
    iteratedSliceBackward f ⋙ forget f ⋙ forget X = forget f.left :=
  rfl
#align category_theory.over.iterated_slice_backward_forget_forget CategoryTheory.Over.iteratedSliceBackward_forget_forget

end IteratedSlice

section

variable {D : Type u₂} [Category.{v₂} D]

/-- A functor `F : T ⥤ D` induces a functor `Over X ⥤ Over (F.obj X)` in the obvious way. -/
@[simps]
def post (F : T ⥤ D) : Over X ⥤ Over (F.obj X)
    where
  obj Y := mk <| F.map Y.hom
  map f := Over.homMk (F.map f.left) (by aesop_cat_nonterminal; erw [← F.map_comp, w])
#align category_theory.over.post CategoryTheory.Over.post

end

end Over

/-- The under category has as objects arrows with domain `X` and as morphisms commutative
    triangles. -/
def Under (X : T) :=
  StructuredArrow X (𝟭 T)
#align category_theory.under CategoryTheory.Under

instance (X : T) : Category (Under X) := commaCategory

-- Satisfying the inhabited linter
instance Under.inhabited [Inhabited T] : Inhabited (Under (default : T))
    where default :=
    { left := default
      right := default
      hom := 𝟙 _ }
#align category_theory.under.inhabited CategoryTheory.Under.inhabited

namespace Under

variable {X : T}

@[ext]
theorem UnderMorphism.ext {X : T} {U V : Under X} {f g : U ⟶ V} (h : f.right = g.right) : f = g :=
  by
  let ⟨_,b,_⟩ := f; let ⟨_,e,_⟩ := g
  congr; simp only [eq_iff_true_of_subsingleton]
#align category_theory.under.under_morphism.ext CategoryTheory.Under.UnderMorphism.ext

-- @[simp] Porting note: simp can prove this
theorem under_left (U : Under X) : U.left = ⟨⟨⟩⟩ := by simp only
#align category_theory.under.under_left CategoryTheory.Under.under_left

@[simp]
theorem id_right (U : Under X) : CommaMorphism.right (𝟙 U) = 𝟙 U.right :=
  rfl
#align category_theory.under.id_right CategoryTheory.Under.id_right

@[simp]
theorem comp_right (a b c : Under X) (f : a ⟶ b) (g : b ⟶ c) : (f ≫ g).right = f.right ≫ g.right :=
  rfl
#align category_theory.under.comp_right CategoryTheory.Under.comp_right

@[reassoc (attr := simp)]
theorem w {A B : Under X} (f : A ⟶ B) : A.hom ≫ f.right = B.hom := by have := f.w; aesop_cat
#align category_theory.under.w CategoryTheory.Under.w

/-- To give an object in the under category, it suffices to give an arrow with domain `X`. -/
@[simps! right hom]
def mk {X Y : T} (f : X ⟶ Y) : Under X :=
  StructuredArrow.mk f
#align category_theory.under.mk CategoryTheory.Under.mk

/-- To give a morphism in the under category, it suffices to give a morphism fitting in a
    commutative triangle. -/
@[simps!]
def homMk {U V : Under X} (f : U.right ⟶ V.right) (w : U.hom ≫ f = V.hom := by aesop_cat) : U ⟶ V :=
  StructuredArrow.homMk f w
#align category_theory.under.hom_mk CategoryTheory.Under.homMk

-- Porting note: simp solves this; simpNF still sees them after `-simp` (?)
attribute [-simp, nolint simpNF] homMk_left_down_down

/-- Construct an isomorphism in the over category given isomorphisms of the objects whose forward
direction gives a commutative triangle.
-/
def isoMk {f g : Under X} (hr : f.right ≅ g.right) (hw : f.hom ≫ hr.hom = g.hom) : f ≅ g :=
  StructuredArrow.isoMk hr hw
#align category_theory.under.iso_mk CategoryTheory.Under.isoMk

@[simp]
theorem isoMk_hom_right {f g : Under X} (hr : f.right ≅ g.right) (hw : f.hom ≫ hr.hom = g.hom) :
    (isoMk hr hw).hom.right = hr.hom :=
  rfl
#align category_theory.under.iso_mk_hom_right CategoryTheory.Under.isoMk_hom_right

@[simp]
theorem isoMk_inv_right {f g : Under X} (hr : f.right ≅ g.right) (hw : f.hom ≫ hr.hom = g.hom) :
    (isoMk hr hw).inv.right = hr.inv :=
  rfl
#align category_theory.under.iso_mk_inv_right CategoryTheory.Under.isoMk_inv_right

section

variable (X)

/-- The forgetful functor mapping an arrow to its domain. -/
def forget : Under X ⥤ T :=
  Comma.snd _ _
#align category_theory.under.forget CategoryTheory.Under.forget

end

@[simp]
theorem forget_obj {U : Under X} : (forget X).obj U = U.right :=
  rfl
#align category_theory.under.forget_obj CategoryTheory.Under.forget_obj

@[simp]
theorem forget_map {U V : Under X} {f : U ⟶ V} : (forget X).map f = f.right :=
  rfl
#align category_theory.under.forget_map CategoryTheory.Under.forget_map

/-- The natural cone over the forgetful functor `Under X ⥤ T` with cone point `X`. -/
@[simps]
def forgetCone (X : T) : Limits.Cone (forget X) :=
  { pt := X
    π := { app := Comma.hom } }
#align category_theory.under.forget_cone CategoryTheory.Under.forgetCone

/-- A morphism `X ⟶ Y` induces a functor `Under Y ⥤ Under X` in the obvious way. -/
def map {Y : T} (f : X ⟶ Y) : Under Y ⥤ Under X :=
  Comma.mapLeft _ <| Discrete.natTrans fun _ => f
#align category_theory.under.map CategoryTheory.Under.map

section

variable {Y : T} {f : X ⟶ Y} {U V : Under Y} {g : U ⟶ V}

@[simp]
theorem map_obj_right : ((map f).obj U).right = U.right :=
  rfl
#align category_theory.under.map_obj_right CategoryTheory.Under.map_obj_right

@[simp]
theorem map_obj_hom : ((map f).obj U).hom = f ≫ U.hom :=
  rfl
#align category_theory.under.map_obj_hom CategoryTheory.Under.map_obj_hom

@[simp]
theorem map_map_right : ((map f).map g).right = g.right :=
  rfl
#align category_theory.under.map_map_right CategoryTheory.Under.map_map_right

/-- Mapping by the identity morphism is just the identity functor. -/
def mapId : map (𝟙 Y) ≅ 𝟭 _ :=
  NatIso.ofComponents (fun X => isoMk (Iso.refl _) (by aesop_cat)) (by aesop_cat)
#align category_theory.under.map_id CategoryTheory.Under.mapId

/-- Mapping by the composite morphism `f ≫ g` is the same as mapping by `f` then by `g`. -/
def mapComp {Y Z : T} (f : X ⟶ Y) (g : Y ⟶ Z) : map (f ≫ g) ≅ map g ⋙ map f :=
  NatIso.ofComponents (fun X => isoMk (Iso.refl _) (by aesop_cat)) (by aesop_cat)
#align category_theory.under.map_comp CategoryTheory.Under.mapComp

end

instance forget_reflects_iso : ReflectsIsomorphisms (forget X) where
  reflects {Y Z} f t := by
    let g : Z ⟶  Y := Under.homMk (inv ((Under.forget X).map f))
      ((IsIso.comp_inv_eq _).2 (Under.w f).symm)
    dsimp [forget] at t
    refine ⟨⟨g, ⟨?_,?_⟩⟩⟩
    repeat (ext; simp)
#align category_theory.under.forget_reflects_iso CategoryTheory.Under.forget_reflects_iso

instance forget_faithful : Faithful (forget X) where
#align category_theory.under.forget_faithful CategoryTheory.Under.forget_faithful

-- TODO: Show the converse holds if `T` has binary coproducts.
/-- If `k.right` is a monomorphism, then `k` is a monomorphism. In other words, `Under.forget X`
reflects epimorphisms.
The converse does not hold without additional assumptions on the underlying category, see
`CategoryTheory.Under.mono_right_of_mono`.
-/
theorem mono_of_mono_right {f g : Under X} (k : f ⟶ g) [hk : Mono k.right] : Mono k :=
  (forget X).mono_of_mono_map hk
#align category_theory.under.mono_of_mono_right CategoryTheory.Under.mono_of_mono_right

/--
If `k.right` is a epimorphism, then `k` is a epimorphism. In other words, `Under.forget X` reflects
epimorphisms.
The converse of `CategoryTheory.Under.epi_right_of_epi`.

This lemma is not an instance, to avoid loops in type class inference.
-/
theorem epi_of_epi_right {f g : Under X} (k : f ⟶ g) [hk : Epi k.right] : Epi k :=
  (forget X).epi_of_epi_map hk
#align category_theory.under.epi_of_epi_right CategoryTheory.Under.epi_of_epi_right

/--
If `k` is a epimorphism, then `k.right` is a epimorphism. In other words, `Under.forget X` preserves
epimorphisms.
The converse of `CategoryTheory.under.epi_of_epi_right`.
-/
instance epi_right_of_epi {f g : Under X} (k : f ⟶ g) [Epi k] : Epi k.right := by
  refine' ⟨fun { Y : T } l m a => _⟩
  let l' : g ⟶ mk (g.hom ≫ m) := homMk l (by
    dsimp; rw [← Under.w k, Category.assoc, a, Category.assoc])
  -- Porting note: add type ascription here to `homMk m`
  suffices l' = (homMk m  : g ⟶  mk (g.hom ≫ m)) by apply congrArg CommaMorphism.right this
  rw [← cancel_epi k]; ext; apply a
#align category_theory.under.epi_right_of_epi CategoryTheory.Under.epi_right_of_epi

section

variable {D : Type u₂} [Category.{v₂} D]

/-- A functor `F : T ⥤ D` induces a functor `Under X ⥤ Under (F.obj X)` in the obvious way. -/
@[simps]
def post {X : T} (F : T ⥤ D) : Under X ⥤ Under (F.obj X) where
  obj Y := mk <| F.map Y.hom
  map f := Under.homMk (F.map f.right) (by aesop_cat_nonterminal; erw [← F.map_comp, w])
#align category_theory.under.post CategoryTheory.Under.post

end

end Under

end CategoryTheory


/-
Copyright (c) 2018 Chris Hughes. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Chris Hughes, Abhimanyu Pallavi Sudhir, Jean Lo, Calle Sönne, Benjamin Davidson

! This file was ported from Lean 3 source module analysis.special_functions.trigonometric.basic
! leanprover-community/mathlib commit f2ce6086713c78a7f880485f7917ea547a215982
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Analysis.SpecialFunctions.Exp
import Mathbin.Data.Set.Intervals.Infinite

/-!
# Trigonometric functions

## Main definitions

This file contains the definition of `π`.

See also `analysis.special_functions.trigonometric.inverse` and
`analysis.special_functions.trigonometric.arctan` for the inverse trigonometric functions.

See also `analysis.special_functions.complex.arg` and
`analysis.special_functions.complex.log` for the complex argument function
and the complex logarithm.

## Main statements

Many basic inequalities on the real trigonometric functions are established.

The continuity of the usual trigonometric functions is proved.

Several facts about the real trigonometric functions have the proofs deferred to
`analysis.special_functions.trigonometric.complex`,
as they are most easily proved by appealing to the corresponding fact for
complex trigonometric functions.

See also `analysis.special_functions.trigonometric.chebyshev` for the multiple angle formulas
in terms of Chebyshev polynomials.

## Tags

sin, cos, tan, angle
-/

noncomputable section

open Classical Topology Filter

open Set Filter

namespace Complex

@[continuity]
theorem continuous_sin : Continuous sin :=
  by
  change Continuous fun z => (exp (-z * I) - exp (z * I)) * I / 2
  continuity
#align complex.continuous_sin Complex.continuous_sin

theorem continuousOn_sin {s : Set ℂ} : ContinuousOn sin s :=
  continuous_sin.ContinuousOn
#align complex.continuous_on_sin Complex.continuousOn_sin

@[continuity]
theorem continuous_cos : Continuous cos :=
  by
  change Continuous fun z => (exp (z * I) + exp (-z * I)) / 2
  continuity
#align complex.continuous_cos Complex.continuous_cos

theorem continuousOn_cos {s : Set ℂ} : ContinuousOn cos s :=
  continuous_cos.ContinuousOn
#align complex.continuous_on_cos Complex.continuousOn_cos

@[continuity]
theorem continuous_sinh : Continuous sinh :=
  by
  change Continuous fun z => (exp z - exp (-z)) / 2
  continuity
#align complex.continuous_sinh Complex.continuous_sinh

@[continuity]
theorem continuous_cosh : Continuous cosh :=
  by
  change Continuous fun z => (exp z + exp (-z)) / 2
  continuity
#align complex.continuous_cosh Complex.continuous_cosh

end Complex

namespace Real

variable {x y z : ℝ}

@[continuity]
theorem continuous_sin : Continuous sin :=
  Complex.continuous_re.comp (Complex.continuous_sin.comp Complex.continuous_of_real)
#align real.continuous_sin Real.continuous_sin

theorem continuousOn_sin {s} : ContinuousOn sin s :=
  continuous_sin.ContinuousOn
#align real.continuous_on_sin Real.continuousOn_sin

@[continuity]
theorem continuous_cos : Continuous cos :=
  Complex.continuous_re.comp (Complex.continuous_cos.comp Complex.continuous_of_real)
#align real.continuous_cos Real.continuous_cos

theorem continuousOn_cos {s} : ContinuousOn cos s :=
  continuous_cos.ContinuousOn
#align real.continuous_on_cos Real.continuousOn_cos

@[continuity]
theorem continuous_sinh : Continuous sinh :=
  Complex.continuous_re.comp (Complex.continuous_sinh.comp Complex.continuous_of_real)
#align real.continuous_sinh Real.continuous_sinh

@[continuity]
theorem continuous_cosh : Continuous cosh :=
  Complex.continuous_re.comp (Complex.continuous_cosh.comp Complex.continuous_of_real)
#align real.continuous_cosh Real.continuous_cosh

end Real

namespace Real

theorem exists_cos_eq_zero : 0 ∈ cos '' Icc (1 : ℝ) 2 :=
  intermediate_value_Icc' (by norm_num) continuousOn_cos
    ⟨le_of_lt cos_two_neg, le_of_lt cos_one_pos⟩
#align real.exists_cos_eq_zero Real.exists_cos_eq_zero

/-- The number π = 3.14159265... Defined here using choice as twice a zero of cos in [1,2], from
which one can derive all its properties. For explicit bounds on π, see `data.real.pi.bounds`. -/
protected noncomputable def pi : ℝ :=
  2 * Classical.choose exists_cos_eq_zero
#align real.pi Real.pi

-- mathport name: real.pi
scoped notation "π" => Real.pi

@[simp]
theorem cos_pi_div_two : cos (π / 2) = 0 := by
  rw [Real.pi, mul_div_cancel_left _ (two_ne_zero' ℝ)] <;>
    exact (Classical.choose_spec exists_cos_eq_zero).2
#align real.cos_pi_div_two Real.cos_pi_div_two

theorem one_le_pi_div_two : (1 : ℝ) ≤ π / 2 := by
  rw [Real.pi, mul_div_cancel_left _ (two_ne_zero' ℝ)] <;>
    exact (Classical.choose_spec exists_cos_eq_zero).1.1
#align real.one_le_pi_div_two Real.one_le_pi_div_two

theorem pi_div_two_le_two : π / 2 ≤ 2 := by
  rw [Real.pi, mul_div_cancel_left _ (two_ne_zero' ℝ)] <;>
    exact (Classical.choose_spec exists_cos_eq_zero).1.2
#align real.pi_div_two_le_two Real.pi_div_two_le_two

theorem two_le_pi : (2 : ℝ) ≤ π :=
  (div_le_div_right (show (0 : ℝ) < 2 by norm_num)).1
    (by rw [div_self (two_ne_zero' ℝ)] <;> exact one_le_pi_div_two)
#align real.two_le_pi Real.two_le_pi

theorem pi_le_four : π ≤ 4 :=
  (div_le_div_right (show (0 : ℝ) < 2 by norm_num)).1
    (calc
      π / 2 ≤ 2 := pi_div_two_le_two
      _ = 4 / 2 := by norm_num
      )
#align real.pi_le_four Real.pi_le_four

theorem pi_pos : 0 < π :=
  lt_of_lt_of_le (by norm_num) two_le_pi
#align real.pi_pos Real.pi_pos

theorem pi_ne_zero : π ≠ 0 :=
  ne_of_gt pi_pos
#align real.pi_ne_zero Real.pi_ne_zero

theorem pi_div_two_pos : 0 < π / 2 :=
  half_pos pi_pos
#align real.pi_div_two_pos Real.pi_div_two_pos

theorem two_pi_pos : 0 < 2 * π := by linarith [pi_pos]
#align real.two_pi_pos Real.two_pi_pos

end Real

namespace NNReal

open Real

open Real NNReal

/-- `π` considered as a nonnegative real. -/
noncomputable def pi : ℝ≥0 :=
  ⟨π, Real.pi_pos.le⟩
#align nnreal.pi NNReal.pi

@[simp]
theorem coe_real_pi : (pi : ℝ) = π :=
  rfl
#align nnreal.coe_real_pi NNReal.coe_real_pi

theorem pi_pos : 0 < pi := by exact_mod_cast Real.pi_pos
#align nnreal.pi_pos NNReal.pi_pos

theorem pi_ne_zero : pi ≠ 0 :=
  pi_pos.ne'
#align nnreal.pi_ne_zero NNReal.pi_ne_zero

end NNReal

namespace Real

open Real

@[simp]
theorem sin_pi : sin π = 0 := by
  rw [← mul_div_cancel_left π (two_ne_zero' ℝ), two_mul, add_div, sin_add, cos_pi_div_two] <;> simp
#align real.sin_pi Real.sin_pi

@[simp]
theorem cos_pi : cos π = -1 := by
  rw [← mul_div_cancel_left π (two_ne_zero' ℝ), mul_div_assoc, cos_two_mul, cos_pi_div_two] <;>
    simp [bit0, pow_add]
#align real.cos_pi Real.cos_pi

@[simp]
theorem sin_two_pi : sin (2 * π) = 0 := by simp [two_mul, sin_add]
#align real.sin_two_pi Real.sin_two_pi

@[simp]
theorem cos_two_pi : cos (2 * π) = 1 := by simp [two_mul, cos_add]
#align real.cos_two_pi Real.cos_two_pi

theorem sin_antiperiodic : Function.Antiperiodic sin π := by simp [sin_add]
#align real.sin_antiperiodic Real.sin_antiperiodic

theorem sin_periodic : Function.Periodic sin (2 * π) :=
  sin_antiperiodic.Periodic
#align real.sin_periodic Real.sin_periodic

@[simp]
theorem sin_add_pi (x : ℝ) : sin (x + π) = -sin x :=
  sin_antiperiodic x
#align real.sin_add_pi Real.sin_add_pi

@[simp]
theorem sin_add_two_pi (x : ℝ) : sin (x + 2 * π) = sin x :=
  sin_periodic x
#align real.sin_add_two_pi Real.sin_add_two_pi

@[simp]
theorem sin_sub_pi (x : ℝ) : sin (x - π) = -sin x :=
  sin_antiperiodic.sub_eq x
#align real.sin_sub_pi Real.sin_sub_pi

@[simp]
theorem sin_sub_two_pi (x : ℝ) : sin (x - 2 * π) = sin x :=
  sin_periodic.sub_eq x
#align real.sin_sub_two_pi Real.sin_sub_two_pi

@[simp]
theorem sin_pi_sub (x : ℝ) : sin (π - x) = sin x :=
  neg_neg (sin x) ▸ sin_neg x ▸ sin_antiperiodic.sub_eq'
#align real.sin_pi_sub Real.sin_pi_sub

@[simp]
theorem sin_two_pi_sub (x : ℝ) : sin (2 * π - x) = -sin x :=
  sin_neg x ▸ sin_periodic.sub_eq'
#align real.sin_two_pi_sub Real.sin_two_pi_sub

@[simp]
theorem sin_nat_mul_pi (n : ℕ) : sin (n * π) = 0 :=
  sin_antiperiodic.nat_mul_eq_of_eq_zero sin_zero n
#align real.sin_nat_mul_pi Real.sin_nat_mul_pi

@[simp]
theorem sin_int_mul_pi (n : ℤ) : sin (n * π) = 0 :=
  sin_antiperiodic.int_mul_eq_of_eq_zero sin_zero n
#align real.sin_int_mul_pi Real.sin_int_mul_pi

@[simp]
theorem sin_add_nat_mul_two_pi (x : ℝ) (n : ℕ) : sin (x + n * (2 * π)) = sin x :=
  sin_periodic.nat_mul n x
#align real.sin_add_nat_mul_two_pi Real.sin_add_nat_mul_two_pi

@[simp]
theorem sin_add_int_mul_two_pi (x : ℝ) (n : ℤ) : sin (x + n * (2 * π)) = sin x :=
  sin_periodic.int_mul n x
#align real.sin_add_int_mul_two_pi Real.sin_add_int_mul_two_pi

@[simp]
theorem sin_sub_nat_mul_two_pi (x : ℝ) (n : ℕ) : sin (x - n * (2 * π)) = sin x :=
  sin_periodic.sub_nat_mul_eq n
#align real.sin_sub_nat_mul_two_pi Real.sin_sub_nat_mul_two_pi

@[simp]
theorem sin_sub_int_mul_two_pi (x : ℝ) (n : ℤ) : sin (x - n * (2 * π)) = sin x :=
  sin_periodic.sub_int_mul_eq n
#align real.sin_sub_int_mul_two_pi Real.sin_sub_int_mul_two_pi

@[simp]
theorem sin_nat_mul_two_pi_sub (x : ℝ) (n : ℕ) : sin (n * (2 * π) - x) = -sin x :=
  sin_neg x ▸ sin_periodic.nat_mul_sub_eq n
#align real.sin_nat_mul_two_pi_sub Real.sin_nat_mul_two_pi_sub

@[simp]
theorem sin_int_mul_two_pi_sub (x : ℝ) (n : ℤ) : sin (n * (2 * π) - x) = -sin x :=
  sin_neg x ▸ sin_periodic.int_mul_sub_eq n
#align real.sin_int_mul_two_pi_sub Real.sin_int_mul_two_pi_sub

theorem cos_antiperiodic : Function.Antiperiodic cos π := by simp [cos_add]
#align real.cos_antiperiodic Real.cos_antiperiodic

theorem cos_periodic : Function.Periodic cos (2 * π) :=
  cos_antiperiodic.Periodic
#align real.cos_periodic Real.cos_periodic

@[simp]
theorem cos_add_pi (x : ℝ) : cos (x + π) = -cos x :=
  cos_antiperiodic x
#align real.cos_add_pi Real.cos_add_pi

@[simp]
theorem cos_add_two_pi (x : ℝ) : cos (x + 2 * π) = cos x :=
  cos_periodic x
#align real.cos_add_two_pi Real.cos_add_two_pi

@[simp]
theorem cos_sub_pi (x : ℝ) : cos (x - π) = -cos x :=
  cos_antiperiodic.sub_eq x
#align real.cos_sub_pi Real.cos_sub_pi

@[simp]
theorem cos_sub_two_pi (x : ℝ) : cos (x - 2 * π) = cos x :=
  cos_periodic.sub_eq x
#align real.cos_sub_two_pi Real.cos_sub_two_pi

@[simp]
theorem cos_pi_sub (x : ℝ) : cos (π - x) = -cos x :=
  cos_neg x ▸ cos_antiperiodic.sub_eq'
#align real.cos_pi_sub Real.cos_pi_sub

@[simp]
theorem cos_two_pi_sub (x : ℝ) : cos (2 * π - x) = cos x :=
  cos_neg x ▸ cos_periodic.sub_eq'
#align real.cos_two_pi_sub Real.cos_two_pi_sub

@[simp]
theorem cos_nat_mul_two_pi (n : ℕ) : cos (n * (2 * π)) = 1 :=
  (cos_periodic.nat_mul_eq n).trans cos_zero
#align real.cos_nat_mul_two_pi Real.cos_nat_mul_two_pi

@[simp]
theorem cos_int_mul_two_pi (n : ℤ) : cos (n * (2 * π)) = 1 :=
  (cos_periodic.int_mul_eq n).trans cos_zero
#align real.cos_int_mul_two_pi Real.cos_int_mul_two_pi

@[simp]
theorem cos_add_nat_mul_two_pi (x : ℝ) (n : ℕ) : cos (x + n * (2 * π)) = cos x :=
  cos_periodic.nat_mul n x
#align real.cos_add_nat_mul_two_pi Real.cos_add_nat_mul_two_pi

@[simp]
theorem cos_add_int_mul_two_pi (x : ℝ) (n : ℤ) : cos (x + n * (2 * π)) = cos x :=
  cos_periodic.int_mul n x
#align real.cos_add_int_mul_two_pi Real.cos_add_int_mul_two_pi

@[simp]
theorem cos_sub_nat_mul_two_pi (x : ℝ) (n : ℕ) : cos (x - n * (2 * π)) = cos x :=
  cos_periodic.sub_nat_mul_eq n
#align real.cos_sub_nat_mul_two_pi Real.cos_sub_nat_mul_two_pi

@[simp]
theorem cos_sub_int_mul_two_pi (x : ℝ) (n : ℤ) : cos (x - n * (2 * π)) = cos x :=
  cos_periodic.sub_int_mul_eq n
#align real.cos_sub_int_mul_two_pi Real.cos_sub_int_mul_two_pi

@[simp]
theorem cos_nat_mul_two_pi_sub (x : ℝ) (n : ℕ) : cos (n * (2 * π) - x) = cos x :=
  cos_neg x ▸ cos_periodic.nat_mul_sub_eq n
#align real.cos_nat_mul_two_pi_sub Real.cos_nat_mul_two_pi_sub

@[simp]
theorem cos_int_mul_two_pi_sub (x : ℝ) (n : ℤ) : cos (n * (2 * π) - x) = cos x :=
  cos_neg x ▸ cos_periodic.int_mul_sub_eq n
#align real.cos_int_mul_two_pi_sub Real.cos_int_mul_two_pi_sub

@[simp]
theorem cos_nat_mul_two_pi_add_pi (n : ℕ) : cos (n * (2 * π) + π) = -1 := by
  simpa only [cos_zero] using (cos_periodic.nat_mul n).add_antiperiod_eq cos_antiperiodic
#align real.cos_nat_mul_two_pi_add_pi Real.cos_nat_mul_two_pi_add_pi

@[simp]
theorem cos_int_mul_two_pi_add_pi (n : ℤ) : cos (n * (2 * π) + π) = -1 := by
  simpa only [cos_zero] using (cos_periodic.int_mul n).add_antiperiod_eq cos_antiperiodic
#align real.cos_int_mul_two_pi_add_pi Real.cos_int_mul_two_pi_add_pi

@[simp]
theorem cos_nat_mul_two_pi_sub_pi (n : ℕ) : cos (n * (2 * π) - π) = -1 := by
  simpa only [cos_zero] using (cos_periodic.nat_mul n).sub_antiperiod_eq cos_antiperiodic
#align real.cos_nat_mul_two_pi_sub_pi Real.cos_nat_mul_two_pi_sub_pi

@[simp]
theorem cos_int_mul_two_pi_sub_pi (n : ℤ) : cos (n * (2 * π) - π) = -1 := by
  simpa only [cos_zero] using (cos_periodic.int_mul n).sub_antiperiod_eq cos_antiperiodic
#align real.cos_int_mul_two_pi_sub_pi Real.cos_int_mul_two_pi_sub_pi

theorem sin_pos_of_pos_of_lt_pi {x : ℝ} (h0x : 0 < x) (hxp : x < π) : 0 < sin x :=
  if hx2 : x ≤ 2 then sin_pos_of_pos_of_le_two h0x hx2
  else
    have : (2 : ℝ) + 2 = 4 := rfl
    have : π - x ≤ 2 :=
      sub_le_iff_le_add.2 (le_trans pi_le_four (this ▸ add_le_add_left (le_of_not_ge hx2) _))
    sin_pi_sub x ▸ sin_pos_of_pos_of_le_two (sub_pos.2 hxp) this
#align real.sin_pos_of_pos_of_lt_pi Real.sin_pos_of_pos_of_lt_pi

theorem sin_pos_of_mem_Ioo {x : ℝ} (hx : x ∈ Ioo 0 π) : 0 < sin x :=
  sin_pos_of_pos_of_lt_pi hx.1 hx.2
#align real.sin_pos_of_mem_Ioo Real.sin_pos_of_mem_Ioo

theorem sin_nonneg_of_mem_Icc {x : ℝ} (hx : x ∈ Icc 0 π) : 0 ≤ sin x :=
  by
  rw [← closure_Ioo pi_ne_zero.symm] at hx
  exact
    closure_lt_subset_le continuous_const continuous_sin
      (closure_mono (fun y => sin_pos_of_mem_Ioo) hx)
#align real.sin_nonneg_of_mem_Icc Real.sin_nonneg_of_mem_Icc

theorem sin_nonneg_of_nonneg_of_le_pi {x : ℝ} (h0x : 0 ≤ x) (hxp : x ≤ π) : 0 ≤ sin x :=
  sin_nonneg_of_mem_Icc ⟨h0x, hxp⟩
#align real.sin_nonneg_of_nonneg_of_le_pi Real.sin_nonneg_of_nonneg_of_le_pi

theorem sin_neg_of_neg_of_neg_pi_lt {x : ℝ} (hx0 : x < 0) (hpx : -π < x) : sin x < 0 :=
  neg_pos.1 <| sin_neg x ▸ sin_pos_of_pos_of_lt_pi (neg_pos.2 hx0) (neg_lt.1 hpx)
#align real.sin_neg_of_neg_of_neg_pi_lt Real.sin_neg_of_neg_of_neg_pi_lt

theorem sin_nonpos_of_nonnpos_of_neg_pi_le {x : ℝ} (hx0 : x ≤ 0) (hpx : -π ≤ x) : sin x ≤ 0 :=
  neg_nonneg.1 <| sin_neg x ▸ sin_nonneg_of_nonneg_of_le_pi (neg_nonneg.2 hx0) (neg_le.1 hpx)
#align real.sin_nonpos_of_nonnpos_of_neg_pi_le Real.sin_nonpos_of_nonnpos_of_neg_pi_le

@[simp]
theorem sin_pi_div_two : sin (π / 2) = 1 :=
  have : sin (π / 2) = 1 ∨ sin (π / 2) = -1 := by
    simpa [sq, mul_self_eq_one_iff] using sin_sq_add_cos_sq (π / 2)
  this.resolve_right fun h =>
    show ¬(0 : ℝ) < -1 by norm_num <|
      h ▸ sin_pos_of_pos_of_lt_pi pi_div_two_pos (half_lt_self pi_pos)
#align real.sin_pi_div_two Real.sin_pi_div_two

theorem sin_add_pi_div_two (x : ℝ) : sin (x + π / 2) = cos x := by simp [sin_add]
#align real.sin_add_pi_div_two Real.sin_add_pi_div_two

theorem sin_sub_pi_div_two (x : ℝ) : sin (x - π / 2) = -cos x := by simp [sub_eq_add_neg, sin_add]
#align real.sin_sub_pi_div_two Real.sin_sub_pi_div_two

theorem sin_pi_div_two_sub (x : ℝ) : sin (π / 2 - x) = cos x := by simp [sub_eq_add_neg, sin_add]
#align real.sin_pi_div_two_sub Real.sin_pi_div_two_sub

theorem cos_add_pi_div_two (x : ℝ) : cos (x + π / 2) = -sin x := by simp [cos_add]
#align real.cos_add_pi_div_two Real.cos_add_pi_div_two

theorem cos_sub_pi_div_two (x : ℝ) : cos (x - π / 2) = sin x := by simp [sub_eq_add_neg, cos_add]
#align real.cos_sub_pi_div_two Real.cos_sub_pi_div_two

theorem cos_pi_div_two_sub (x : ℝ) : cos (π / 2 - x) = sin x := by
  rw [← cos_neg, neg_sub, cos_sub_pi_div_two]
#align real.cos_pi_div_two_sub Real.cos_pi_div_two_sub

theorem cos_pos_of_mem_Ioo {x : ℝ} (hx : x ∈ Ioo (-(π / 2)) (π / 2)) : 0 < cos x :=
  sin_add_pi_div_two x ▸ sin_pos_of_mem_Ioo ⟨by linarith [hx.1], by linarith [hx.2]⟩
#align real.cos_pos_of_mem_Ioo Real.cos_pos_of_mem_Ioo

theorem cos_nonneg_of_mem_Icc {x : ℝ} (hx : x ∈ Icc (-(π / 2)) (π / 2)) : 0 ≤ cos x :=
  sin_add_pi_div_two x ▸ sin_nonneg_of_mem_Icc ⟨by linarith [hx.1], by linarith [hx.2]⟩
#align real.cos_nonneg_of_mem_Icc Real.cos_nonneg_of_mem_Icc

theorem cos_nonneg_of_neg_pi_div_two_le_of_le {x : ℝ} (hl : -(π / 2) ≤ x) (hu : x ≤ π / 2) :
    0 ≤ cos x :=
  cos_nonneg_of_mem_Icc ⟨hl, hu⟩
#align real.cos_nonneg_of_neg_pi_div_two_le_of_le Real.cos_nonneg_of_neg_pi_div_two_le_of_le

theorem cos_neg_of_pi_div_two_lt_of_lt {x : ℝ} (hx₁ : π / 2 < x) (hx₂ : x < π + π / 2) :
    cos x < 0 :=
  neg_pos.1 <| cos_pi_sub x ▸ cos_pos_of_mem_Ioo ⟨by linarith, by linarith⟩
#align real.cos_neg_of_pi_div_two_lt_of_lt Real.cos_neg_of_pi_div_two_lt_of_lt

theorem cos_nonpos_of_pi_div_two_le_of_le {x : ℝ} (hx₁ : π / 2 ≤ x) (hx₂ : x ≤ π + π / 2) :
    cos x ≤ 0 :=
  neg_nonneg.1 <| cos_pi_sub x ▸ cos_nonneg_of_mem_Icc ⟨by linarith, by linarith⟩
#align real.cos_nonpos_of_pi_div_two_le_of_le Real.cos_nonpos_of_pi_div_two_le_of_le

theorem sin_eq_sqrt_one_sub_cos_sq {x : ℝ} (hl : 0 ≤ x) (hu : x ≤ π) :
    sin x = sqrt (1 - cos x ^ 2) := by
  rw [← abs_sin_eq_sqrt_one_sub_cos_sq, abs_of_nonneg (sin_nonneg_of_nonneg_of_le_pi hl hu)]
#align real.sin_eq_sqrt_one_sub_cos_sq Real.sin_eq_sqrt_one_sub_cos_sq

theorem cos_eq_sqrt_one_sub_sin_sq {x : ℝ} (hl : -(π / 2) ≤ x) (hu : x ≤ π / 2) :
    cos x = sqrt (1 - sin x ^ 2) := by
  rw [← abs_cos_eq_sqrt_one_sub_sin_sq, abs_of_nonneg (cos_nonneg_of_mem_Icc ⟨hl, hu⟩)]
#align real.cos_eq_sqrt_one_sub_sin_sq Real.cos_eq_sqrt_one_sub_sin_sq

theorem sin_eq_zero_iff_of_lt_of_lt {x : ℝ} (hx₁ : -π < x) (hx₂ : x < π) : sin x = 0 ↔ x = 0 :=
  ⟨fun h =>
    le_antisymm
      (le_of_not_gt fun h0 =>
        lt_irrefl (0 : ℝ) <|
          calc
            0 < sin x := sin_pos_of_pos_of_lt_pi h0 hx₂
            _ = 0 := h
            )
      (le_of_not_gt fun h0 =>
        lt_irrefl (0 : ℝ) <|
          calc
            0 = sin x := h.symm
            _ < 0 := sin_neg_of_neg_of_neg_pi_lt h0 hx₁
            ),
    fun h => by simp [h]⟩
#align real.sin_eq_zero_iff_of_lt_of_lt Real.sin_eq_zero_iff_of_lt_of_lt

theorem sin_eq_zero_iff {x : ℝ} : sin x = 0 ↔ ∃ n : ℤ, (n : ℝ) * π = x :=
  ⟨fun h =>
    ⟨⌊x / π⌋,
      le_antisymm (sub_nonneg.1 (Int.sub_floor_div_mul_nonneg _ pi_pos))
        (sub_nonpos.1 <|
          le_of_not_gt fun h₃ =>
            (sin_pos_of_pos_of_lt_pi h₃ (Int.sub_floor_div_mul_lt _ pi_pos)).Ne
              (by simp [sub_eq_add_neg, sin_add, h, sin_int_mul_pi]))⟩,
    fun ⟨n, hn⟩ => hn ▸ sin_int_mul_pi _⟩
#align real.sin_eq_zero_iff Real.sin_eq_zero_iff

theorem sin_ne_zero_iff {x : ℝ} : sin x ≠ 0 ↔ ∀ n : ℤ, (n : ℝ) * π ≠ x := by
  rw [← not_exists, not_iff_not, sin_eq_zero_iff]
#align real.sin_ne_zero_iff Real.sin_ne_zero_iff

theorem sin_eq_zero_iff_cos_eq {x : ℝ} : sin x = 0 ↔ cos x = 1 ∨ cos x = -1 := by
  rw [← mul_self_eq_one_iff, ← sin_sq_add_cos_sq x, sq, sq, ← sub_eq_iff_eq_add, sub_self] <;>
    exact ⟨fun h => by rw [h, MulZeroClass.mul_zero], eq_zero_of_mul_self_eq_zero ∘ Eq.symm⟩
#align real.sin_eq_zero_iff_cos_eq Real.sin_eq_zero_iff_cos_eq

theorem cos_eq_one_iff (x : ℝ) : cos x = 1 ↔ ∃ n : ℤ, (n : ℝ) * (2 * π) = x :=
  ⟨fun h =>
    let ⟨n, hn⟩ := sin_eq_zero_iff.1 (sin_eq_zero_iff_cos_eq.2 (Or.inl h))
    ⟨n / 2,
      (Int.emod_two_eq_zero_or_one n).elim
        (fun hn0 => by
          rwa [← mul_assoc, ← @Int.cast_two ℝ, ← Int.cast_mul,
            Int.ediv_mul_cancel ((Int.dvd_iff_emod_eq_zero _ _).2 hn0)])
        fun hn1 => by
        rw [← Int.emod_add_ediv n 2, hn1, Int.cast_add, Int.cast_one, add_mul, one_mul, add_comm,
              mul_comm (2 : ℤ), Int.cast_mul, mul_assoc, Int.cast_two] at hn <;>
            rw [← hn, cos_int_mul_two_pi_add_pi] at h <;>
          exact absurd h (by norm_num)⟩,
    fun ⟨n, hn⟩ => hn ▸ cos_int_mul_two_pi _⟩
#align real.cos_eq_one_iff Real.cos_eq_one_iff

theorem cos_eq_one_iff_of_lt_of_lt {x : ℝ} (hx₁ : -(2 * π) < x) (hx₂ : x < 2 * π) :
    cos x = 1 ↔ x = 0 :=
  ⟨fun h => by
    rcases(cos_eq_one_iff _).1 h with ⟨n, rfl⟩
    rw [mul_lt_iff_lt_one_left two_pi_pos] at hx₂
    rw [neg_lt, neg_mul_eq_neg_mul, mul_lt_iff_lt_one_left two_pi_pos] at hx₁
    norm_cast  at hx₁ hx₂
    obtain rfl : n = 0 := le_antisymm (by linarith) (by linarith)
    simp, fun h => by simp [h]⟩
#align real.cos_eq_one_iff_of_lt_of_lt Real.cos_eq_one_iff_of_lt_of_lt

theorem cos_lt_cos_of_nonneg_of_le_pi_div_two {x y : ℝ} (hx₁ : 0 ≤ x) (hy₂ : y ≤ π / 2)
    (hxy : x < y) : cos y < cos x :=
  by
  rw [← sub_lt_zero, cos_sub_cos]
  have : 0 < sin ((y + x) / 2) := by refine' sin_pos_of_pos_of_lt_pi _ _ <;> linarith
  have : 0 < sin ((y - x) / 2) := by refine' sin_pos_of_pos_of_lt_pi _ _ <;> linarith
  nlinarith
#align real.cos_lt_cos_of_nonneg_of_le_pi_div_two Real.cos_lt_cos_of_nonneg_of_le_pi_div_two

theorem cos_lt_cos_of_nonneg_of_le_pi {x y : ℝ} (hx₁ : 0 ≤ x) (hy₂ : y ≤ π) (hxy : x < y) :
    cos y < cos x :=
  match (le_total x (π / 2) : x ≤ π / 2 ∨ π / 2 ≤ x), le_total y (π / 2) with
  | Or.inl hx, Or.inl hy => cos_lt_cos_of_nonneg_of_le_pi_div_two hx₁ hy hxy
  | Or.inl hx, Or.inr hy =>
    (lt_or_eq_of_le hx).elim
      (fun hx =>
        calc
          cos y ≤ 0 := cos_nonpos_of_pi_div_two_le_of_le hy (by linarith [pi_pos])
          _ < cos x := cos_pos_of_mem_Ioo ⟨by linarith, hx⟩
          )
      fun hx =>
      calc
        cos y < 0 := cos_neg_of_pi_div_two_lt_of_lt (by linarith) (by linarith [pi_pos])
        _ = cos x := by rw [hx, cos_pi_div_two]

  | Or.inr hx, Or.inl hy => by linarith
  | Or.inr hx, Or.inr hy =>
    neg_lt_neg_iff.1
      (by
        rw [← cos_pi_sub, ← cos_pi_sub] <;> apply cos_lt_cos_of_nonneg_of_le_pi_div_two <;>
          linarith)
#align real.cos_lt_cos_of_nonneg_of_le_pi Real.cos_lt_cos_of_nonneg_of_le_pi

theorem strictAntiOn_cos : StrictAntiOn cos (Icc 0 π) := fun x hx y hy hxy =>
  cos_lt_cos_of_nonneg_of_le_pi hx.1 hy.2 hxy
#align real.strict_anti_on_cos Real.strictAntiOn_cos

theorem cos_le_cos_of_nonneg_of_le_pi {x y : ℝ} (hx₁ : 0 ≤ x) (hy₂ : y ≤ π) (hxy : x ≤ y) :
    cos y ≤ cos x :=
  (strictAntiOn_cos.le_iff_le ⟨hx₁.trans hxy, hy₂⟩ ⟨hx₁, hxy.trans hy₂⟩).2 hxy
#align real.cos_le_cos_of_nonneg_of_le_pi Real.cos_le_cos_of_nonneg_of_le_pi

theorem sin_lt_sin_of_lt_of_le_pi_div_two {x y : ℝ} (hx₁ : -(π / 2) ≤ x) (hy₂ : y ≤ π / 2)
    (hxy : x < y) : sin x < sin y := by
  rw [← cos_sub_pi_div_two, ← cos_sub_pi_div_two, ← cos_neg (x - _), ← cos_neg (y - _)] <;>
      apply cos_lt_cos_of_nonneg_of_le_pi <;>
    linarith
#align real.sin_lt_sin_of_lt_of_le_pi_div_two Real.sin_lt_sin_of_lt_of_le_pi_div_two

theorem strictMonoOn_sin : StrictMonoOn sin (Icc (-(π / 2)) (π / 2)) := fun x hx y hy hxy =>
  sin_lt_sin_of_lt_of_le_pi_div_two hx.1 hy.2 hxy
#align real.strict_mono_on_sin Real.strictMonoOn_sin

theorem sin_le_sin_of_le_of_le_pi_div_two {x y : ℝ} (hx₁ : -(π / 2) ≤ x) (hy₂ : y ≤ π / 2)
    (hxy : x ≤ y) : sin x ≤ sin y :=
  (strictMonoOn_sin.le_iff_le ⟨hx₁, hxy.trans hy₂⟩ ⟨hx₁.trans hxy, hy₂⟩).2 hxy
#align real.sin_le_sin_of_le_of_le_pi_div_two Real.sin_le_sin_of_le_of_le_pi_div_two

theorem injOn_sin : InjOn sin (Icc (-(π / 2)) (π / 2)) :=
  strictMonoOn_sin.InjOn
#align real.inj_on_sin Real.injOn_sin

theorem injOn_cos : InjOn cos (Icc 0 π) :=
  strictAntiOn_cos.InjOn
#align real.inj_on_cos Real.injOn_cos

theorem surjOn_sin : SurjOn sin (Icc (-(π / 2)) (π / 2)) (Icc (-1) 1) := by
  simpa only [sin_neg, sin_pi_div_two] using
    intermediate_value_Icc (neg_le_self pi_div_two_pos.le) continuous_sin.continuous_on
#align real.surj_on_sin Real.surjOn_sin

theorem surjOn_cos : SurjOn cos (Icc 0 π) (Icc (-1) 1) := by
  simpa only [cos_zero, cos_pi] using intermediate_value_Icc' pi_pos.le continuous_cos.continuous_on
#align real.surj_on_cos Real.surjOn_cos

theorem sin_mem_Icc (x : ℝ) : sin x ∈ Icc (-1 : ℝ) 1 :=
  ⟨neg_one_le_sin x, sin_le_one x⟩
#align real.sin_mem_Icc Real.sin_mem_Icc

theorem cos_mem_Icc (x : ℝ) : cos x ∈ Icc (-1 : ℝ) 1 :=
  ⟨neg_one_le_cos x, cos_le_one x⟩
#align real.cos_mem_Icc Real.cos_mem_Icc

theorem mapsTo_sin (s : Set ℝ) : MapsTo sin s (Icc (-1 : ℝ) 1) := fun x _ => sin_mem_Icc x
#align real.maps_to_sin Real.mapsTo_sin

theorem mapsTo_cos (s : Set ℝ) : MapsTo cos s (Icc (-1 : ℝ) 1) := fun x _ => cos_mem_Icc x
#align real.maps_to_cos Real.mapsTo_cos

theorem bijOn_sin : BijOn sin (Icc (-(π / 2)) (π / 2)) (Icc (-1) 1) :=
  ⟨mapsTo_sin _, injOn_sin, surjOn_sin⟩
#align real.bij_on_sin Real.bijOn_sin

theorem bijOn_cos : BijOn cos (Icc 0 π) (Icc (-1) 1) :=
  ⟨mapsTo_cos _, injOn_cos, surjOn_cos⟩
#align real.bij_on_cos Real.bijOn_cos

@[simp]
theorem range_cos : range cos = (Icc (-1) 1 : Set ℝ) :=
  Subset.antisymm (range_subset_iff.2 cos_mem_Icc) surjOn_cos.subset_range
#align real.range_cos Real.range_cos

@[simp]
theorem range_sin : range sin = (Icc (-1) 1 : Set ℝ) :=
  Subset.antisymm (range_subset_iff.2 sin_mem_Icc) surjOn_sin.subset_range
#align real.range_sin Real.range_sin

theorem range_cos_infinite : (range Real.cos).Infinite :=
  by
  rw [Real.range_cos]
  exact Icc_infinite (by norm_num)
#align real.range_cos_infinite Real.range_cos_infinite

theorem range_sin_infinite : (range Real.sin).Infinite :=
  by
  rw [Real.range_sin]
  exact Icc_infinite (by norm_num)
#align real.range_sin_infinite Real.range_sin_infinite

section CosDivSq

variable (x : ℝ)

/-- the series `sqrt_two_add_series x n` is `sqrt(2 + sqrt(2 + ... ))` with `n` square roots,
  starting with `x`. We define it here because `cos (pi / 2 ^ (n+1)) = sqrt_two_add_series 0 n / 2`
-/
@[simp, pp_nodot]
noncomputable def sqrtTwoAddSeries (x : ℝ) : ℕ → ℝ
  | 0 => x
  | n + 1 => sqrt (2 + sqrt_two_add_series n)
#align real.sqrt_two_add_series Real.sqrtTwoAddSeries

theorem sqrtTwoAddSeries_zero : sqrtTwoAddSeries x 0 = x := by simp
#align real.sqrt_two_add_series_zero Real.sqrtTwoAddSeries_zero

theorem sqrtTwoAddSeries_one : sqrtTwoAddSeries 0 1 = sqrt 2 := by simp
#align real.sqrt_two_add_series_one Real.sqrtTwoAddSeries_one

theorem sqrtTwoAddSeries_two : sqrtTwoAddSeries 0 2 = sqrt (2 + sqrt 2) := by simp
#align real.sqrt_two_add_series_two Real.sqrtTwoAddSeries_two

theorem sqrtTwoAddSeries_zero_nonneg : ∀ n : ℕ, 0 ≤ sqrtTwoAddSeries 0 n
  | 0 => le_refl 0
  | n + 1 => sqrt_nonneg _
#align real.sqrt_two_add_series_zero_nonneg Real.sqrtTwoAddSeries_zero_nonneg

theorem sqrtTwoAddSeries_nonneg {x : ℝ} (h : 0 ≤ x) : ∀ n : ℕ, 0 ≤ sqrtTwoAddSeries x n
  | 0 => h
  | n + 1 => sqrt_nonneg _
#align real.sqrt_two_add_series_nonneg Real.sqrtTwoAddSeries_nonneg

theorem sqrtTwoAddSeries_lt_two : ∀ n : ℕ, sqrtTwoAddSeries 0 n < 2
  | 0 => by norm_num
  | n + 1 => by
    refine' lt_of_lt_of_le _ (sqrt_sq zero_lt_two.le).le
    rw [sqrt_two_add_series, sqrt_lt_sqrt_iff, ← lt_sub_iff_add_lt']
    · refine' (sqrt_two_add_series_lt_two n).trans_le _
      norm_num
    · exact add_nonneg zero_le_two (sqrt_two_add_series_zero_nonneg n)
#align real.sqrt_two_add_series_lt_two Real.sqrtTwoAddSeries_lt_two

theorem sqrtTwoAddSeries_succ (x : ℝ) :
    ∀ n : ℕ, sqrtTwoAddSeries x (n + 1) = sqrtTwoAddSeries (sqrt (2 + x)) n
  | 0 => rfl
  | n + 1 => by rw [sqrt_two_add_series, sqrt_two_add_series_succ, sqrt_two_add_series]
#align real.sqrt_two_add_series_succ Real.sqrtTwoAddSeries_succ

theorem sqrtTwoAddSeries_monotone_left {x y : ℝ} (h : x ≤ y) :
    ∀ n : ℕ, sqrtTwoAddSeries x n ≤ sqrtTwoAddSeries y n
  | 0 => h
  | n + 1 => by
    rw [sqrt_two_add_series, sqrt_two_add_series]
    exact sqrt_le_sqrt (add_le_add_left (sqrt_two_add_series_monotone_left _) _)
#align real.sqrt_two_add_series_monotone_left Real.sqrtTwoAddSeries_monotone_left

@[simp]
theorem cos_pi_over_two_pow : ∀ n : ℕ, cos (π / 2 ^ (n + 1)) = sqrtTwoAddSeries 0 n / 2
  | 0 => by simp
  | n + 1 => by
    have : (2 : ℝ) ≠ 0 := two_ne_zero
    symm; rw [div_eq_iff_mul_eq this]; symm
    rw [sqrt_two_add_series, sqrt_eq_iff_sq_eq, mul_pow, cos_sq, ← mul_div_assoc, Nat.add_succ,
      pow_succ, mul_div_mul_left _ _ this, cos_pi_over_two_pow, add_mul]
    congr ; · norm_num
    rw [mul_comm, sq, mul_assoc, ← mul_div_assoc, mul_div_cancel_left, ← mul_div_assoc,
        mul_div_cancel_left] <;>
      try exact this
    apply add_nonneg; norm_num; apply sqrt_two_add_series_zero_nonneg; norm_num
    apply le_of_lt; apply cos_pos_of_mem_Ioo ⟨_, _⟩
    · trans (0 : ℝ)
      rw [neg_lt_zero]
      apply pi_div_two_pos
      apply div_pos pi_pos
      apply pow_pos
      norm_num
    apply div_lt_div' (le_refl π) _ pi_pos _
    refine' lt_of_le_of_lt (le_of_eq (pow_one _).symm) _
    apply pow_lt_pow; norm_num; apply Nat.succ_lt_succ; apply Nat.succ_pos; all_goals norm_num
#align real.cos_pi_over_two_pow Real.cos_pi_over_two_pow

theorem sin_sq_pi_over_two_pow (n : ℕ) :
    sin (π / 2 ^ (n + 1)) ^ 2 = 1 - (sqrtTwoAddSeries 0 n / 2) ^ 2 := by
  rw [sin_sq, cos_pi_over_two_pow]
#align real.sin_sq_pi_over_two_pow Real.sin_sq_pi_over_two_pow

theorem sin_sq_pi_over_two_pow_succ (n : ℕ) :
    sin (π / 2 ^ (n + 2)) ^ 2 = 1 / 2 - sqrtTwoAddSeries 0 n / 4 :=
  by
  rw [sin_sq_pi_over_two_pow, sqrt_two_add_series, div_pow, sq_sqrt, add_div, ← sub_sub]
  congr ; norm_num; norm_num; apply add_nonneg; norm_num; apply sqrt_two_add_series_zero_nonneg
#align real.sin_sq_pi_over_two_pow_succ Real.sin_sq_pi_over_two_pow_succ

@[simp]
theorem sin_pi_over_two_pow_succ (n : ℕ) :
    sin (π / 2 ^ (n + 2)) = sqrt (2 - sqrtTwoAddSeries 0 n) / 2 :=
  by
  symm; rw [div_eq_iff_mul_eq]; symm
  rw [sqrt_eq_iff_sq_eq, mul_pow, sin_sq_pi_over_two_pow_succ, sub_mul]
  · congr
    norm_num
    rw [mul_comm]
    convert mul_div_cancel' _ _
    norm_num
    norm_num
  · rw [sub_nonneg]
    apply le_of_lt
    apply sqrt_two_add_series_lt_two
  apply le_of_lt; apply mul_pos; apply sin_pos_of_pos_of_lt_pi
  · apply div_pos pi_pos
    apply pow_pos
    norm_num
  refine' lt_of_lt_of_le _ (le_of_eq (div_one _)); rw [div_lt_div_left]
  refine' lt_of_le_of_lt (le_of_eq (pow_zero 2).symm) _
  apply pow_lt_pow; norm_num; apply Nat.succ_pos; apply pi_pos
  apply pow_pos; all_goals norm_num
#align real.sin_pi_over_two_pow_succ Real.sin_pi_over_two_pow_succ

@[simp]
theorem cos_pi_div_four : cos (π / 4) = sqrt 2 / 2 :=
  by
  trans cos (π / 2 ^ 2)
  congr
  norm_num
  simp
#align real.cos_pi_div_four Real.cos_pi_div_four

@[simp]
theorem sin_pi_div_four : sin (π / 4) = sqrt 2 / 2 :=
  by
  trans sin (π / 2 ^ 2)
  congr
  norm_num
  simp
#align real.sin_pi_div_four Real.sin_pi_div_four

@[simp]
theorem cos_pi_div_eight : cos (π / 8) = sqrt (2 + sqrt 2) / 2 :=
  by
  trans cos (π / 2 ^ 3)
  congr
  norm_num
  simp
#align real.cos_pi_div_eight Real.cos_pi_div_eight

@[simp]
theorem sin_pi_div_eight : sin (π / 8) = sqrt (2 - sqrt 2) / 2 :=
  by
  trans sin (π / 2 ^ 3)
  congr
  norm_num
  simp
#align real.sin_pi_div_eight Real.sin_pi_div_eight

@[simp]
theorem cos_pi_div_sixteen : cos (π / 16) = sqrt (2 + sqrt (2 + sqrt 2)) / 2 :=
  by
  trans cos (π / 2 ^ 4)
  congr
  norm_num
  simp
#align real.cos_pi_div_sixteen Real.cos_pi_div_sixteen

@[simp]
theorem sin_pi_div_sixteen : sin (π / 16) = sqrt (2 - sqrt (2 + sqrt 2)) / 2 :=
  by
  trans sin (π / 2 ^ 4)
  congr
  norm_num
  simp
#align real.sin_pi_div_sixteen Real.sin_pi_div_sixteen

@[simp]
theorem cos_pi_div_thirty_two : cos (π / 32) = sqrt (2 + sqrt (2 + sqrt (2 + sqrt 2))) / 2 :=
  by
  trans cos (π / 2 ^ 5)
  congr
  norm_num
  simp
#align real.cos_pi_div_thirty_two Real.cos_pi_div_thirty_two

@[simp]
theorem sin_pi_div_thirty_two : sin (π / 32) = sqrt (2 - sqrt (2 + sqrt (2 + sqrt 2))) / 2 :=
  by
  trans sin (π / 2 ^ 5)
  congr
  norm_num
  simp
#align real.sin_pi_div_thirty_two Real.sin_pi_div_thirty_two

-- This section is also a convenient location for other explicit values of `sin` and `cos`.
/-- The cosine of `π / 3` is `1 / 2`. -/
@[simp]
theorem cos_pi_div_three : cos (π / 3) = 1 / 2 :=
  by
  have h₁ : (2 * cos (π / 3) - 1) ^ 2 * (2 * cos (π / 3) + 2) = 0 :=
    by
    have : cos (3 * (π / 3)) = cos π := by
      congr 1
      ring
    linarith [cos_pi, cos_three_mul (π / 3)]
  cases' mul_eq_zero.mp h₁ with h h
  · linarith [pow_eq_zero h]
  · have : cos π < cos (π / 3) := by
      refine' cos_lt_cos_of_nonneg_of_le_pi _ rfl.ge _ <;> linarith [pi_pos]
    linarith [cos_pi]
#align real.cos_pi_div_three Real.cos_pi_div_three

/-- The square of the cosine of `π / 6` is `3 / 4` (this is sometimes more convenient than the
result for cosine itself). -/
theorem sq_cos_pi_div_six : cos (π / 6) ^ 2 = 3 / 4 :=
  by
  have h1 : cos (π / 6) ^ 2 = 1 / 2 + 1 / 2 / 2 :=
    by
    convert cos_sq (π / 6)
    have h2 : 2 * (π / 6) = π / 3 := by cancel_denoms
    rw [h2, cos_pi_div_three]
  rw [← sub_eq_zero] at h1⊢
  convert h1 using 1
  ring
#align real.sq_cos_pi_div_six Real.sq_cos_pi_div_six

/-- The cosine of `π / 6` is `√3 / 2`. -/
@[simp]
theorem cos_pi_div_six : cos (π / 6) = sqrt 3 / 2 :=
  by
  suffices sqrt 3 = cos (π / 6) * 2
    by
    field_simp [(by norm_num : 0 ≠ 2)]
    exact this.symm
  rw [sqrt_eq_iff_sq_eq]
  · have h1 := (mul_right_inj' (by norm_num : (4 : ℝ) ≠ 0)).mpr sq_cos_pi_div_six
    rw [← sub_eq_zero] at h1⊢
    convert h1 using 1
    ring
  · norm_num
  · have : 0 < cos (π / 6) := by apply cos_pos_of_mem_Ioo <;> constructor <;> linarith [pi_pos]
    linarith
#align real.cos_pi_div_six Real.cos_pi_div_six

/-- The sine of `π / 6` is `1 / 2`. -/
@[simp]
theorem sin_pi_div_six : sin (π / 6) = 1 / 2 :=
  by
  rw [← cos_pi_div_two_sub, ← cos_pi_div_three]
  congr
  ring
#align real.sin_pi_div_six Real.sin_pi_div_six

/-- The square of the sine of `π / 3` is `3 / 4` (this is sometimes more convenient than the
result for cosine itself). -/
theorem sq_sin_pi_div_three : sin (π / 3) ^ 2 = 3 / 4 :=
  by
  rw [← cos_pi_div_two_sub, ← sq_cos_pi_div_six]
  congr
  ring
#align real.sq_sin_pi_div_three Real.sq_sin_pi_div_three

/-- The sine of `π / 3` is `√3 / 2`. -/
@[simp]
theorem sin_pi_div_three : sin (π / 3) = sqrt 3 / 2 :=
  by
  rw [← cos_pi_div_two_sub, ← cos_pi_div_six]
  congr
  ring
#align real.sin_pi_div_three Real.sin_pi_div_three

end CosDivSq

/-- `real.sin` as an `order_iso` between `[-(π / 2), π / 2]` and `[-1, 1]`. -/
def sinOrderIso : Icc (-(π / 2)) (π / 2) ≃o Icc (-1 : ℝ) 1 :=
  (strictMonoOn_sin.OrderIso _ _).trans <| OrderIso.setCongr _ _ bijOn_sin.image_eq
#align real.sin_order_iso Real.sinOrderIso

@[simp]
theorem coe_sinOrderIso_apply (x : Icc (-(π / 2)) (π / 2)) : (sinOrderIso x : ℝ) = sin x :=
  rfl
#align real.coe_sin_order_iso_apply Real.coe_sinOrderIso_apply

theorem sinOrderIso_apply (x : Icc (-(π / 2)) (π / 2)) : sinOrderIso x = ⟨sin x, sin_mem_Icc x⟩ :=
  rfl
#align real.sin_order_iso_apply Real.sinOrderIso_apply

@[simp]
theorem tan_pi_div_four : tan (π / 4) = 1 :=
  by
  rw [tan_eq_sin_div_cos, cos_pi_div_four, sin_pi_div_four]
  have h : sqrt 2 / 2 > 0 := by cancel_denoms
  exact div_self (ne_of_gt h)
#align real.tan_pi_div_four Real.tan_pi_div_four

@[simp]
theorem tan_pi_div_two : tan (π / 2) = 0 := by simp [tan_eq_sin_div_cos]
#align real.tan_pi_div_two Real.tan_pi_div_two

theorem tan_pos_of_pos_of_lt_pi_div_two {x : ℝ} (h0x : 0 < x) (hxp : x < π / 2) : 0 < tan x := by
  rw [tan_eq_sin_div_cos] <;>
    exact
      div_pos (sin_pos_of_pos_of_lt_pi h0x (by linarith)) (cos_pos_of_mem_Ioo ⟨by linarith, hxp⟩)
#align real.tan_pos_of_pos_of_lt_pi_div_two Real.tan_pos_of_pos_of_lt_pi_div_two

theorem tan_nonneg_of_nonneg_of_le_pi_div_two {x : ℝ} (h0x : 0 ≤ x) (hxp : x ≤ π / 2) : 0 ≤ tan x :=
  match lt_or_eq_of_le h0x, lt_or_eq_of_le hxp with
  | Or.inl hx0, Or.inl hxp => le_of_lt (tan_pos_of_pos_of_lt_pi_div_two hx0 hxp)
  | Or.inl hx0, Or.inr hxp => by simp [hxp, tan_eq_sin_div_cos]
  | Or.inr hx0, _ => by simp [hx0.symm]
#align real.tan_nonneg_of_nonneg_of_le_pi_div_two Real.tan_nonneg_of_nonneg_of_le_pi_div_two

theorem tan_neg_of_neg_of_pi_div_two_lt {x : ℝ} (hx0 : x < 0) (hpx : -(π / 2) < x) : tan x < 0 :=
  neg_pos.1 (tan_neg x ▸ tan_pos_of_pos_of_lt_pi_div_two (by linarith) (by linarith [pi_pos]))
#align real.tan_neg_of_neg_of_pi_div_two_lt Real.tan_neg_of_neg_of_pi_div_two_lt

theorem tan_nonpos_of_nonpos_of_neg_pi_div_two_le {x : ℝ} (hx0 : x ≤ 0) (hpx : -(π / 2) ≤ x) :
    tan x ≤ 0 :=
  neg_nonneg.1 (tan_neg x ▸ tan_nonneg_of_nonneg_of_le_pi_div_two (by linarith) (by linarith))
#align real.tan_nonpos_of_nonpos_of_neg_pi_div_two_le Real.tan_nonpos_of_nonpos_of_neg_pi_div_two_le

theorem tan_lt_tan_of_nonneg_of_lt_pi_div_two {x y : ℝ} (hx₁ : 0 ≤ x) (hy₂ : y < π / 2)
    (hxy : x < y) : tan x < tan y :=
  by
  rw [tan_eq_sin_div_cos, tan_eq_sin_div_cos]
  exact
    div_lt_div (sin_lt_sin_of_lt_of_le_pi_div_two (by linarith) (le_of_lt hy₂) hxy)
      (cos_le_cos_of_nonneg_of_le_pi hx₁ (by linarith) (le_of_lt hxy))
      (sin_nonneg_of_nonneg_of_le_pi (by linarith) (by linarith))
      (cos_pos_of_mem_Ioo ⟨by linarith, hy₂⟩)
#align real.tan_lt_tan_of_nonneg_of_lt_pi_div_two Real.tan_lt_tan_of_nonneg_of_lt_pi_div_two

theorem tan_lt_tan_of_lt_of_lt_pi_div_two {x y : ℝ} (hx₁ : -(π / 2) < x) (hy₂ : y < π / 2)
    (hxy : x < y) : tan x < tan y :=
  match le_total x 0, le_total y 0 with
  | Or.inl hx0, Or.inl hy0 =>
    neg_lt_neg_iff.1 <| by
      rw [← tan_neg, ← tan_neg] <;>
        exact
          tan_lt_tan_of_nonneg_of_lt_pi_div_two (neg_nonneg.2 hy0) (neg_lt.2 hx₁) (neg_lt_neg hxy)
  | Or.inl hx0, Or.inr hy0 =>
    (lt_or_eq_of_le hy0).elim
      (fun hy0 =>
        calc
          tan x ≤ 0 := tan_nonpos_of_nonpos_of_neg_pi_div_two_le hx0 (le_of_lt hx₁)
          _ < tan y := tan_pos_of_pos_of_lt_pi_div_two hy0 hy₂
          )
      fun hy0 => by
      rw [← hy0, tan_zero] <;> exact tan_neg_of_neg_of_pi_div_two_lt (hy0.symm ▸ hxy) hx₁
  | Or.inr hx0, Or.inl hy0 => by linarith
  | Or.inr hx0, Or.inr hy0 => tan_lt_tan_of_nonneg_of_lt_pi_div_two hx0 hy₂ hxy
#align real.tan_lt_tan_of_lt_of_lt_pi_div_two Real.tan_lt_tan_of_lt_of_lt_pi_div_two

theorem strictMonoOn_tan : StrictMonoOn tan (Ioo (-(π / 2)) (π / 2)) := fun x hx y hy =>
  tan_lt_tan_of_lt_of_lt_pi_div_two hx.1 hy.2
#align real.strict_mono_on_tan Real.strictMonoOn_tan

theorem injOn_tan : InjOn tan (Ioo (-(π / 2)) (π / 2)) :=
  strictMonoOn_tan.InjOn
#align real.inj_on_tan Real.injOn_tan

theorem tan_inj_of_lt_of_lt_pi_div_two {x y : ℝ} (hx₁ : -(π / 2) < x) (hx₂ : x < π / 2)
    (hy₁ : -(π / 2) < y) (hy₂ : y < π / 2) (hxy : tan x = tan y) : x = y :=
  injOn_tan ⟨hx₁, hx₂⟩ ⟨hy₁, hy₂⟩ hxy
#align real.tan_inj_of_lt_of_lt_pi_div_two Real.tan_inj_of_lt_of_lt_pi_div_two

theorem tan_periodic : Function.Periodic tan π := by
  simpa only [Function.Periodic, tan_eq_sin_div_cos] using sin_antiperiodic.div cos_antiperiodic
#align real.tan_periodic Real.tan_periodic

theorem tan_add_pi (x : ℝ) : tan (x + π) = tan x :=
  tan_periodic x
#align real.tan_add_pi Real.tan_add_pi

theorem tan_sub_pi (x : ℝ) : tan (x - π) = tan x :=
  tan_periodic.sub_eq x
#align real.tan_sub_pi Real.tan_sub_pi

theorem tan_pi_sub (x : ℝ) : tan (π - x) = -tan x :=
  tan_neg x ▸ tan_periodic.sub_eq'
#align real.tan_pi_sub Real.tan_pi_sub

theorem tan_pi_div_two_sub (x : ℝ) : tan (π / 2 - x) = (tan x)⁻¹ := by
  rw [tan_eq_sin_div_cos, tan_eq_sin_div_cos, inv_div, sin_pi_div_two_sub, cos_pi_div_two_sub]
#align real.tan_pi_div_two_sub Real.tan_pi_div_two_sub

theorem tan_nat_mul_pi (n : ℕ) : tan (n * π) = 0 :=
  tan_zero ▸ tan_periodic.nat_mul_eq n
#align real.tan_nat_mul_pi Real.tan_nat_mul_pi

theorem tan_int_mul_pi (n : ℤ) : tan (n * π) = 0 :=
  tan_zero ▸ tan_periodic.int_mul_eq n
#align real.tan_int_mul_pi Real.tan_int_mul_pi

theorem tan_add_nat_mul_pi (x : ℝ) (n : ℕ) : tan (x + n * π) = tan x :=
  tan_periodic.nat_mul n x
#align real.tan_add_nat_mul_pi Real.tan_add_nat_mul_pi

theorem tan_add_int_mul_pi (x : ℝ) (n : ℤ) : tan (x + n * π) = tan x :=
  tan_periodic.int_mul n x
#align real.tan_add_int_mul_pi Real.tan_add_int_mul_pi

theorem tan_sub_nat_mul_pi (x : ℝ) (n : ℕ) : tan (x - n * π) = tan x :=
  tan_periodic.sub_nat_mul_eq n
#align real.tan_sub_nat_mul_pi Real.tan_sub_nat_mul_pi

theorem tan_sub_int_mul_pi (x : ℝ) (n : ℤ) : tan (x - n * π) = tan x :=
  tan_periodic.sub_int_mul_eq n
#align real.tan_sub_int_mul_pi Real.tan_sub_int_mul_pi

theorem tan_nat_mul_pi_sub (x : ℝ) (n : ℕ) : tan (n * π - x) = -tan x :=
  tan_neg x ▸ tan_periodic.nat_mul_sub_eq n
#align real.tan_nat_mul_pi_sub Real.tan_nat_mul_pi_sub

theorem tan_int_mul_pi_sub (x : ℝ) (n : ℤ) : tan (n * π - x) = -tan x :=
  tan_neg x ▸ tan_periodic.int_mul_sub_eq n
#align real.tan_int_mul_pi_sub Real.tan_int_mul_pi_sub

theorem tendsto_sin_pi_div_two : Tendsto sin (𝓝[<] (π / 2)) (𝓝 1) :=
  by
  convert continuous_sin.continuous_within_at
  simp
#align real.tendsto_sin_pi_div_two Real.tendsto_sin_pi_div_two

theorem tendsto_cos_pi_div_two : Tendsto cos (𝓝[<] (π / 2)) (𝓝[>] 0) :=
  by
  apply tendsto_nhdsWithin_of_tendsto_nhds_of_eventually_within
  · convert continuous_cos.continuous_within_at
    simp
  ·
    filter_upwards [Ioo_mem_nhdsWithin_Iio
        (right_mem_Ioc.mpr (neg_lt_self pi_div_two_pos))]with x hx using cos_pos_of_mem_Ioo hx
#align real.tendsto_cos_pi_div_two Real.tendsto_cos_pi_div_two

theorem tendsto_tan_pi_div_two : Tendsto tan (𝓝[<] (π / 2)) atTop :=
  by
  convert tendsto_cos_pi_div_two.inv_tendsto_zero.at_top_mul zero_lt_one tendsto_sin_pi_div_two
  simp only [Pi.inv_apply, ← div_eq_inv_mul, ← tan_eq_sin_div_cos]
#align real.tendsto_tan_pi_div_two Real.tendsto_tan_pi_div_two

theorem tendsto_sin_neg_pi_div_two : Tendsto sin (𝓝[>] (-(π / 2))) (𝓝 (-1)) :=
  by
  convert continuous_sin.continuous_within_at
  simp
#align real.tendsto_sin_neg_pi_div_two Real.tendsto_sin_neg_pi_div_two

theorem tendsto_cos_neg_pi_div_two : Tendsto cos (𝓝[>] (-(π / 2))) (𝓝[>] 0) :=
  by
  apply tendsto_nhdsWithin_of_tendsto_nhds_of_eventually_within
  · convert continuous_cos.continuous_within_at
    simp
  ·
    filter_upwards [Ioo_mem_nhdsWithin_Ioi
        (left_mem_Ico.mpr (neg_lt_self pi_div_two_pos))]with x hx using cos_pos_of_mem_Ioo hx
#align real.tendsto_cos_neg_pi_div_two Real.tendsto_cos_neg_pi_div_two

theorem tendsto_tan_neg_pi_div_two : Tendsto tan (𝓝[>] (-(π / 2))) atBot :=
  by
  convert tendsto_cos_neg_pi_div_two.inv_tendsto_zero.at_top_mul_neg (by norm_num)
      tendsto_sin_neg_pi_div_two
  simp only [Pi.inv_apply, ← div_eq_inv_mul, ← tan_eq_sin_div_cos]
#align real.tendsto_tan_neg_pi_div_two Real.tendsto_tan_neg_pi_div_two

end Real

namespace Complex

open Real

theorem sin_eq_zero_iff_cos_eq {z : ℂ} : sin z = 0 ↔ cos z = 1 ∨ cos z = -1 := by
  rw [← mul_self_eq_one_iff, ← sin_sq_add_cos_sq, sq, sq, ← sub_eq_iff_eq_add, sub_self] <;>
    exact ⟨fun h => by rw [h, MulZeroClass.mul_zero], eq_zero_of_mul_self_eq_zero ∘ Eq.symm⟩
#align complex.sin_eq_zero_iff_cos_eq Complex.sin_eq_zero_iff_cos_eq

@[simp]
theorem cos_pi_div_two : cos (π / 2) = 0 :=
  calc
    cos (π / 2) = Real.cos (π / 2) := by rw [of_real_cos] <;> simp
    _ = 0 := by simp

#align complex.cos_pi_div_two Complex.cos_pi_div_two

@[simp]
theorem sin_pi_div_two : sin (π / 2) = 1 :=
  calc
    sin (π / 2) = Real.sin (π / 2) := by rw [of_real_sin] <;> simp
    _ = 1 := by simp

#align complex.sin_pi_div_two Complex.sin_pi_div_two

@[simp]
theorem sin_pi : sin π = 0 := by rw [← of_real_sin, Real.sin_pi] <;> simp
#align complex.sin_pi Complex.sin_pi

@[simp]
theorem cos_pi : cos π = -1 := by rw [← of_real_cos, Real.cos_pi] <;> simp
#align complex.cos_pi Complex.cos_pi

@[simp]
theorem sin_two_pi : sin (2 * π) = 0 := by simp [two_mul, sin_add]
#align complex.sin_two_pi Complex.sin_two_pi

@[simp]
theorem cos_two_pi : cos (2 * π) = 1 := by simp [two_mul, cos_add]
#align complex.cos_two_pi Complex.cos_two_pi

theorem sin_antiperiodic : Function.Antiperiodic sin π := by simp [sin_add]
#align complex.sin_antiperiodic Complex.sin_antiperiodic

theorem sin_periodic : Function.Periodic sin (2 * π) :=
  sin_antiperiodic.Periodic
#align complex.sin_periodic Complex.sin_periodic

theorem sin_add_pi (x : ℂ) : sin (x + π) = -sin x :=
  sin_antiperiodic x
#align complex.sin_add_pi Complex.sin_add_pi

theorem sin_add_two_pi (x : ℂ) : sin (x + 2 * π) = sin x :=
  sin_periodic x
#align complex.sin_add_two_pi Complex.sin_add_two_pi

theorem sin_sub_pi (x : ℂ) : sin (x - π) = -sin x :=
  sin_antiperiodic.sub_eq x
#align complex.sin_sub_pi Complex.sin_sub_pi

theorem sin_sub_two_pi (x : ℂ) : sin (x - 2 * π) = sin x :=
  sin_periodic.sub_eq x
#align complex.sin_sub_two_pi Complex.sin_sub_two_pi

theorem sin_pi_sub (x : ℂ) : sin (π - x) = sin x :=
  neg_neg (sin x) ▸ sin_neg x ▸ sin_antiperiodic.sub_eq'
#align complex.sin_pi_sub Complex.sin_pi_sub

theorem sin_two_pi_sub (x : ℂ) : sin (2 * π - x) = -sin x :=
  sin_neg x ▸ sin_periodic.sub_eq'
#align complex.sin_two_pi_sub Complex.sin_two_pi_sub

theorem sin_nat_mul_pi (n : ℕ) : sin (n * π) = 0 :=
  sin_antiperiodic.nat_mul_eq_of_eq_zero sin_zero n
#align complex.sin_nat_mul_pi Complex.sin_nat_mul_pi

theorem sin_int_mul_pi (n : ℤ) : sin (n * π) = 0 :=
  sin_antiperiodic.int_mul_eq_of_eq_zero sin_zero n
#align complex.sin_int_mul_pi Complex.sin_int_mul_pi

theorem sin_add_nat_mul_two_pi (x : ℂ) (n : ℕ) : sin (x + n * (2 * π)) = sin x :=
  sin_periodic.nat_mul n x
#align complex.sin_add_nat_mul_two_pi Complex.sin_add_nat_mul_two_pi

theorem sin_add_int_mul_two_pi (x : ℂ) (n : ℤ) : sin (x + n * (2 * π)) = sin x :=
  sin_periodic.int_mul n x
#align complex.sin_add_int_mul_two_pi Complex.sin_add_int_mul_two_pi

theorem sin_sub_nat_mul_two_pi (x : ℂ) (n : ℕ) : sin (x - n * (2 * π)) = sin x :=
  sin_periodic.sub_nat_mul_eq n
#align complex.sin_sub_nat_mul_two_pi Complex.sin_sub_nat_mul_two_pi

theorem sin_sub_int_mul_two_pi (x : ℂ) (n : ℤ) : sin (x - n * (2 * π)) = sin x :=
  sin_periodic.sub_int_mul_eq n
#align complex.sin_sub_int_mul_two_pi Complex.sin_sub_int_mul_two_pi

theorem sin_nat_mul_two_pi_sub (x : ℂ) (n : ℕ) : sin (n * (2 * π) - x) = -sin x :=
  sin_neg x ▸ sin_periodic.nat_mul_sub_eq n
#align complex.sin_nat_mul_two_pi_sub Complex.sin_nat_mul_two_pi_sub

theorem sin_int_mul_two_pi_sub (x : ℂ) (n : ℤ) : sin (n * (2 * π) - x) = -sin x :=
  sin_neg x ▸ sin_periodic.int_mul_sub_eq n
#align complex.sin_int_mul_two_pi_sub Complex.sin_int_mul_two_pi_sub

theorem cos_antiperiodic : Function.Antiperiodic cos π := by simp [cos_add]
#align complex.cos_antiperiodic Complex.cos_antiperiodic

theorem cos_periodic : Function.Periodic cos (2 * π) :=
  cos_antiperiodic.Periodic
#align complex.cos_periodic Complex.cos_periodic

theorem cos_add_pi (x : ℂ) : cos (x + π) = -cos x :=
  cos_antiperiodic x
#align complex.cos_add_pi Complex.cos_add_pi

theorem cos_add_two_pi (x : ℂ) : cos (x + 2 * π) = cos x :=
  cos_periodic x
#align complex.cos_add_two_pi Complex.cos_add_two_pi

theorem cos_sub_pi (x : ℂ) : cos (x - π) = -cos x :=
  cos_antiperiodic.sub_eq x
#align complex.cos_sub_pi Complex.cos_sub_pi

theorem cos_sub_two_pi (x : ℂ) : cos (x - 2 * π) = cos x :=
  cos_periodic.sub_eq x
#align complex.cos_sub_two_pi Complex.cos_sub_two_pi

theorem cos_pi_sub (x : ℂ) : cos (π - x) = -cos x :=
  cos_neg x ▸ cos_antiperiodic.sub_eq'
#align complex.cos_pi_sub Complex.cos_pi_sub

theorem cos_two_pi_sub (x : ℂ) : cos (2 * π - x) = cos x :=
  cos_neg x ▸ cos_periodic.sub_eq'
#align complex.cos_two_pi_sub Complex.cos_two_pi_sub

theorem cos_nat_mul_two_pi (n : ℕ) : cos (n * (2 * π)) = 1 :=
  (cos_periodic.nat_mul_eq n).trans cos_zero
#align complex.cos_nat_mul_two_pi Complex.cos_nat_mul_two_pi

theorem cos_int_mul_two_pi (n : ℤ) : cos (n * (2 * π)) = 1 :=
  (cos_periodic.int_mul_eq n).trans cos_zero
#align complex.cos_int_mul_two_pi Complex.cos_int_mul_two_pi

theorem cos_add_nat_mul_two_pi (x : ℂ) (n : ℕ) : cos (x + n * (2 * π)) = cos x :=
  cos_periodic.nat_mul n x
#align complex.cos_add_nat_mul_two_pi Complex.cos_add_nat_mul_two_pi

theorem cos_add_int_mul_two_pi (x : ℂ) (n : ℤ) : cos (x + n * (2 * π)) = cos x :=
  cos_periodic.int_mul n x
#align complex.cos_add_int_mul_two_pi Complex.cos_add_int_mul_two_pi

theorem cos_sub_nat_mul_two_pi (x : ℂ) (n : ℕ) : cos (x - n * (2 * π)) = cos x :=
  cos_periodic.sub_nat_mul_eq n
#align complex.cos_sub_nat_mul_two_pi Complex.cos_sub_nat_mul_two_pi

theorem cos_sub_int_mul_two_pi (x : ℂ) (n : ℤ) : cos (x - n * (2 * π)) = cos x :=
  cos_periodic.sub_int_mul_eq n
#align complex.cos_sub_int_mul_two_pi Complex.cos_sub_int_mul_two_pi

theorem cos_nat_mul_two_pi_sub (x : ℂ) (n : ℕ) : cos (n * (2 * π) - x) = cos x :=
  cos_neg x ▸ cos_periodic.nat_mul_sub_eq n
#align complex.cos_nat_mul_two_pi_sub Complex.cos_nat_mul_two_pi_sub

theorem cos_int_mul_two_pi_sub (x : ℂ) (n : ℤ) : cos (n * (2 * π) - x) = cos x :=
  cos_neg x ▸ cos_periodic.int_mul_sub_eq n
#align complex.cos_int_mul_two_pi_sub Complex.cos_int_mul_two_pi_sub

theorem cos_nat_mul_two_pi_add_pi (n : ℕ) : cos (n * (2 * π) + π) = -1 := by
  simpa only [cos_zero] using (cos_periodic.nat_mul n).add_antiperiod_eq cos_antiperiodic
#align complex.cos_nat_mul_two_pi_add_pi Complex.cos_nat_mul_two_pi_add_pi

theorem cos_int_mul_two_pi_add_pi (n : ℤ) : cos (n * (2 * π) + π) = -1 := by
  simpa only [cos_zero] using (cos_periodic.int_mul n).add_antiperiod_eq cos_antiperiodic
#align complex.cos_int_mul_two_pi_add_pi Complex.cos_int_mul_two_pi_add_pi

theorem cos_nat_mul_two_pi_sub_pi (n : ℕ) : cos (n * (2 * π) - π) = -1 := by
  simpa only [cos_zero] using (cos_periodic.nat_mul n).sub_antiperiod_eq cos_antiperiodic
#align complex.cos_nat_mul_two_pi_sub_pi Complex.cos_nat_mul_two_pi_sub_pi

theorem cos_int_mul_two_pi_sub_pi (n : ℤ) : cos (n * (2 * π) - π) = -1 := by
  simpa only [cos_zero] using (cos_periodic.int_mul n).sub_antiperiod_eq cos_antiperiodic
#align complex.cos_int_mul_two_pi_sub_pi Complex.cos_int_mul_two_pi_sub_pi

theorem sin_add_pi_div_two (x : ℂ) : sin (x + π / 2) = cos x := by simp [sin_add]
#align complex.sin_add_pi_div_two Complex.sin_add_pi_div_two

theorem sin_sub_pi_div_two (x : ℂ) : sin (x - π / 2) = -cos x := by simp [sub_eq_add_neg, sin_add]
#align complex.sin_sub_pi_div_two Complex.sin_sub_pi_div_two

theorem sin_pi_div_two_sub (x : ℂ) : sin (π / 2 - x) = cos x := by simp [sub_eq_add_neg, sin_add]
#align complex.sin_pi_div_two_sub Complex.sin_pi_div_two_sub

theorem cos_add_pi_div_two (x : ℂ) : cos (x + π / 2) = -sin x := by simp [cos_add]
#align complex.cos_add_pi_div_two Complex.cos_add_pi_div_two

theorem cos_sub_pi_div_two (x : ℂ) : cos (x - π / 2) = sin x := by simp [sub_eq_add_neg, cos_add]
#align complex.cos_sub_pi_div_two Complex.cos_sub_pi_div_two

theorem cos_pi_div_two_sub (x : ℂ) : cos (π / 2 - x) = sin x := by
  rw [← cos_neg, neg_sub, cos_sub_pi_div_two]
#align complex.cos_pi_div_two_sub Complex.cos_pi_div_two_sub

theorem tan_periodic : Function.Periodic tan π := by
  simpa only [tan_eq_sin_div_cos] using sin_antiperiodic.div cos_antiperiodic
#align complex.tan_periodic Complex.tan_periodic

theorem tan_add_pi (x : ℂ) : tan (x + π) = tan x :=
  tan_periodic x
#align complex.tan_add_pi Complex.tan_add_pi

theorem tan_sub_pi (x : ℂ) : tan (x - π) = tan x :=
  tan_periodic.sub_eq x
#align complex.tan_sub_pi Complex.tan_sub_pi

theorem tan_pi_sub (x : ℂ) : tan (π - x) = -tan x :=
  tan_neg x ▸ tan_periodic.sub_eq'
#align complex.tan_pi_sub Complex.tan_pi_sub

theorem tan_pi_div_two_sub (x : ℂ) : tan (π / 2 - x) = (tan x)⁻¹ := by
  rw [tan_eq_sin_div_cos, tan_eq_sin_div_cos, inv_div, sin_pi_div_two_sub, cos_pi_div_two_sub]
#align complex.tan_pi_div_two_sub Complex.tan_pi_div_two_sub

theorem tan_nat_mul_pi (n : ℕ) : tan (n * π) = 0 :=
  tan_zero ▸ tan_periodic.nat_mul_eq n
#align complex.tan_nat_mul_pi Complex.tan_nat_mul_pi

theorem tan_int_mul_pi (n : ℤ) : tan (n * π) = 0 :=
  tan_zero ▸ tan_periodic.int_mul_eq n
#align complex.tan_int_mul_pi Complex.tan_int_mul_pi

theorem tan_add_nat_mul_pi (x : ℂ) (n : ℕ) : tan (x + n * π) = tan x :=
  tan_periodic.nat_mul n x
#align complex.tan_add_nat_mul_pi Complex.tan_add_nat_mul_pi

theorem tan_add_int_mul_pi (x : ℂ) (n : ℤ) : tan (x + n * π) = tan x :=
  tan_periodic.int_mul n x
#align complex.tan_add_int_mul_pi Complex.tan_add_int_mul_pi

theorem tan_sub_nat_mul_pi (x : ℂ) (n : ℕ) : tan (x - n * π) = tan x :=
  tan_periodic.sub_nat_mul_eq n
#align complex.tan_sub_nat_mul_pi Complex.tan_sub_nat_mul_pi

theorem tan_sub_int_mul_pi (x : ℂ) (n : ℤ) : tan (x - n * π) = tan x :=
  tan_periodic.sub_int_mul_eq n
#align complex.tan_sub_int_mul_pi Complex.tan_sub_int_mul_pi

theorem tan_nat_mul_pi_sub (x : ℂ) (n : ℕ) : tan (n * π - x) = -tan x :=
  tan_neg x ▸ tan_periodic.nat_mul_sub_eq n
#align complex.tan_nat_mul_pi_sub Complex.tan_nat_mul_pi_sub

theorem tan_int_mul_pi_sub (x : ℂ) (n : ℤ) : tan (n * π - x) = -tan x :=
  tan_neg x ▸ tan_periodic.int_mul_sub_eq n
#align complex.tan_int_mul_pi_sub Complex.tan_int_mul_pi_sub

theorem exp_antiperiodic : Function.Antiperiodic exp (π * I) := by simp [exp_add, exp_mul_I]
#align complex.exp_antiperiodic Complex.exp_antiperiodic

theorem exp_periodic : Function.Periodic exp (2 * π * I) :=
  (mul_assoc (2 : ℂ) π I).symm ▸ exp_antiperiodic.Periodic
#align complex.exp_periodic Complex.exp_periodic

theorem exp_mul_i_antiperiodic : Function.Antiperiodic (fun x => exp (x * I)) π := by
  simpa only [mul_inv_cancel_right₀ I_ne_zero] using exp_antiperiodic.mul_const I_ne_zero
#align complex.exp_mul_I_antiperiodic Complex.exp_mul_i_antiperiodic

theorem exp_mul_i_periodic : Function.Periodic (fun x => exp (x * I)) (2 * π) :=
  exp_mul_i_antiperiodic.Periodic
#align complex.exp_mul_I_periodic Complex.exp_mul_i_periodic

@[simp]
theorem exp_pi_mul_i : exp (π * I) = -1 :=
  exp_zero ▸ exp_antiperiodic.Eq
#align complex.exp_pi_mul_I Complex.exp_pi_mul_i

@[simp]
theorem exp_two_pi_mul_i : exp (2 * π * I) = 1 :=
  exp_periodic.Eq.trans exp_zero
#align complex.exp_two_pi_mul_I Complex.exp_two_pi_mul_i

@[simp]
theorem exp_nat_mul_two_pi_mul_i (n : ℕ) : exp (n * (2 * π * I)) = 1 :=
  (exp_periodic.nat_mul_eq n).trans exp_zero
#align complex.exp_nat_mul_two_pi_mul_I Complex.exp_nat_mul_two_pi_mul_i

@[simp]
theorem exp_int_mul_two_pi_mul_i (n : ℤ) : exp (n * (2 * π * I)) = 1 :=
  (exp_periodic.int_mul_eq n).trans exp_zero
#align complex.exp_int_mul_two_pi_mul_I Complex.exp_int_mul_two_pi_mul_i

@[simp]
theorem exp_add_pi_mul_i (z : ℂ) : exp (z + π * I) = -exp z :=
  exp_antiperiodic z
#align complex.exp_add_pi_mul_I Complex.exp_add_pi_mul_i

@[simp]
theorem exp_sub_pi_mul_i (z : ℂ) : exp (z - π * I) = -exp z :=
  exp_antiperiodic.sub_eq z
#align complex.exp_sub_pi_mul_I Complex.exp_sub_pi_mul_i

/-- A supporting lemma for the **Phragmen-Lindelöf principle** in a horizontal strip. If `z : ℂ`
belongs to a horizontal strip `|complex.im z| ≤ b`, `b ≤ π / 2`, and `a ≤ 0`, then
$$\left|exp^{a\left(e^{z}+e^{-z}\right)}\right| \le e^{a\cos b \exp^{|re z|}}.$$
-/
theorem abs_exp_mul_exp_add_exp_neg_le_of_abs_im_le {a b : ℝ} (ha : a ≤ 0) {z : ℂ} (hz : |z.im| ≤ b)
    (hb : b ≤ π / 2) :
    abs (exp (a * (exp z + exp (-z)))) ≤ Real.exp (a * Real.cos b * Real.exp (|z.re|)) :=
  by
  simp only [abs_exp, Real.exp_le_exp, of_real_mul_re, add_re, exp_re, neg_im, Real.cos_neg, ←
    add_mul, mul_assoc, mul_comm (Real.cos b), neg_re, ← Real.cos_abs z.im]
  have : Real.exp (|z.re|) ≤ Real.exp z.re + Real.exp (-z.re) :=
    apply_abs_le_add_of_nonneg (fun x => (Real.exp_pos x).le) z.re
  refine' mul_le_mul_of_nonpos_left (mul_le_mul this _ _ ((Real.exp_pos _).le.trans this)) ha
  ·
    exact
      Real.cos_le_cos_of_nonneg_of_le_pi (_root_.abs_nonneg _)
        (hb.trans <| half_le_self <| real.pi_pos.le) hz
  · refine' Real.cos_nonneg_of_mem_Icc ⟨_, hb⟩
    exact (neg_nonpos.2 <| real.pi_div_two_pos.le).trans ((_root_.abs_nonneg _).trans hz)
#align complex.abs_exp_mul_exp_add_exp_neg_le_of_abs_im_le Complex.abs_exp_mul_exp_add_exp_neg_le_of_abs_im_le

end Complex


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

import category_theory.limits.preserves.shapes.terminal

/-!

# Limits and the category of (co)cones

This files contains results that stem from the limit API. For the definition and the category
instance of `cone`, please refer to `category_theory/limits/cones.lean`.

A cone is limiting iff it is terminal in the category of cones. As a corollary, an equivalence of
categories of cones preserves limiting properties. We also provide the dual.

-/

namespace category_theory.limits

open category_theory

universes v u

variables {J : Type v} [category.{v} J] {J' : Type v} [category.{v} J']
variables {C : Type u} [category.{v} C] {C' : Type u} [category.{v} C']

/-- A cone is a limit cone iff it is terminal. -/
def cone.is_limit_equiv_is_terminal {F : J ⥤ C} (c : cone F) : is_limit c ≃ is_terminal c :=
is_limit.iso_unique_cone_morphism.to_equiv.trans
{ to_fun := λ h, by exactI is_terminal.of_unique _,
  inv_fun := λ h s, ⟨⟨is_terminal.from h s⟩, λ a, is_terminal.hom_ext h a _⟩,
  left_inv := by tidy,
  right_inv := by tidy }

lemma is_limit.lift_cone_morphism_eq_is_terminal_from {F : J ⥤ C} {c : cone F} (hc : is_limit c)
  (s : cone F) : hc.lift_cone_morphism s =
    is_terminal.from (cone.is_limit_equiv_is_terminal _ hc) _ := rfl

lemma is_terminal.from_eq_lift_cone_morphism {F : J ⥤ C} {c : cone F} (hc : is_terminal c)
  (s : cone F) : is_terminal.from hc s =
    ((cone.is_limit_equiv_is_terminal _).symm hc).lift_cone_morphism s :=
by convert (is_limit.lift_cone_morphism_eq_is_terminal_from _ s).symm

/-- If `G : cone F ⥤ cone F'` preserves terminal objects, it preserves limit cones. -/
def is_limit.of_preserves_cone_terminal {F : J ⥤ C} {F' : J' ⥤ C'} (G : cone F ⥤ cone F')
  [preserves_limit (functor.empty _) G] {c : cone F} (hc : is_limit c) :
  is_limit (G.obj c) :=
(cone.is_limit_equiv_is_terminal _).symm $
  (cone.is_limit_equiv_is_terminal _ hc).is_terminal_obj _ _

/-- If `G : cone F ⥤ cone F'` reflects terminal objects, it reflects limit cones. -/
def is_limit.of_reflects_cone_terminal {F : J ⥤ C} {F' : J' ⥤ C'} (G : cone F ⥤ cone F')
  [reflects_limit (functor.empty _) G] {c : cone F} (hc : is_limit (G.obj c)) :
  is_limit c :=
(cone.is_limit_equiv_is_terminal _).symm $
  (cone.is_limit_equiv_is_terminal _ hc).is_terminal_of_obj _ _

/-- A cocone is a colimit cocone iff it is initial. -/
def cocone.is_colimit_equiv_is_initial {F : J ⥤ C} (c : cocone F) : is_colimit c ≃ is_initial c :=
is_colimit.iso_unique_cocone_morphism.to_equiv.trans
{ to_fun := λ h, by exactI is_initial.of_unique _,
  inv_fun := λ h s, ⟨⟨is_initial.to h s⟩, λ a, is_initial.hom_ext h a _⟩,
  left_inv := by tidy,
  right_inv := by tidy }

lemma is_colimit.desc_cocone_morphism_eq_is_initial_to {F : J ⥤ C} {c : cocone F}
  (hc : is_colimit c) (s : cocone F) :
  hc.desc_cocone_morphism s =
    is_initial.to (cocone.is_colimit_equiv_is_initial _ hc) _ := rfl

lemma is_initial.to_eq_desc_cocone_morphism {F : J ⥤ C} {c : cocone F}
  (hc : is_initial c) (s : cocone F) :
  is_initial.to hc s = ((cocone.is_colimit_equiv_is_initial _).symm hc).desc_cocone_morphism s :=
by convert (is_colimit.desc_cocone_morphism_eq_is_initial_to _ s).symm

/-- If `G : cocone F ⥤ cocone F'` preserves initial objects, it preserves colimit cocones. -/
def is_colimit.of_preserves_cocone_initial {F : J ⥤ C} {F' : J' ⥤ C'} (G : cocone F ⥤ cocone F')
  [preserves_colimit (functor.empty _) G] {c : cocone F} (hc : is_colimit c) :
  is_colimit (G.obj c) :=
(cocone.is_colimit_equiv_is_initial _).symm $
  (cocone.is_colimit_equiv_is_initial _ hc).is_initial_obj _ _

/-- If `G : cocone F ⥤ cocone F'` reflects initial objects, it reflects colimit cocones. -/
def is_colimit.of_reflects_cocone_initial {F : J ⥤ C} {F' : J' ⥤ C'} (G : cocone F ⥤ cocone F')
  [reflects_colimit (functor.empty _) G] {c : cocone F} (hc : is_colimit (G.obj c)) :
  is_colimit c :=
(cocone.is_colimit_equiv_is_initial _).symm $
  (cocone.is_colimit_equiv_is_initial _ hc).is_initial_of_obj _ _

end category_theory.limits


/-
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura, Jeremy Avigad
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.PostPort

universes u_1

namespace Mathlib

/-!
# booleans

This file proves various trivial lemmas about booleans and their
relation to decidable propositions.

## Notations

This file introduces the notation `!b` for `bnot b`, the boolean "not".

## Tags
bool, boolean, De Morgan
-/

namespace bool

prefix:90 "!" => Mathlib.bnot

@[simp] theorem coe_sort_tt : ↥tt = True := eq_true_intro rfl

@[simp] theorem coe_sort_ff : ↥false = False := eq_false_intro ff_ne_tt

@[simp] theorem to_bool_true {h : Decidable True} : to_bool True = tt := sorry

@[simp] theorem to_bool_false {h : Decidable False} : to_bool False = false := sorry

@[simp] theorem to_bool_coe (b : Bool) {h : Decidable ↥b} : to_bool ↥b = b := sorry

theorem coe_to_bool (p : Prop) [Decidable p] : ↥(to_bool p) ↔ p := to_bool_iff p

@[simp] theorem of_to_bool_iff {p : Prop} [Decidable p] : ↥(to_bool p) ↔ p :=
  { mp := of_to_bool_true, mpr := to_bool_true }

@[simp] theorem tt_eq_to_bool_iff {p : Prop} [Decidable p] : tt = to_bool p ↔ p :=
  iff.trans eq_comm of_to_bool_iff

@[simp] theorem ff_eq_to_bool_iff {p : Prop} [Decidable p] : false = to_bool p ↔ ¬p :=
  iff.trans eq_comm (to_bool_ff_iff p)

@[simp] theorem to_bool_not (p : Prop) [Decidable p] : to_bool (¬p) = !to_bool p := sorry

@[simp] theorem to_bool_and (p : Prop) (q : Prop) [Decidable p] [Decidable q] :
    to_bool (p ∧ q) = to_bool p && to_bool q :=
  sorry

@[simp] theorem to_bool_or (p : Prop) (q : Prop) [Decidable p] [Decidable q] :
    to_bool (p ∨ q) = to_bool p || to_bool q :=
  sorry

@[simp] theorem to_bool_eq {p : Prop} {q : Prop} [Decidable p] [Decidable q] :
    to_bool p = to_bool q ↔ (p ↔ q) :=
  sorry

theorem not_ff : ¬↥false := sorry

@[simp] theorem default_bool : Inhabited.default = false := rfl

theorem dichotomy (b : Bool) : b = false ∨ b = tt := sorry

@[simp] theorem forall_bool {p : Bool → Prop} : (∀ (b : Bool), p b) ↔ p false ∧ p tt := sorry

@[simp] theorem exists_bool {p : Bool → Prop} : (∃ (b : Bool), p b) ↔ p false ∨ p tt := sorry

/-- If `p b` is decidable for all `b : bool`, then `∀ b, p b` is decidable -/
protected instance decidable_forall_bool {p : Bool → Prop} [(b : Bool) → Decidable (p b)] :
    Decidable (∀ (b : Bool), p b) :=
  decidable_of_decidable_of_iff and.decidable sorry

/-- If `p b` is decidable for all `b : bool`, then `∃ b, p b` is decidable -/
protected instance decidable_exists_bool {p : Bool → Prop} [(b : Bool) → Decidable (p b)] :
    Decidable (∃ (b : Bool), p b) :=
  decidable_of_decidable_of_iff or.decidable sorry

@[simp] theorem cond_ff {α : Type u_1} (t : α) (e : α) : cond false t e = e := rfl

@[simp] theorem cond_tt {α : Type u_1} (t : α) (e : α) : cond tt t e = t := rfl

@[simp] theorem cond_to_bool {α : Type u_1} (p : Prop) [Decidable p] (t : α) (e : α) :
    cond (to_bool p) t e = ite p t e :=
  sorry

theorem coe_bool_iff {a : Bool} {b : Bool} : ↥a ↔ ↥b ↔ a = b := of_as_true trivial

theorem eq_tt_of_ne_ff {a : Bool} : a ≠ false → a = tt := of_as_true trivial

theorem eq_ff_of_ne_tt {a : Bool} : a ≠ tt → a = false := of_as_true trivial

theorem bor_comm (a : Bool) (b : Bool) : a || b = b || a := of_as_true trivial

@[simp] theorem bor_assoc (a : Bool) (b : Bool) (c : Bool) : a || b || c = a || (b || c) :=
  of_as_true trivial

theorem bor_left_comm (a : Bool) (b : Bool) (c : Bool) : a || (b || c) = b || (a || c) :=
  of_as_true trivial

theorem bor_inl {a : Bool} {b : Bool} (H : ↥a) : ↥(a || b) := sorry

theorem bor_inr {a : Bool} {b : Bool} (H : ↥b) : ↥(a || b) := sorry

theorem band_comm (a : Bool) (b : Bool) : a && b = b && a := of_as_true trivial

@[simp] theorem band_assoc (a : Bool) (b : Bool) (c : Bool) : a && b && c = a && (b && c) :=
  of_as_true trivial

theorem band_left_comm (a : Bool) (b : Bool) (c : Bool) : a && (b && c) = b && (a && c) :=
  of_as_true trivial

theorem band_elim_left {a : Bool} {b : Bool} : ↥(a && b) → ↥a := of_as_true trivial

theorem band_intro {a : Bool} {b : Bool} : ↥a → ↥b → ↥(a && b) := of_as_true trivial

theorem band_elim_right {a : Bool} {b : Bool} : ↥(a && b) → ↥b := of_as_true trivial

@[simp] theorem bnot_false : !false = tt := rfl

@[simp] theorem bnot_true : !tt = false := rfl

theorem eq_tt_of_bnot_eq_ff {a : Bool} : !a = false → a = tt := of_as_true trivial

theorem eq_ff_of_bnot_eq_tt {a : Bool} : !a = tt → a = false := of_as_true trivial

theorem bxor_comm (a : Bool) (b : Bool) : bxor a b = bxor b a := of_as_true trivial

@[simp] theorem bxor_assoc (a : Bool) (b : Bool) (c : Bool) :
    bxor (bxor a b) c = bxor a (bxor b c) :=
  of_as_true trivial

theorem bxor_left_comm (a : Bool) (b : Bool) (c : Bool) : bxor a (bxor b c) = bxor b (bxor a c) :=
  of_as_true trivial

@[simp] theorem bxor_bnot_left (a : Bool) : bxor (!a) a = tt := of_as_true trivial

@[simp] theorem bxor_bnot_right (a : Bool) : bxor a (!a) = tt := of_as_true trivial

@[simp] theorem bxor_bnot_bnot (a : Bool) (b : Bool) : bxor (!a) (!b) = bxor a b :=
  of_as_true trivial

@[simp] theorem bxor_ff_left (a : Bool) : bxor false a = a := of_as_true trivial

@[simp] theorem bxor_ff_right (a : Bool) : bxor a false = a := of_as_true trivial

theorem bxor_iff_ne {x : Bool} {y : Bool} : bxor x y = tt ↔ x ≠ y := of_as_true trivial

/-! ### De Morgan's laws for booleans-/

@[simp] theorem bnot_band (a : Bool) (b : Bool) : !(a && b) = !a || !b := of_as_true trivial

@[simp] theorem bnot_bor (a : Bool) (b : Bool) : !(a || b) = !a && !b := of_as_true trivial

theorem bnot_inj {a : Bool} {b : Bool} : !a = !b → a = b := of_as_true trivial

end bool

protected instance bool.linear_order : linear_order Bool :=
  linear_order.mk (fun (a b : Bool) => a = false ∨ b = tt)
    (partial_order.lt._default fun (a b : Bool) => a = false ∨ b = tt) sorry sorry sorry sorry
    infer_instance infer_instance infer_instance

namespace bool

@[simp] theorem ff_le {x : Bool} : false ≤ x := or.intro_left (x = tt) rfl

@[simp] theorem le_tt {x : Bool} : x ≤ tt := or.intro_right (x = false) rfl

@[simp] theorem ff_lt_tt : false < tt := lt_of_le_of_ne ff_le ff_ne_tt

/-- convert a `bool` to a `ℕ`, `false -> 0`, `true -> 1` -/
def to_nat (b : Bool) : ℕ := cond b 1 0

/-- convert a `ℕ` to a `bool`, `0 -> false`, everything else -> `true` -/
def of_nat (n : ℕ) : Bool := to_bool (n ≠ 0)

theorem of_nat_le_of_nat {n : ℕ} {m : ℕ} (h : n ≤ m) : of_nat n ≤ of_nat m := sorry

theorem to_nat_le_to_nat {b₀ : Bool} {b₁ : Bool} (h : b₀ ≤ b₁) : to_nat b₀ ≤ to_nat b₁ := sorry

theorem of_nat_to_nat (b : Bool) : of_nat (to_nat b) = b := sorry

end Mathlib