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

! This file was ported from Lean 3 source module order.rel_iso.set
! leanprover-community/mathlib commit 448144f7ae193a8990cb7473c9e9a01990f64ac7
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Order.RelIso.Basic
import Mathbin.Logic.Embedding.Set

/-!
# Interactions between relation homomorphisms and sets

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

It is likely that there are better homes for many of these statement,
in files further down the import graph.
-/

open Function

universe u v w

variable {α β γ δ : Type _} {r : α → α → Prop} {s : β → β → Prop} {t : γ → γ → Prop}
  {u : δ → δ → Prop}

namespace RelHomClass

variable {F : Type _}

/- warning: rel_hom_class.map_inf -> RelHomClass.map_inf is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {F : Type.{u3}} [_inst_1 : SemilatticeInf.{u1} α] [_inst_2 : LinearOrder.{u2} β] [_inst_3 : RelHomClass.{u3, u2, u1} F β α (LT.lt.{u2} β (Preorder.toLT.{u2} β (PartialOrder.toPreorder.{u2} β (SemilatticeInf.toPartialOrder.{u2} β (Lattice.toSemilatticeInf.{u2} β (LinearOrder.toLattice.{u2} β _inst_2)))))) (LT.lt.{u1} α (Preorder.toLT.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α _inst_1))))] (a : F) (m : β) (n : β), Eq.{succ u1} α (coeFn.{succ u3, max (succ u2) (succ u1)} F (fun (_x : F) => β -> α) (FunLike.hasCoeToFun.{succ u3, succ u2, succ u1} F β (fun (_x : β) => α) (RelHomClass.toFunLike.{u3, u2, u1} F β α (LT.lt.{u2} β (Preorder.toLT.{u2} β (PartialOrder.toPreorder.{u2} β (SemilatticeInf.toPartialOrder.{u2} β (Lattice.toSemilatticeInf.{u2} β (LinearOrder.toLattice.{u2} β _inst_2)))))) (LT.lt.{u1} α (Preorder.toLT.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α _inst_1)))) _inst_3)) a (Inf.inf.{u2} β (SemilatticeInf.toHasInf.{u2} β (Lattice.toSemilatticeInf.{u2} β (LinearOrder.toLattice.{u2} β _inst_2))) m n)) (Inf.inf.{u1} α (SemilatticeInf.toHasInf.{u1} α _inst_1) (coeFn.{succ u3, max (succ u2) (succ u1)} F (fun (_x : F) => β -> α) (FunLike.hasCoeToFun.{succ u3, succ u2, succ u1} F β (fun (_x : β) => α) (RelHomClass.toFunLike.{u3, u2, u1} F β α (LT.lt.{u2} β (Preorder.toLT.{u2} β (PartialOrder.toPreorder.{u2} β (SemilatticeInf.toPartialOrder.{u2} β (Lattice.toSemilatticeInf.{u2} β (LinearOrder.toLattice.{u2} β _inst_2)))))) (LT.lt.{u1} α (Preorder.toLT.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α _inst_1)))) _inst_3)) a m) (coeFn.{succ u3, max (succ u2) (succ u1)} F (fun (_x : F) => β -> α) (FunLike.hasCoeToFun.{succ u3, succ u2, succ u1} F β (fun (_x : β) => α) (RelHomClass.toFunLike.{u3, u2, u1} F β α (LT.lt.{u2} β (Preorder.toLT.{u2} β (PartialOrder.toPreorder.{u2} β (SemilatticeInf.toPartialOrder.{u2} β (Lattice.toSemilatticeInf.{u2} β (LinearOrder.toLattice.{u2} β _inst_2)))))) (LT.lt.{u1} α (Preorder.toLT.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α _inst_1)))) _inst_3)) a n))
but is expected to have type
  forall {α : Type.{u3}} {β : Type.{u2}} {F : Type.{u1}} [_inst_1 : SemilatticeInf.{u3} α] [_inst_2 : LinearOrder.{u2} β] [_inst_3 : RelHomClass.{u1, u2, u3} F β α (fun (x._@.Mathlib.Order.RelIso.Set._hyg.111 : β) (x._@.Mathlib.Order.RelIso.Set._hyg.113 : β) => LT.lt.{u2} β (Preorder.toLT.{u2} β (PartialOrder.toPreorder.{u2} β (SemilatticeInf.toPartialOrder.{u2} β (Lattice.toSemilatticeInf.{u2} β (DistribLattice.toLattice.{u2} β (instDistribLattice.{u2} β _inst_2)))))) x._@.Mathlib.Order.RelIso.Set._hyg.111 x._@.Mathlib.Order.RelIso.Set._hyg.113) (fun (x._@.Mathlib.Order.RelIso.Set._hyg.133 : α) (x._@.Mathlib.Order.RelIso.Set._hyg.135 : α) => LT.lt.{u3} α (Preorder.toLT.{u3} α (PartialOrder.toPreorder.{u3} α (SemilatticeInf.toPartialOrder.{u3} α _inst_1))) x._@.Mathlib.Order.RelIso.Set._hyg.133 x._@.Mathlib.Order.RelIso.Set._hyg.135)] (a : F) (m : β) (n : β), Eq.{succ u3} ((fun (x._@.Mathlib.Order.RelIso.Basic._hyg.867 : β) => α) (Inf.inf.{u2} β (Lattice.toInf.{u2} β (DistribLattice.toLattice.{u2} β (instDistribLattice.{u2} β _inst_2))) m n)) (FunLike.coe.{succ u1, succ u2, succ u3} F β (fun (_x : β) => (fun (x._@.Mathlib.Order.RelIso.Basic._hyg.867 : β) => α) _x) (RelHomClass.toFunLike.{u1, u2, u3} F β α (fun (x._@.Mathlib.Order.RelIso.Set._hyg.111 : β) (x._@.Mathlib.Order.RelIso.Set._hyg.113 : β) => LT.lt.{u2} β (Preorder.toLT.{u2} β (PartialOrder.toPreorder.{u2} β (SemilatticeInf.toPartialOrder.{u2} β (Lattice.toSemilatticeInf.{u2} β (DistribLattice.toLattice.{u2} β (instDistribLattice.{u2} β _inst_2)))))) x._@.Mathlib.Order.RelIso.Set._hyg.111 x._@.Mathlib.Order.RelIso.Set._hyg.113) (fun (_x : α) (x._@.Mathlib.Order.RelIso.Set._hyg.135 : α) => LT.lt.{u3} α (Preorder.toLT.{u3} α (PartialOrder.toPreorder.{u3} α (SemilatticeInf.toPartialOrder.{u3} α _inst_1))) _x x._@.Mathlib.Order.RelIso.Set._hyg.135) _inst_3) a (Inf.inf.{u2} β (Lattice.toInf.{u2} β (DistribLattice.toLattice.{u2} β (instDistribLattice.{u2} β _inst_2))) m n)) (Inf.inf.{u3} ((fun (x._@.Mathlib.Order.RelIso.Basic._hyg.867 : β) => α) m) (SemilatticeInf.toInf.{u3} ((fun (x._@.Mathlib.Order.RelIso.Basic._hyg.867 : β) => α) m) _inst_1) (FunLike.coe.{succ u1, succ u2, succ u3} F β (fun (_x : β) => (fun (x._@.Mathlib.Order.RelIso.Basic._hyg.867 : β) => α) _x) (RelHomClass.toFunLike.{u1, u2, u3} F β α (fun (x._@.Mathlib.Order.RelIso.Set._hyg.111 : β) (x._@.Mathlib.Order.RelIso.Set._hyg.113 : β) => LT.lt.{u2} β (Preorder.toLT.{u2} β (PartialOrder.toPreorder.{u2} β (SemilatticeInf.toPartialOrder.{u2} β (Lattice.toSemilatticeInf.{u2} β (DistribLattice.toLattice.{u2} β (instDistribLattice.{u2} β _inst_2)))))) x._@.Mathlib.Order.RelIso.Set._hyg.111 x._@.Mathlib.Order.RelIso.Set._hyg.113) (fun (_x : α) (x._@.Mathlib.Order.RelIso.Set._hyg.135 : α) => LT.lt.{u3} α (Preorder.toLT.{u3} α (PartialOrder.toPreorder.{u3} α (SemilatticeInf.toPartialOrder.{u3} α _inst_1))) _x x._@.Mathlib.Order.RelIso.Set._hyg.135) _inst_3) a m) (FunLike.coe.{succ u1, succ u2, succ u3} F β (fun (_x : β) => (fun (x._@.Mathlib.Order.RelIso.Basic._hyg.867 : β) => α) _x) (RelHomClass.toFunLike.{u1, u2, u3} F β α (fun (x._@.Mathlib.Order.RelIso.Set._hyg.111 : β) (x._@.Mathlib.Order.RelIso.Set._hyg.113 : β) => LT.lt.{u2} β (Preorder.toLT.{u2} β (PartialOrder.toPreorder.{u2} β (SemilatticeInf.toPartialOrder.{u2} β (Lattice.toSemilatticeInf.{u2} β (DistribLattice.toLattice.{u2} β (instDistribLattice.{u2} β _inst_2)))))) x._@.Mathlib.Order.RelIso.Set._hyg.111 x._@.Mathlib.Order.RelIso.Set._hyg.113) (fun (_x : α) (x._@.Mathlib.Order.RelIso.Set._hyg.135 : α) => LT.lt.{u3} α (Preorder.toLT.{u3} α (PartialOrder.toPreorder.{u3} α (SemilatticeInf.toPartialOrder.{u3} α _inst_1))) _x x._@.Mathlib.Order.RelIso.Set._hyg.135) _inst_3) a n))
Case conversion may be inaccurate. Consider using '#align rel_hom_class.map_inf RelHomClass.map_infₓ'. -/
theorem map_inf [SemilatticeInf α] [LinearOrder β]
    [RelHomClass F ((· < ·) : β → β → Prop) ((· < ·) : α → α → Prop)] (a : F) (m n : β) :
    a (m ⊓ n) = a m ⊓ a n :=
  (StrictMono.monotone fun x y => map_rel a).map_inf m n
#align rel_hom_class.map_inf RelHomClass.map_inf

/- warning: rel_hom_class.map_sup -> RelHomClass.map_sup is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {F : Type.{u3}} [_inst_1 : SemilatticeSup.{u1} α] [_inst_2 : LinearOrder.{u2} β] [_inst_3 : RelHomClass.{u3, u2, u1} F β α (GT.gt.{u2} β (Preorder.toLT.{u2} β (PartialOrder.toPreorder.{u2} β (SemilatticeInf.toPartialOrder.{u2} β (Lattice.toSemilatticeInf.{u2} β (LinearOrder.toLattice.{u2} β _inst_2)))))) (GT.gt.{u1} α (Preorder.toLT.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeSup.toPartialOrder.{u1} α _inst_1))))] (a : F) (m : β) (n : β), Eq.{succ u1} α (coeFn.{succ u3, max (succ u2) (succ u1)} F (fun (_x : F) => β -> α) (FunLike.hasCoeToFun.{succ u3, succ u2, succ u1} F β (fun (_x : β) => α) (RelHomClass.toFunLike.{u3, u2, u1} F β α (GT.gt.{u2} β (Preorder.toLT.{u2} β (PartialOrder.toPreorder.{u2} β (SemilatticeInf.toPartialOrder.{u2} β (Lattice.toSemilatticeInf.{u2} β (LinearOrder.toLattice.{u2} β _inst_2)))))) (GT.gt.{u1} α (Preorder.toLT.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeSup.toPartialOrder.{u1} α _inst_1)))) _inst_3)) a (Sup.sup.{u2} β (SemilatticeSup.toHasSup.{u2} β (Lattice.toSemilatticeSup.{u2} β (LinearOrder.toLattice.{u2} β _inst_2))) m n)) (Sup.sup.{u1} α (SemilatticeSup.toHasSup.{u1} α _inst_1) (coeFn.{succ u3, max (succ u2) (succ u1)} F (fun (_x : F) => β -> α) (FunLike.hasCoeToFun.{succ u3, succ u2, succ u1} F β (fun (_x : β) => α) (RelHomClass.toFunLike.{u3, u2, u1} F β α (GT.gt.{u2} β (Preorder.toLT.{u2} β (PartialOrder.toPreorder.{u2} β (SemilatticeInf.toPartialOrder.{u2} β (Lattice.toSemilatticeInf.{u2} β (LinearOrder.toLattice.{u2} β _inst_2)))))) (GT.gt.{u1} α (Preorder.toLT.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeSup.toPartialOrder.{u1} α _inst_1)))) _inst_3)) a m) (coeFn.{succ u3, max (succ u2) (succ u1)} F (fun (_x : F) => β -> α) (FunLike.hasCoeToFun.{succ u3, succ u2, succ u1} F β (fun (_x : β) => α) (RelHomClass.toFunLike.{u3, u2, u1} F β α (GT.gt.{u2} β (Preorder.toLT.{u2} β (PartialOrder.toPreorder.{u2} β (SemilatticeInf.toPartialOrder.{u2} β (Lattice.toSemilatticeInf.{u2} β (LinearOrder.toLattice.{u2} β _inst_2)))))) (GT.gt.{u1} α (Preorder.toLT.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeSup.toPartialOrder.{u1} α _inst_1)))) _inst_3)) a n))
but is expected to have type
  forall {α : Type.{u3}} {β : Type.{u2}} {F : Type.{u1}} [_inst_1 : SemilatticeSup.{u3} α] [_inst_2 : LinearOrder.{u2} β] [_inst_3 : RelHomClass.{u1, u2, u3} F β α (fun (x._@.Mathlib.Order.RelIso.Set._hyg.228 : β) (x._@.Mathlib.Order.RelIso.Set._hyg.230 : β) => GT.gt.{u2} β (Preorder.toLT.{u2} β (PartialOrder.toPreorder.{u2} β (SemilatticeInf.toPartialOrder.{u2} β (Lattice.toSemilatticeInf.{u2} β (DistribLattice.toLattice.{u2} β (instDistribLattice.{u2} β _inst_2)))))) x._@.Mathlib.Order.RelIso.Set._hyg.228 x._@.Mathlib.Order.RelIso.Set._hyg.230) (fun (x._@.Mathlib.Order.RelIso.Set._hyg.250 : α) (x._@.Mathlib.Order.RelIso.Set._hyg.252 : α) => GT.gt.{u3} α (Preorder.toLT.{u3} α (PartialOrder.toPreorder.{u3} α (SemilatticeSup.toPartialOrder.{u3} α _inst_1))) x._@.Mathlib.Order.RelIso.Set._hyg.250 x._@.Mathlib.Order.RelIso.Set._hyg.252)] (a : F) (m : β) (n : β), Eq.{succ u3} ((fun (x._@.Mathlib.Order.RelIso.Basic._hyg.867 : β) => α) (Sup.sup.{u2} β (SemilatticeSup.toSup.{u2} β (Lattice.toSemilatticeSup.{u2} β (DistribLattice.toLattice.{u2} β (instDistribLattice.{u2} β _inst_2)))) m n)) (FunLike.coe.{succ u1, succ u2, succ u3} F β (fun (_x : β) => (fun (x._@.Mathlib.Order.RelIso.Basic._hyg.867 : β) => α) _x) (RelHomClass.toFunLike.{u1, u2, u3} F β α (fun (x._@.Mathlib.Order.RelIso.Set._hyg.228 : β) (x._@.Mathlib.Order.RelIso.Set._hyg.230 : β) => GT.gt.{u2} β (Preorder.toLT.{u2} β (PartialOrder.toPreorder.{u2} β (SemilatticeInf.toPartialOrder.{u2} β (Lattice.toSemilatticeInf.{u2} β (DistribLattice.toLattice.{u2} β (instDistribLattice.{u2} β _inst_2)))))) x._@.Mathlib.Order.RelIso.Set._hyg.228 x._@.Mathlib.Order.RelIso.Set._hyg.230) (fun (_x : α) (x._@.Mathlib.Order.RelIso.Set._hyg.252 : α) => GT.gt.{u3} α (Preorder.toLT.{u3} α (PartialOrder.toPreorder.{u3} α (SemilatticeSup.toPartialOrder.{u3} α _inst_1))) _x x._@.Mathlib.Order.RelIso.Set._hyg.252) _inst_3) a (Sup.sup.{u2} β (SemilatticeSup.toSup.{u2} β (Lattice.toSemilatticeSup.{u2} β (DistribLattice.toLattice.{u2} β (instDistribLattice.{u2} β _inst_2)))) m n)) (Sup.sup.{u3} ((fun (x._@.Mathlib.Order.RelIso.Basic._hyg.867 : β) => α) m) (SemilatticeSup.toSup.{u3} ((fun (x._@.Mathlib.Order.RelIso.Basic._hyg.867 : β) => α) m) _inst_1) (FunLike.coe.{succ u1, succ u2, succ u3} F β (fun (_x : β) => (fun (x._@.Mathlib.Order.RelIso.Basic._hyg.867 : β) => α) _x) (RelHomClass.toFunLike.{u1, u2, u3} F β α (fun (x._@.Mathlib.Order.RelIso.Set._hyg.228 : β) (x._@.Mathlib.Order.RelIso.Set._hyg.230 : β) => GT.gt.{u2} β (Preorder.toLT.{u2} β (PartialOrder.toPreorder.{u2} β (SemilatticeInf.toPartialOrder.{u2} β (Lattice.toSemilatticeInf.{u2} β (DistribLattice.toLattice.{u2} β (instDistribLattice.{u2} β _inst_2)))))) x._@.Mathlib.Order.RelIso.Set._hyg.228 x._@.Mathlib.Order.RelIso.Set._hyg.230) (fun (_x : α) (x._@.Mathlib.Order.RelIso.Set._hyg.252 : α) => GT.gt.{u3} α (Preorder.toLT.{u3} α (PartialOrder.toPreorder.{u3} α (SemilatticeSup.toPartialOrder.{u3} α _inst_1))) _x x._@.Mathlib.Order.RelIso.Set._hyg.252) _inst_3) a m) (FunLike.coe.{succ u1, succ u2, succ u3} F β (fun (_x : β) => (fun (x._@.Mathlib.Order.RelIso.Basic._hyg.867 : β) => α) _x) (RelHomClass.toFunLike.{u1, u2, u3} F β α (fun (x._@.Mathlib.Order.RelIso.Set._hyg.228 : β) (x._@.Mathlib.Order.RelIso.Set._hyg.230 : β) => GT.gt.{u2} β (Preorder.toLT.{u2} β (PartialOrder.toPreorder.{u2} β (SemilatticeInf.toPartialOrder.{u2} β (Lattice.toSemilatticeInf.{u2} β (DistribLattice.toLattice.{u2} β (instDistribLattice.{u2} β _inst_2)))))) x._@.Mathlib.Order.RelIso.Set._hyg.228 x._@.Mathlib.Order.RelIso.Set._hyg.230) (fun (_x : α) (x._@.Mathlib.Order.RelIso.Set._hyg.252 : α) => GT.gt.{u3} α (Preorder.toLT.{u3} α (PartialOrder.toPreorder.{u3} α (SemilatticeSup.toPartialOrder.{u3} α _inst_1))) _x x._@.Mathlib.Order.RelIso.Set._hyg.252) _inst_3) a n))
Case conversion may be inaccurate. Consider using '#align rel_hom_class.map_sup RelHomClass.map_supₓ'. -/
theorem map_sup [SemilatticeSup α] [LinearOrder β]
    [RelHomClass F ((· > ·) : β → β → Prop) ((· > ·) : α → α → Prop)] (a : F) (m n : β) :
    a (m ⊔ n) = a m ⊔ a n :=
  @map_inf αᵒᵈ βᵒᵈ _ _ _ _ _ _ _
#align rel_hom_class.map_sup RelHomClass.map_sup

end RelHomClass

namespace RelIso

/- warning: rel_iso.range_eq -> RelIso.range_eq is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {r : α -> α -> Prop} {s : β -> β -> Prop} (e : RelIso.{u1, u2} α β r s), Eq.{succ u2} (Set.{u2} β) (Set.range.{u2, succ u1} β α (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RelIso.{u1, u2} α β r s) (fun (_x : RelIso.{u1, u2} α β r s) => α -> β) (RelIso.hasCoeToFun.{u1, u2} α β r s) e)) (Set.univ.{u2} β)
but is expected to have type
  forall {α : Type.{u2}} {β : Type.{u1}} {r : α -> α -> Prop} {s : β -> β -> Prop} (e : RelIso.{u2, u1} α β r s), Eq.{succ u1} (Set.{u1} β) (Set.range.{u1, succ u2} β α (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α (fun (_x : α) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => β) _x) (EmbeddingLike.toFunLike.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α β (Function.instEmbeddingLikeEmbedding.{succ u2, succ u1} α β)) (RelEmbedding.toEmbedding.{u2, u1} α β r s (RelIso.toRelEmbedding.{u2, u1} α β r s e)))) (Set.univ.{u1} β)
Case conversion may be inaccurate. Consider using '#align rel_iso.range_eq RelIso.range_eqₓ'. -/
@[simp]
theorem range_eq (e : r ≃r s) : Set.range e = Set.univ :=
  e.Surjective.range_eq
#align rel_iso.range_eq RelIso.range_eq

end RelIso

#print Subrel /-
/-- `subrel r p` is the inherited relation on a subset. -/
def Subrel (r : α → α → Prop) (p : Set α) : p → p → Prop :=
  (coe : p → α) ⁻¹'o r
#align subrel Subrel
-/

#print subrel_val /-
@[simp]
theorem subrel_val (r : α → α → Prop) (p : Set α) {a b} : Subrel r p a b ↔ r a.1 b.1 :=
  Iff.rfl
#align subrel_val subrel_val
-/

namespace Subrel

#print Subrel.relEmbedding /-
/-- The relation embedding from the inherited relation on a subset. -/
protected def relEmbedding (r : α → α → Prop) (p : Set α) : Subrel r p ↪r r :=
  ⟨Embedding.subtype _, fun a b => Iff.rfl⟩
#align subrel.rel_embedding Subrel.relEmbedding
-/

/- warning: subrel.rel_embedding_apply -> Subrel.relEmbedding_apply is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} (r : α -> α -> Prop) (p : Set.{u1} α) (a : coeSort.{succ u1, succ (succ u1)} (Set.{u1} α) Type.{u1} (Set.hasCoeToSort.{u1} α) p), Eq.{succ u1} α (coeFn.{succ u1, succ u1} (RelEmbedding.{u1, u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} α) Type.{u1} (Set.hasCoeToSort.{u1} α) p) α (Subrel.{u1} α r p) r) (fun (_x : RelEmbedding.{u1, u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} α) Type.{u1} (Set.hasCoeToSort.{u1} α) p) α (Subrel.{u1} α r p) r) => (coeSort.{succ u1, succ (succ u1)} (Set.{u1} α) Type.{u1} (Set.hasCoeToSort.{u1} α) p) -> α) (RelEmbedding.hasCoeToFun.{u1, u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} α) Type.{u1} (Set.hasCoeToSort.{u1} α) p) α (Subrel.{u1} α r p) r) (Subrel.relEmbedding.{u1} α r p) a) (Subtype.val.{succ u1} α (fun (x : α) => Membership.Mem.{u1, u1} α (Set.{u1} α) (Set.hasMem.{u1} α) x p) a)
but is expected to have type
  forall {α : Type.{u1}} (r : α -> α -> Prop) (p : Set.{u1} α) (a : Set.Elem.{u1} α p), Eq.{succ u1} ((fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : Set.Elem.{u1} α p) => α) a) (FunLike.coe.{succ u1, succ u1, succ u1} (Function.Embedding.{succ u1, succ u1} (Set.Elem.{u1} α p) α) (Set.Elem.{u1} α p) (fun (_x : Set.Elem.{u1} α p) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : Set.Elem.{u1} α p) => α) _x) (EmbeddingLike.toFunLike.{succ u1, succ u1, succ u1} (Function.Embedding.{succ u1, succ u1} (Set.Elem.{u1} α p) α) (Set.Elem.{u1} α p) α (Function.instEmbeddingLikeEmbedding.{succ u1, succ u1} (Set.Elem.{u1} α p) α)) (RelEmbedding.toEmbedding.{u1, u1} (Set.Elem.{u1} α p) α (Subrel.{u1} α r p) r (Subrel.relEmbedding.{u1} α r p)) a) (Subtype.val.{succ u1} α (fun (x : α) => Membership.mem.{u1, u1} α (Set.{u1} α) (Set.instMembershipSet.{u1} α) x p) a)
Case conversion may be inaccurate. Consider using '#align subrel.rel_embedding_apply Subrel.relEmbedding_applyₓ'. -/
@[simp]
theorem relEmbedding_apply (r : α → α → Prop) (p a) : Subrel.relEmbedding r p a = a.1 :=
  rfl
#align subrel.rel_embedding_apply Subrel.relEmbedding_apply

instance (r : α → α → Prop) [IsWellOrder α r] (p : Set α) : IsWellOrder p (Subrel r p) :=
  RelEmbedding.isWellOrder (Subrel.relEmbedding r p)

instance (r : α → α → Prop) [IsRefl α r] (p : Set α) : IsRefl p (Subrel r p) :=
  ⟨fun x => @IsRefl.refl α r _ x⟩

instance (r : α → α → Prop) [IsSymm α r] (p : Set α) : IsSymm p (Subrel r p) :=
  ⟨fun x y => @IsSymm.symm α r _ x y⟩

instance (r : α → α → Prop) [IsTrans α r] (p : Set α) : IsTrans p (Subrel r p) :=
  ⟨fun x y z => @IsTrans.trans α r _ x y z⟩

instance (r : α → α → Prop) [IsIrrefl α r] (p : Set α) : IsIrrefl p (Subrel r p) :=
  ⟨fun x => @IsIrrefl.irrefl α r _ x⟩

end Subrel

/- warning: rel_embedding.cod_restrict -> RelEmbedding.codRestrict is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {r : α -> α -> Prop} {s : β -> β -> Prop} (p : Set.{u2} β) (f : RelEmbedding.{u1, u2} α β r s), (forall (a : α), Membership.Mem.{u2, u2} β (Set.{u2} β) (Set.hasMem.{u2} β) (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RelEmbedding.{u1, u2} α β r s) (fun (_x : RelEmbedding.{u1, u2} α β r s) => α -> β) (RelEmbedding.hasCoeToFun.{u1, u2} α β r s) f a) p) -> (RelEmbedding.{u1, u2} α (coeSort.{succ u2, succ (succ u2)} (Set.{u2} β) Type.{u2} (Set.hasCoeToSort.{u2} β) p) r (Subrel.{u2} β s p))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} {r : α -> α -> Prop} {s : β -> β -> Prop} (p : Set.{u2} β) (f : RelEmbedding.{u1, u2} α β r s), (forall (a : α), Membership.mem.{u2, u2} ((fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => β) a) (Set.{u2} β) (Set.instMembershipSet.{u2} β) (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (Function.Embedding.{succ u1, succ u2} α β) α (fun (_x : α) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => β) _x) (EmbeddingLike.toFunLike.{max (succ u1) (succ u2), succ u1, succ u2} (Function.Embedding.{succ u1, succ u2} α β) α β (Function.instEmbeddingLikeEmbedding.{succ u1, succ u2} α β)) (RelEmbedding.toEmbedding.{u1, u2} α β r s f) a) p) -> (RelEmbedding.{u1, u2} α (Set.Elem.{u2} β p) r (Subrel.{u2} β s p))
Case conversion may be inaccurate. Consider using '#align rel_embedding.cod_restrict RelEmbedding.codRestrictₓ'. -/
/-- Restrict the codomain of a relation embedding. -/
def RelEmbedding.codRestrict (p : Set β) (f : r ↪r s) (H : ∀ a, f a ∈ p) : r ↪r Subrel s p :=
  ⟨f.toEmbedding.codRestrict p H, fun _ _ => f.map_rel_iff'⟩
#align rel_embedding.cod_restrict RelEmbedding.codRestrict

/- warning: rel_embedding.cod_restrict_apply -> RelEmbedding.codRestrict_apply is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {r : α -> α -> Prop} {s : β -> β -> Prop} (p : Set.{u2} β) (f : RelEmbedding.{u1, u2} α β r s) (H : forall (a : α), Membership.Mem.{u2, u2} β (Set.{u2} β) (Set.hasMem.{u2} β) (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RelEmbedding.{u1, u2} α β r s) (fun (_x : RelEmbedding.{u1, u2} α β r s) => α -> β) (RelEmbedding.hasCoeToFun.{u1, u2} α β r s) f a) p) (a : α), Eq.{succ u2} (coeSort.{succ u2, succ (succ u2)} (Set.{u2} β) Type.{u2} (Set.hasCoeToSort.{u2} β) p) (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RelEmbedding.{u1, u2} α (coeSort.{succ u2, succ (succ u2)} (Set.{u2} β) Type.{u2} (Set.hasCoeToSort.{u2} β) p) r (Subrel.{u2} β s p)) (fun (_x : RelEmbedding.{u1, u2} α (coeSort.{succ u2, succ (succ u2)} (Set.{u2} β) Type.{u2} (Set.hasCoeToSort.{u2} β) p) r (Subrel.{u2} β s p)) => α -> (coeSort.{succ u2, succ (succ u2)} (Set.{u2} β) Type.{u2} (Set.hasCoeToSort.{u2} β) p)) (RelEmbedding.hasCoeToFun.{u1, u2} α (coeSort.{succ u2, succ (succ u2)} (Set.{u2} β) Type.{u2} (Set.hasCoeToSort.{u2} β) p) r (Subrel.{u2} β s p)) (RelEmbedding.codRestrict.{u1, u2} α β r s p f H) a) (Subtype.mk.{succ u2} β (fun (x : β) => Membership.Mem.{u2, u2} β (Set.{u2} β) (Set.hasMem.{u2} β) x p) (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RelEmbedding.{u1, u2} α β r s) (fun (_x : RelEmbedding.{u1, u2} α β r s) => α -> β) (RelEmbedding.hasCoeToFun.{u1, u2} α β r s) f a) (H a))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} {r : α -> α -> Prop} {s : β -> β -> Prop} (p : Set.{u2} β) (f : RelEmbedding.{u1, u2} α β r s) (H : forall (a : α), Membership.mem.{u2, u2} ((fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => β) a) (Set.{u2} β) (Set.instMembershipSet.{u2} β) (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (Function.Embedding.{succ u1, succ u2} α β) α (fun (_x : α) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => β) _x) (EmbeddingLike.toFunLike.{max (succ u1) (succ u2), succ u1, succ u2} (Function.Embedding.{succ u1, succ u2} α β) α β (Function.instEmbeddingLikeEmbedding.{succ u1, succ u2} α β)) (RelEmbedding.toEmbedding.{u1, u2} α β r s f) a) p) (a : α), Eq.{succ u2} ((fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => Set.Elem.{u2} β p) a) (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (Function.Embedding.{succ u1, succ u2} α (Set.Elem.{u2} β p)) α (fun (_x : α) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => Set.Elem.{u2} β p) _x) (EmbeddingLike.toFunLike.{max (succ u1) (succ u2), succ u1, succ u2} (Function.Embedding.{succ u1, succ u2} α (Set.Elem.{u2} β p)) α (Set.Elem.{u2} β p) (Function.instEmbeddingLikeEmbedding.{succ u1, succ u2} α (Set.Elem.{u2} β p))) (RelEmbedding.toEmbedding.{u1, u2} α (Set.Elem.{u2} β p) r (Subrel.{u2} β s p) (RelEmbedding.codRestrict.{u1, u2} α β r s p f H)) a) (Subtype.mk.{succ u2} β (fun (x : β) => Membership.mem.{u2, u2} β (Set.{u2} β) (Set.instMembershipSet.{u2} β) x p) (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (Function.Embedding.{succ u1, succ u2} α β) α (fun (_x : α) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => β) _x) (EmbeddingLike.toFunLike.{max (succ u1) (succ u2), succ u1, succ u2} (Function.Embedding.{succ u1, succ u2} α β) α β (Function.instEmbeddingLikeEmbedding.{succ u1, succ u2} α β)) (RelEmbedding.toEmbedding.{u1, u2} α β r s f) a) (H a))
Case conversion may be inaccurate. Consider using '#align rel_embedding.cod_restrict_apply RelEmbedding.codRestrict_applyₓ'. -/
@[simp]
theorem RelEmbedding.codRestrict_apply (p) (f : r ↪r s) (H a) :
    RelEmbedding.codRestrict p f H a = ⟨f a, H a⟩ :=
  rfl
#align rel_embedding.cod_restrict_apply RelEmbedding.codRestrict_apply


import data.real.irrational
import topology.basic
import algebra.order.floor

--OUTPUT 1
theorem irrational_orbit_dense {α : ℝ} (hα_irrat : irrational α) : closure ((λ m : ℤ, int.fract (α * ↑m)) '' (@set.univ ℤ)) = set.Icc 0 1 :=
begin
  have h1 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h2 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h3 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h4 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h5 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h6 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h7 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h8 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h9 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h10 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h11 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h12 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h13 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h14 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h15 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h16 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h17 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h18 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h19 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h20 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h21 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h22 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h23 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h24 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h25 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h26 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h27 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h28 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h29 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h30 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h31 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h32 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h33 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h34 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h35 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h36 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h37 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h38 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h39 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h40 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.fract (α * ↑j)), from sorry,
  have h41 : ∀ (i j : ℤ), (i ≠ j) → (int.fract (α * ↑i) ≠ int.
end --Needs more than 2000 tokens!

--OUTPUT 2
theorem irrational_orbit_dense {α : ℝ} (hα_irrat : irrational α) : closure ((λ m : ℤ, int.fract (α * ↑m)) '' (@set.univ ℤ)) = set.Icc 0 1 :=
begin
  have h1 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j),
  from sorry,

  have h2 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)),
  from sorry,

  let S : set ℝ := (λ (m : ℤ), int.fract (α * ↑m)) '' (@set.univ ℤ),
  have h3 : S ≠ ∅, from sorry,

  have h4 : ∀ x : ℝ, x ∈ closure S → x ∈ S, from sorry,

  have h5 : ∀ x : ℝ, x ∈ closure S → x ∈ set.Icc 0 1, from sorry,

  have h6 : ∀ x : ℝ, x ∈ set.Icc 0 1 → x ∈ closure S, from sorry,

  have h7 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h8 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h9 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h10 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h11 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h12 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h13 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h14 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h15 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h16 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h17 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h18 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h19 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h20 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h21 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h22 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h23 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h24 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h25 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h26 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h27 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h28 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h29 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h30 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h31 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h32 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h33 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h34 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h35 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h36 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h37 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h38 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h39 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h40 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

  have h41 : ∀ y : ℝ, y ∈ set.Icc 0 1 → ∃ x : ℝ, x ∈ S ∧ abs (y - x) < 1, from sorry,

end --Needs more than 2000 tokens!

--OUTPUT 3
theorem irrational_orbit_dense {α : ℝ} (hα_irrat : irrational α) : closure ((λ m : ℤ, int.fract (α * ↑m)) '' (@set.univ ℤ)) = set.Icc 0 1 :=
begin
  have h1 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j),
  from sorry,

  have h2 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) ≤ int.fract (α * ↑j) ∨ int.fract (α * ↑j) ≤ int.fract (α * ↑i),
  from sorry,

  have h3 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h4 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h5 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h6 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h7 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h8 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h9 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h10 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h11 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h12 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h13 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h14 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h15 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h16 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h17 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h18 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h19 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h20 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h21 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h22 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h23 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h24 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h25 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h26 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h27 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h28 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) < int.fract (α * ↑j) ∨ int.fract (α * ↑j) < int.fract (α * ↑i),
  from sorry,

  have h29 : ∀ (i j : ℤ), i ≠ j → int.fract (α * ↑i) <
end --Needs more than 2000 tokens!

--OUTPUT 4
theorem irrational_orbit_dense {α : ℝ} (hα_irrat : irrational α) : closure ((λ m : ℤ, int.fract (α * ↑m)) '' (@set.univ ℤ)) = set.Icc 0 1 :=
begin
  have h1 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h2 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h3 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h4 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h5 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h6 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h7 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h8 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h9 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h10 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h11 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h12 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h13 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h14 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h15 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h16 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h17 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h18 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h19 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h20 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h21 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h22 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h23 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h24 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h25 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h26 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h27 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h28 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h29 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h30 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h31 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h32 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h33 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h34 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h35 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h36 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h37 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h38 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h39 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h40 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h41 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h42 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h43 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h44 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h45 : ∀ i j : ℤ, i ≠
end --Needs more than 2000 tokens!

--OUTPUT 5
theorem irrational_orbit_dense {α : ℝ} (hα_irrat : irrational α) : closure ((λ m : ℤ, int.fract (α * ↑m)) '' (@set.univ ℤ)) = set.Icc 0 1 :=
begin
  have h1 : ∀ i j : ℤ, i ≠ j → int.fract (α * ↑i) ≠ int.fract (α * ↑j), from sorry,
  have h2 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h3 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,

  have h4 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h5 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,

  have h6 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h7 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,

  have h8 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h9 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,

  have h10 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h11 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,

  have h12 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h13 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,

  have h14 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h15 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,

  have h16 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h17 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,

  have h18 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h19 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,

  have h20 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h21 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,

  have h22 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h23 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,

  have h24 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h25 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,

  have h26 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h27 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,

  have h28 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h29 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,

  have h30 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h31 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,

  have h32 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h33 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,

  have h34 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h35 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,

  have h36 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h37 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,

  have h38 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h39 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,

  have h40 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h41 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,

  have h42 : ∀ i j : ℤ, i ≠ j → (int.fract (α * ↑i)) ≠ (int.fract (α * ↑j)), from sorry,
  have h43 : ∀ i j : ℤ, i ≠ j → (int.fract (
end --Needs more than 2000 tokens!

--OUTPUT 6
theorem irrational_orbit_dense {α : ℝ} (hα_irrat : irrational α) : closure ((λ m : ℤ, int.fract (α * ↑m)) '' (@set.univ ℤ)) = set.Icc 0 1 := sorry

/--`theorem`
Density of rational orbit
The fractional parts of the integer multiples of a rational number form a dense subset of the unit interval
`proof`
Let $\alpha$ be a rational number. Then for distinct $i, j \in \mathbb{Z}$, we must have $\{i \alpha\} \neq\{j \alpha\}$. If this were not true, then
$$
i \alpha-\lfloor i \alpha\rfloor=\{i \alpha\}=\{j \alpha\}=j \alpha-\lfloor j \alpha\rfloor,
$$
which yields the false statement $\alpha=\frac{\lfloor i \alpha\rfloor-\lfloor j \alpha\rfloor}{i-j} \in \mathbb{Q}$. Hence,
$$
S:=\{\{i \alpha\} \mid i \in \mathbb{Z}\}
$$
is an infinite subset of $\left[0,1\right]$.

By the Bolzano-Weierstrass theorem, $S$ has a limit point in $[0, 1]$. One can thus find pairs of elements of $S$ that are arbitrarily close. Since (the absolute value of) the difference of any two elements of $S$ is also an element of $S$, it follows that $0$ is a limit point of $S$.

To show that $S$ is dense in $[0, 1]$, consider $y \in[0,1]$, and $\epsilon>0$. Then by selecting $x \in S$ such that $\{x\}<\epsilon$ (which exists as $0$ is a limit point), and $N$ such that $N \cdot\{x\} \leq y<(N+1) \cdot\{x\}$, we get: $|y-\{N x\}|<\epsilon$.

QED
-/
theorem  rational_orbit_dense {α : ℝ} (hα_rat : rational α) : closure ((λ m : ℤ, int.fract (α * ↑m)) '' (@set.univ ℤ)) = set.Icc 0 1 := sorry

/--`theorem`
The fractional parts of the integer multiples of an irrational number form a dense subset of the unit interval
`proof`
Let $\alpha$ be an irrational number. Then for distinct $i, j \in \mathbb{Z}$, we must have $\{i \alpha\} \neq\{j \alpha\}$. If this were not true, then
$$
i \alpha-\lfloor i \alpha\rfloor=\{i \alpha\}=\{j \alpha\}=j \alpha-\lfloor j \alpha\rfloor,
$$
which yields the false statement $\alpha=\frac{\lfloor i \alpha\rfloor-\lfloor j \alpha\rfloor}{i-j} \in \mathbb{Q}$. Hence,
$$
S:=\{\{i \alpha\} \mid i \in \mathbb{Z}\}
$$
is an infinite subset of $\left[0,1\right]$.

By the Bolzano-Weierstrass theorem, $S$ has a limit point in $[0, 1]$. One can thus find pairs of elements of $S$ that are arbitrarily close. Since (the absolute value of) the difference of any two elements of $S$ is also an element of $S$, it follows that $0$ is a limit point of $S$.

To show that $S$ is dense in $[0, 1]$, consider $y \in[0,1]$, and $\epsilon>0$. Then by selecting $x \in S$ such that $\{x\}<\epsilon$ (which exists as $0$ is a limit point), and $N$ such that $N \cdot\{x\} \leq y<(N+1) \cdot\{x\}$, we get: $|y-\{N x\}|<\epsilon$.

QED
-/
theorem  irrational_orbit_dense {α : ℝ} (hα_irrat : irrational α) : closure ((λ m : ℤ, int.fract (α * ↑m)) '' (@set.univ ℤ)) = set.Icc 0 1 := sorry

/--`theorem`
The fractional parts of the integer multiples of a rational number form a dense subset of the unit interval
`proof`
Let $\alpha$ be a rational number. Then for distinct $i, j \in \mathbb{Z}$, we must have $\{i \alpha\} \neq\{j \alpha\}$. If this were not true, then
$$
i \alpha-\lfloor i \alpha\rfloor=\{i \alpha\}=\{j \alpha\}=j \alpha-\lfloor j \alpha\rfloor,
$$
which yields the false statement $\alpha=\frac{\lfloor i \alpha\rfloor-\lfloor j \alpha\rfloor}{i-j} \in \mathbb{Q}$. Hence,
$$
S:=\{\{i \alpha\} \mid i \in \mathbb{Z}\}
$$
is an infinite subset of $\left[0,1\right]$.

By the Bolzano-Weierstrass theorem, $S$ has a limit point in $[0, 1]$. One can thus find pairs of elements of $S$ that are arbitrarily close. Since (the absolute value of) the difference of any two elements of $S$ is also an element of $S$, it follows that $0$ is a limit point of $S$.

To show that $S$ is dense in $[0, 1]$, consider $y \in[0,1]$, and $\epsilon>0$. Then by selecting $x \in S$ such that $\{x\}<\epsilon$ (which exists as $0$ is a limit point), and $N$ such that $N \cdot\{x\} \leq y<(N+1) \cdot\{x\}$, we get: $|y-\{N x\}|<\epsilon$.

QED
-/
theorem  rational_orbit_dense {α : ℝ} (hα_rat : rational α) : closure ((λ m : ℤ, int.fract (α * ↑m)) '' (@set.univ ℤ)) = set.Icc 0 1 := sorry

/--`theorem`
The fractional parts of the integer multiples of an irrational number form a dense subset of the unit interval
`proof`
Let $\alpha$ be an irrational number. Then for distinct $i, j \in \mathbb{Z}$, we must have $\{i \alpha\} \neq\{j \alpha\}$. If this were not true, then
$$
i \alpha-\lfloor i \alpha\rfloor=\{i \alpha\}=\{j \alpha\}=j \alpha-\lfloor j \alpha\rfloor,
$$
which yields the false statement $\alpha=\frac{\lfloor i \alpha\rfloor-\lfloor j \alpha\rfloor}{i-j} \in \mathbb{Q}$. Hence,
$$
S:=\{\{i \alpha\} \mid i \in \mathbb{Z}\}
$$
is an infinite subset of $\left[0,1\right]$.

By the Bolzano-Weierstrass theorem, $S$ has a limit point in $[0, 1]$. One can thus find pairs of elements of $S$ that are arbitrarily close. Since (the absolute value of) the difference of any two elements of $S$ is also an element of $S$, it follows that $0$ is a limit point of $S$.

To show that $S$ is dense in $[0, 1]$, consider $y \in[0,1]$, and $\epsilon>0$. Then by selecting $x \in S$ such that $\{x\}<\epsilon$ (which exists as $0$ is a limit point), and $N$ such that $N \cdot\{x\} \leq y<(N+1) \cdot\{x\}$, we get: $|y-\{N x\}|<\epsilon$.

QED
-/
theorem  irrational
end --Needs more than 2000 tokens!

/- FEW SHOT PROMPTS TO CODEX(START)
/--`theorem`
Power Set is Closed under Intersection
Let $S$ be a set.

Let $\powerset S$ be the power set of $S$.

Then:
:$\forall A, B \in \powerset S: A \cap B \in \powerset S$
`proof`
Let $A, B \in \powerset S$.

Then by the definition of power set, $A \subseteq S$ and $B \subseteq S$.

From Intersection is Subset we have that $A \cap B \subseteq A$.

It follows from Subset Relation is Transitive that $A \cap B \subseteq S$.

Thus $A \cap B \in \powerset S$ and closure is proved.
{{qed}}
-/
theorem power_set_intersection_closed {α : Type*} (S : set α) : ∀ A B ∈ 𝒫 S, (A ∩ B) ∈ 𝒫 S :=
begin
  assume (A : set α) (hA : A ∈ 𝒫 S) (B : set α) (hB : B ∈ 𝒫 S),
  have h1 : (A ⊆ S) ∧ (B ⊆ S), from sorry,
  have h2 : (A ∩ B) ⊆ A, from sorry,
  have h3 : (A ∩ B) ⊆ S, from sorry,
  show (A ∩ B) ∈  𝒫 S, from sorry,
end

/--`theorem`
Square of Sum
 :$\forall x, y \in \R: \paren {x + y}^2 = x^2 + 2 x y + y^2$
`proof`
Follows from the distribution of multiplication over addition:

{{begin-eqn}}
{{eqn | l = \left({x + y}\right)^2
      | r = \left({x + y}\right) \cdot \left({x + y}\right)
}}
{{eqn | r = x \cdot \left({x + y}\right) + y \cdot \left({x + y}\right)
      | c = Real Multiplication Distributes over Addition
}}
{{eqn | r = x \cdot x + x \cdot y + y \cdot x + y \cdot y
      | c = Real Multiplication Distributes over Addition
}}
{{eqn | r = x^2 + 2xy + y^2
      | c =
}}
{{end-eqn}}
{{qed}}
-/
theorem square_of_sum (x y : ℝ) : (x + y)^2 = (x^2 + 2*x*y + y^2) :=
begin
  calc (x + y)^2 = (x+y)*(x+y) : by sorry
  ... = x*(x+y) + y*(x+y) : by sorry
  ... = x*x + x*y + y*x + y*y : by sorry
  ... = x^2 + 2*x*y + y^2 : by sorry,
end

/--`theorem`
Identity of Group is Unique
Let $\struct {G, \circ}$ be a group. Then there is a unique identity element $e \in G$.
`proof`
From Group has Latin Square Property, there exists a unique $x \in G$ such that:
:$a x = b$

and there exists a unique $y \in G$ such that:
:$y a = b$

Setting $b = a$, this becomes:

There exists a unique $x \in G$ such that:
:$a x = a$

and there exists a unique $y \in G$ such that:
:$y a = a$

These $x$ and $y$ are both $e$, by definition of identity element.
{{qed}}
-/
theorem group_identity_unique {G : Type*} [group G] : ∃! e : G, ∀ a : G, e * a = a ∧ a * e = a :=
begin
  have h1 : ∀ a b : G, ∃! x : G, a * x = b, from sorry,
  have h2 : ∀ a b : G, ∃! y : G, y * a = b, from sorry,

  have h3 : ∀ a : G, ∃! x : G, a * x = a, from sorry,
  have h4 : ∀ a : G, ∃! y : G, y * a = a, from sorry,

  have h5 : ∀ a : G, classical.some (h3 a) = (1 : G), from sorry,
  have h6 : ∀ a : G, classical.some (h4 a) = (1 : G), from sorry,

  show ∃! e : G, ∀ a : G, e * a = a ∧ a * e = a, from by {
    use (1 : G),
    have h7 : ∀ e : G, (∀ a : G, e * a = a ∧ a * e = a) → e = 1, from by {
      assume (e : G) (h7 : ∀ a : G, e * a = a ∧ a * e = a),
      have h8 : ∀ a : G, e = classical.some (h3 a), from sorry,
      have h9 : ∀ a : G, e = classical.some (h4 a), from sorry,
      show e = (1 : G), from sorry,
    },
    sorry,
  }
end

/--`theorem`
Squeeze Theorem for Real Numbers
Let $\sequence {x_n}$, $\sequence {y_n}$ and $\sequence {z_n}$ be sequences in $\R$.

Let $\sequence {y_n}$ and $\sequence {z_n}$ both be convergent to the following limit:
:$\ds \lim_{n \mathop \to \infty} y_n = l, \lim_{n \mathop \to \infty} z_n = l$

Suppose that:
:$\forall n \in \N: y_n \le x_n \le z_n$

Then:
:$x_n \to l$ as $n \to \infty$
that is:
:$\ds \lim_{n \mathop \to \infty} x_n = l$

`proof`
From Negative of Absolute Value:
:$\size {x - l} < \epsilon \iff l - \epsilon < x < l + \epsilon$

Let $\epsilon > 0$.

We need to prove that:
:$\exists N: \forall n > N: \size {x_n - l} < \epsilon$

As $\ds \lim_{n \mathop \to \infty} y_n = l$ we know that:
:$\exists N_1: \forall n > N_1: \size {y_n - l} < \epsilon$

As $\ds \lim_{n \mathop \to \infty} z_n = l$ we know that:
:$\exists N_2: \forall n > N_2: \size {z_n - l} < \epsilon$

Let $N = \max \set {N_1, N_2}$.

Then if $n > N$, it follows that $n > N_1$ and $n > N_2$.

So:
:$\forall n > N: l - \epsilon < y_n < l + \epsilon$
:$\forall n > N: l - \epsilon < z_n < l + \epsilon$

But:
:$\forall n \in \N: y_n \le x_n \le z_n$

So:
:$\forall n > N: l - \epsilon < y_n \le x_n \le z_n < l + \epsilon$

and so:
:$\forall n > N: l - \epsilon < x_n < l + \epsilon$

So:
:$\forall n > N: \size {x_n - l} < \epsilon$

Hence the result.
{{qed}}

-/
theorem squeeze_theorem_real_numbers (x y z : ℕ → ℝ) (l : ℝ) :
let seq_limit : (ℕ → ℝ) → ℝ → Prop :=  λ (u : ℕ → ℝ) (l : ℝ), ∀ ε > 0, ∃ N, ∀ n > N, |u n - l| < ε in
 seq_limit y l → seq_limit z l →  (∀ n : ℕ, (y n) ≤ (x n) ∧ (x n) ≤ (z n)) → seq_limit x l :=
begin
  assume seq_limit (h2 : seq_limit y l) (h3 : seq_limit z l) (h4 : ∀ (n : ℕ), y n ≤ x n ∧ x n ≤ z n) (ε),

  have h5 : ∀ x, |x - l| < ε ↔ (((l - ε) < x) ∧ (x < (l + ε))),
  from sorry,

  assume (h7 : ε > 0),
  cases h2 ε h7 with N1 h8,
  cases h3 ε h7 with N2 h9,
  let N := max N1 N2,
  use N,

  have h10 : ∀ n > N, n > N1 ∧ n > N2 := sorry,
  have h11 : ∀ n > N, (((l - ε) < (y n)) ∧ ((y n) ≤ (x n))) ∧ (((x n) ≤ (z n)) ∧ ((z n) < l+ε)),
  from sorry,

  have h15 : ∀ n > N, ((l - ε) < (x n)) ∧ ((x n) < (l+ε)),
  from sorry,

  show  ∀ (n : ℕ), n > N → |x n - l| < ε,
  from sorry,
end

/--`theorem`
Density of irrational orbit
The fractional parts of the integer multiples of an irrational number form a dense subset of the unit interval
`proof`
Let $\alpha$ be an irrational number. Then for distinct $i, j \in \mathbb{Z}$, we must have $\{i \alpha\} \neq\{j \alpha\}$. If this were not true, then
$$
i \alpha-\lfloor i \alpha\rfloor=\{i \alpha\}=\{j \alpha\}=j \alpha-\lfloor j \alpha\rfloor,
$$
which yields the false statement $\alpha=\frac{\lfloor i \alpha\rfloor-\lfloor j \alpha\rfloor}{i-j} \in \mathbb{Q}$. Hence,
$$
S:=\{\{i \alpha\} \mid i \in \mathbb{Z}\}
$$
is an infinite subset of $\left[0,1\right]$.

By the Bolzano-Weierstrass theorem, $S$ has a limit point in $[0, 1]$. One can thus find pairs of elements of $S$ that are arbitrarily close. Since (the absolute value of) the difference of any two elements of $S$ is also an element of $S$, it follows that $0$ is a limit point of $S$.

To show that $S$ is dense in $[0, 1]$, consider $y \in[0,1]$, and $\epsilon>0$. Then by selecting $x \in S$ such that $\{x\}<\epsilon$ (which exists as $0$ is a limit point), and $N$ such that $N \cdot\{x\} \leq y<(N+1) \cdot\{x\}$, we get: $|y-\{N x\}|<\epsilon$.

QED
-/
theorem  irrational_orbit_dense {α : ℝ} (hα_irrat : irrational α) : closure ((λ m : ℤ, int.fract (α * ↑m)) '' (@set.univ ℤ)) = set.Icc 0 1 :=
FEW SHOT PROMPTS TO CODEX(END)-/


import category_theory.preadditive
import algebraic_topology.cech_nerve

import for_mathlib.simplicial.complex
import for_mathlib.arrow.split

namespace category_theory

universes v u v' u'

namespace arrow

noncomputable theory
open_locale simplicial
open category_theory.limits

variables {C : Type u} [category.{v} C] (f : arrow C)
variables [∀ n : ℕ, has_wide_pullback f.right (λ i : fin (n+1), f.left) (λ i, f.hom)]

/-- The splittings of the Cech nerve associated to a split arrow. -/
def cech_splitting [split f] (n : ℕ) : f.cech_nerve _[n] ⟶ f.cech_nerve _[n+1] :=
wide_pullback.lift (wide_pullback.base _)
(λ i, if h : i = 0 then wide_pullback.base _ ≫ split.σ else wide_pullback.π _ (i.pred h))
begin
  rintro ⟨j⟩,
  split_ifs,
  tidy,
end

lemma cech_splitting_face_zero [split f] (n : ℕ) :
  f.cech_splitting n ≫ f.cech_nerve.δ 0 = 𝟙 _ :=
begin
  ext j,
  dsimp [cech_splitting, simplicial_object.δ],
  simp only [category.id_comp, category.assoc, wide_pullback.lift_π],
  split_ifs,
  { exfalso,
    exact fin.succ_ne_zero _ h },
  { congr,
    dsimp [simplicial_object.δ, simplex_category.δ],
    simp },
  { dsimp [simplicial_object.δ, cech_splitting],
    simp },
end

lemma face_π (n : ℕ) (i : fin (n+1)) (j : fin (n+2)) :
  (f.cech_nerve.δ j : f.cech_nerve _[n+1] ⟶ _) ≫ wide_pullback.π _ i =
  wide_pullback.π _ (j.succ_above i) :=
begin
  change wide_pullback.lift _ _ _ ≫ _ = _,
  simpa,
end

lemma cech_splitting_face [split f] (n : ℕ) (j : fin (n+3)) (hj : j ≠ 0) :
  f.cech_splitting (n+1) ≫ f.cech_nerve.δ j =
  f.cech_nerve.δ (j.pred hj) ≫ f.cech_splitting n :=
begin
  ext k,
  swap,
  { dsimp [cech_splitting, simplicial_object.δ],
    simp },
  { dsimp [cech_splitting, simplicial_object.δ],
    simp only [category.assoc, limits.wide_pullback.lift_π],
    split_ifs with h1 h2,
    { simp },
    { refine false.elim (h2 _),
      change j.succ_above k = 0 at h1,
      change k = 0,
      rwa ← fin.succ_above_eq_zero_iff hj },
    { refine false.elim (h1 _),
      erw h,
      change j.succ_above 0 = 0,
      rw fin.succ_above_eq_zero_iff hj },
    { simp only [category_theory.limits.wide_pullback.lift_π],
      congr,
      change (j.succ_above k).pred h1 = (j.pred hj).succ_above (k.pred h),
      rw fin.pred_succ_above_pred,
      refl } }
end

end arrow

namespace arrow

section contracting_homotopy

open category_theory.limits opposite

-- Note: Universe restrictions! I hope this doesn't pose any issues later...
-- jmc: seems like it might! I removed them.
variables {P : Type u} {N : Type u'} [category.{v} P] [category.{v'} N] (M : Pᵒᵖ ⥤ N)
variables (f : arrow P)
variables [∀ n : ℕ, has_wide_pullback f.right (λ i : fin (n+1), f.left) (λ i, f.hom)]

/-- The augmented Cech conerve induced by applying M to `f.augmented_cech_nerve`. -/
abbreviation conerve : cosimplicial_object.augmented N :=
((cosimplicial_object.augmented.whiskering _ _).obj M).obj f.augmented_cech_nerve.right_op

variables [arrow.split f] [preadditive N]

/-- The morphisms yielding the contracting homotopy. -/
def contracting_homotopy : Π (n : ℕ),
  (f.conerve M).to_cocomplex.X (n+1) ⟶ (f.conerve M).to_cocomplex.X n
| 0 := M.map (wide_pullback.lift (𝟙 _)
         (λ i, (split.σ : f.right ⟶ _))
         (by simp)).op
| (n+1) := M.map (f.cech_splitting n).op

open cosimplicial_object.augmented
open_locale big_operators

lemma is_contracting_homotopy_zero :
  (f.conerve M).to_cocomplex.d 0 1 ≫ f.contracting_homotopy M 0 = 𝟙 _ :=
begin
  dsimp,
  rw if_pos,
  swap, { simp },
  delta conerve,
  dsimp [to_cocomplex_d, to_cocomplex_obj, contracting_homotopy ],
  simp only [category.id_comp, category.comp_id],
  simp_rw [← M.map_comp, ← op_comp, ← M.map_id, ← op_id],
  congr' 2,
  simp,
end

lemma is_contracting_homotopy_one :
  (f.conerve M).to_cocomplex.d 1 2 ≫ f.contracting_homotopy M 1 +
  f.contracting_homotopy M 0 ≫ (f.conerve M).to_cocomplex.d 0 1 = 𝟙 _ :=
begin
  rw ← add_zero (𝟙 ((conerve M f).to_cocomplex.X 1)),
  dsimp only [to_cocomplex, cochain_complex.of],
  rw dif_pos,
  swap, { dec_trivial },
  rw dif_pos,
  swap, { dec_trivial },
  dsimp,
  delta conerve,
  dsimp only [to_cocomplex_d, cosimplicial_object.coboundary, whiskering, whiskering_obj,
    drop, to_cocomplex_obj, comma.snd, cosimplicial_object.whiskering, whiskering_right,
    contracting_homotopy],
  simp_rw fin.sum_univ_succ,
  simp only [fin.coe_zero, fin.sum_univ_zero, fin.coe_one,
    one_zsmul, preadditive.add_comp, pow_one, fin.succ_zero_eq_one,
    category.id_comp, neg_smul, category.comp_id, preadditive.neg_comp, pow_zero ],
  rw [add_assoc],
  congr' 1,
  { dsimp [cosimplicial_object.δ],
    simp_rw [← M.map_comp, ← M.map_id, ← op_id, ← op_comp],
    congr' 2,
    dsimp [cech_splitting],
    ext j,
    { simp only [wide_pullback.lift_π, category.id_comp, category.assoc],
      split_ifs,
      { cases j,
        injection h with hh,
        simp only [nat.succ_ne_zero] at hh,
        cases hh },
      { congr, have hj : j = 0 := subsingleton.elim j 0, subst j,
        dsimp only [simplex_category.δ],
        simp only [simplex_category.mk_hom, simplex_category.hom.to_order_hom_mk,
          order_embedding.to_order_hom_coe, fin.zero_succ_above, fin.succ_zero_eq_one,
          fin.one_eq_zero_iff, nat.one_ne_zero],
        refl, } },
    { simp only [wide_pullback.lift_base, category.assoc, category.id_comp] } },
  { dsimp [cosimplicial_object.δ],
    rw [add_assoc, neg_add_eq_zero, ← M.map_comp],
    simp only [zero_comp, category.id_comp, zero_add, functor.map_comp, ← M.map_comp, ← op_comp],
    congr' 2,
    dsimp [cech_splitting],
    ext j,
    { simp only [wide_pullback.lift_π, category.assoc],
      split_ifs,
      { refl },
      { refine false.elim (h _),
        change (1 : fin 2).succ_above j = 0,
        rw fin.succ_above_eq_zero_iff,
        { simp },
        { exact top_ne_bot } } },
    { simp only [wide_pullback.lift_base, category.assoc, category.comp_id] } }
end

lemma is_contracting_homotopy (n : ℕ) :
  (f.conerve M).to_cocomplex.d (n+2) (n+3) ≫ f.contracting_homotopy M (n+2) +
  f.contracting_homotopy M (n+1) ≫ (f.conerve M).to_cocomplex.d (n+1) (n+2) = 𝟙 _ :=
begin
  dsimp,
  erw if_pos,
  swap, refl,
  dsimp only [to_cocomplex_d],
  rw if_pos,
  swap, refl,
  dsimp only [cosimplicial_object.coboundary],
  simp only [preadditive.sum_comp, preadditive.comp_sum],
  erw [fin.sum_univ_succ, add_assoc, ← finset.sum_add_distrib],
  rw ← add_zero (𝟙 ((conerve M f).to_cocomplex_obj (n + 2))),
  dsimp only [cosimplicial_object.δ],
  congr' 1,
  { delta conerve,
    dsimp [to_cocomplex_obj, contracting_homotopy],
    simp only [category_theory.category.comp_id, one_zsmul, pow_zero],
    simp_rw [← M.map_id, ← M.map_comp, ← op_comp, ← op_id],
    congr' 2,
    apply cech_splitting_face_zero },
  { apply fintype.sum_eq_zero,
    intros i,
    simp only [
      category.comp_id,
      add_zero,
      functor.comp_map,
      fin.coe_succ,
      preadditive.comp_zsmul,
      preadditive.zsmul_comp],
    suffices :
      (drop.obj (conerve M f)).map (simplex_category.δ i.succ) ≫ contracting_homotopy M f (n+2) =
          contracting_homotopy M f (n+1) ≫ (drop.obj (conerve M f)).map (simplex_category.δ i),
    { rw [this, pow_succ],
      simp },
    delta conerve,
    dsimp [contracting_homotopy],
    simp_rw [← M.map_comp, ← op_comp],
    congr' 2,
    convert cech_splitting_face _ _ _ (fin.succ_ne_zero _),
    funext,
    congr,
    simp }
end

end contracting_homotopy

section covariant_contracting_homotopy

open category_theory.limits opposite

variables {P : Type u} {N : Type u'} [category.{v} P] [category.{v'} N] (M : P ⥤ N)
variables (f : arrow P)
variables [∀ n : ℕ, has_wide_pullback f.right (λ i : fin (n+1), f.left) (λ i, f.hom)]

/-- The augmented Cech nerve induced by applying M to `f.augmented_cech_nerve`. -/
abbreviation nerve : simplicial_object.augmented N :=
((simplicial_object.augmented.whiskering _ _).obj M).obj f.augmented_cech_nerve

variables [arrow.split f] [preadditive N]

open simplicial_object.augmented
open_locale big_operators

def covariant_contracting_homotopy : Π (n : ℕ),
  (f.nerve M).to_complex.X n ⟶ (f.nerve M).to_complex.X (n+1)
| 0 := M.map $ wide_pullback.lift (𝟙 _) (λ i, (split.σ : f.right ⟶ _)) (by simpa)
| (n+1) := M.map $ f.cech_splitting n

lemma covariant_is_contracting_homotopy_zero :
  f.covariant_contracting_homotopy M 0 ≫ (f.nerve M).to_complex.d 1 0 = 𝟙 _ :=
begin
  dsimp,
  rw if_pos,
  swap, { simp },
  delta nerve,
  dsimp [to_complex_obj, to_complex_d, covariant_contracting_homotopy],
  simp only [category.id_comp, category.comp_id],
  simp_rw [← M.map_comp, ← M.map_id],
  congr' 2,
  simp,
end

lemma covariant_is_contracting_homotopy_one :
  f.covariant_contracting_homotopy M 1 ≫ (f.nerve M).to_complex.d 2 1 +
  (f.nerve M).to_complex.d 1 0 ≫ f.covariant_contracting_homotopy M 0 = 𝟙 _ :=
begin
  dsimp [covariant_contracting_homotopy],
  rw if_pos, rw if_pos, any_goals { dec_trivial },
  dsimp [to_complex_d, simplicial_object.boundary, simplicial_object.δ],
  delta nerve,
  dsimp [to_complex_obj],
  simp only [fin.sum_univ_succ, fin.coe_zero, pow_zero, one_zsmul, fintype.univ_of_subsingleton,
    nat.add_def, fin.mk_zero, fin.coe_succ, pow_one, neg_smul, finset.sum_singleton,
    preadditive.comp_add, category.id_comp, preadditive.comp_neg, category.comp_id],
  simp only [← M.map_comp],
  rw add_assoc,
  convert add_zero _,
  swap,
  { symmetry,
    convert M.map_id _,
    dsimp [arrow.cech_splitting],
    ext ⟨j,hj⟩, simp,
    rw dif_neg, refl,
    dsimp [simplex_category.δ],
    have : j = 0, by simpa using hj, subst this, dec_trivial,
    simp },
  { rw neg_add_eq_zero,
    congr' 1,
    dsimp [cech_splitting],
    ext ⟨j,hj⟩,
    { simp only [category.assoc, wide_pullback.lift_π], dsimp [simplex_category.δ],
      rw dif_pos, have : j = 0, by simpa using hj, subst this,
      dsimp [simplex_category.δ], dec_trivial },
    { simp } }
end

lemma covariant_is_contracting_homotopy (n : ℕ) :
  f.covariant_contracting_homotopy M (n+2) ≫ (f.nerve M).to_complex.d (n+3) (n+2) +
  (f.nerve M).to_complex.d (n+2) (n+1) ≫ f.covariant_contracting_homotopy M (n+1) = 𝟙 _ :=
begin
  dsimp, rw if_pos, rw if_pos, swap, { refl }, swap, { refl },
  simp only [category.comp_id, category.id_comp],
  dsimp only [to_complex_d, simplicial_object.boundary],
  simp only [preadditive.sum_comp, preadditive.comp_sum],
  rw [fin.sum_univ_succ, add_assoc, ← finset.sum_add_distrib],
  convert add_zero _,
  { apply fintype.sum_eq_zero, intros j,
    have : ((j.succ : fin _) : ℕ) = (j : ℕ) + 1 := by simp, rw this, clear this,
    rw [pow_succ],
    simp only [neg_mul, one_mul, neg_smul, preadditive.comp_neg],
    rw neg_add_eq_zero,
    simp only [preadditive.comp_zsmul, preadditive.zsmul_comp],
    congr' 1,
    dsimp [covariant_contracting_homotopy, simplicial_object.δ],
    delta nerve,
    dsimp [whiskering],
    simp only [← M.map_comp],
    congr' 1,
    convert cech_splitting_face _ _ _ (fin.succ_ne_zero _), funext i,
    congr, simp },
  { dsimp [covariant_contracting_homotopy],
    simp only [pow_zero, one_zsmul],
    delta nerve,
    dsimp [arrow.cech_splitting, simplicial_object.whiskering, simplicial_object.δ],
    rw ← M.map_comp, symmetry,
    convert M.map_id _,
    ext ⟨j,hj⟩,
    simp only [category.assoc, wide_pullback.lift_π],
    rw dif_neg, dsimp, simpa, dsimp [simplex_category.δ],
    intro c, apply_fun (λ e, e.1) at c, simpa using c,
    simp, dsimp, simp }
end

end covariant_contracting_homotopy

end arrow

end category_theory


/-
Copyright (c) 2017 Scott Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Stephen Morgan, Scott Morrison, Floris van Doorn
-/
import category_theory.functor.const
import category_theory.discrete_category
import category_theory.yoneda
import category_theory.functor.reflects_isomorphisms

-- morphism levels before object levels. See note [category_theory universes].
universes v₁ v₂ v₃ v₄ u₁ u₂ u₃ u₄
open category_theory

variables {J : Type u₁} [category.{v₁} J]
variables {K : Type u₂} [category.{v₂} K]
variables {C : Type u₃} [category.{v₃} C]
variables {D : Type u₄} [category.{v₄} D]

open category_theory
open category_theory.category
open category_theory.functor
open opposite

namespace category_theory

namespace functor
variables {J C} (F : J ⥤ C)

/--
`F.cones` is the functor assigning to an object `X` the type of
natural transformations from the constant functor with value `X` to `F`.
An object representing this functor is a limit of `F`.
-/
@[simps]
def cones : Cᵒᵖ ⥤ Type (max u₁ v₃) := (const J).op ⋙ yoneda.obj F

/--
`F.cocones` is the functor assigning to an object `X` the type of
natural transformations from `F` to the constant functor with value `X`.
An object corepresenting this functor is a colimit of `F`.
-/
@[simps]
def cocones : C ⥤ Type (max u₁ v₃) := const J ⋙ coyoneda.obj (op F)

end functor

section
variables (J C)

/--
Functorially associated to each functor `J ⥤ C`, we have the `C`-presheaf consisting of
cones with a given cone point.
-/
@[simps] def cones : (J ⥤ C) ⥤ (Cᵒᵖ ⥤ Type (max u₁ v₃)) :=
{ obj := functor.cones,
  map := λ F G f, whisker_left (const J).op (yoneda.map f) }

/--
Contravariantly associated to each functor `J ⥤ C`, we have the `C`-copresheaf consisting of
cocones with a given cocone point.
-/
@[simps] def cocones : (J ⥤ C)ᵒᵖ ⥤ (C ⥤ Type (max u₁ v₃)) :=
{ obj := λ F, functor.cocones (unop F),
  map := λ F G f, whisker_left (const J) (coyoneda.map f) }

end

namespace limits

/--
A `c : cone F` is:
* an object `c.X` and
* a natural transformation `c.π : c.X ⟶ F` from the constant `c.X` functor to `F`.

`cone F` is equivalent, via `cone.equiv` below, to `Σ X, F.cones.obj X`.
-/
structure cone (F : J ⥤ C) :=
(X : C)
(π : (const J).obj X ⟶ F)

instance inhabited_cone (F : discrete punit ⥤ C) : inhabited (cone F) :=
⟨{ X := F.obj punit.star,
   π := { app := λ ⟨⟩, 𝟙 _ } }⟩

@[simp, reassoc] lemma cone.w {F : J ⥤ C} (c : cone F) {j j' : J} (f : j ⟶ j') :
  c.π.app j ≫ F.map f = c.π.app j' :=
by { rw ← c.π.naturality f, apply id_comp }

/--
A `c : cocone F` is
* an object `c.X` and
* a natural transformation `c.ι : F ⟶ c.X` from `F` to the constant `c.X` functor.

`cocone F` is equivalent, via `cone.equiv` below, to `Σ X, F.cocones.obj X`.
-/
structure cocone (F : J ⥤ C) :=
(X : C)
(ι : F ⟶ (const J).obj X)

instance inhabited_cocone (F : discrete punit ⥤ C) : inhabited (cocone F) :=
⟨{ X := F.obj punit.star,
   ι := { app := λ ⟨⟩, 𝟙 _ } }⟩

@[simp, reassoc] lemma cocone.w {F : J ⥤ C} (c : cocone F) {j j' : J} (f : j ⟶ j') :
  F.map f ≫ c.ι.app j' = c.ι.app j :=
by { rw c.ι.naturality f, apply comp_id }

variables {F : J ⥤ C}

namespace cone

/-- The isomorphism between a cone on `F` and an element of the functor `F.cones`. -/
@[simps]
def equiv (F : J ⥤ C) : cone F ≅ Σ X, F.cones.obj X :=
{ hom := λ c, ⟨op c.X, c.π⟩,
  inv := λ c, { X := c.1.unop, π := c.2 },
  hom_inv_id' := by { ext1, cases x, refl },
  inv_hom_id' := by { ext1, cases x, refl } }

/-- A map to the vertex of a cone naturally induces a cone by composition. -/
@[simps] def extensions (c : cone F) :
  yoneda.obj c.X ⋙ ulift_functor.{u₁} ⟶ F.cones :=
{ app := λ X f, (const J).map f.down ≫ c.π }

/-- A map to the vertex of a cone induces a cone by composition. -/
@[simps] def extend (c : cone F) {X : C} (f : X ⟶ c.X) : cone F :=
{ X := X,
  π := c.extensions.app (op X) ⟨f⟩ }

/-- Whisker a cone by precomposition of a functor. -/
@[simps] def whisker (E : K ⥤ J) (c : cone F) : cone (E ⋙ F) :=
{ X := c.X,
  π := whisker_left E c.π }

end cone

namespace cocone

/-- The isomorphism between a cocone on `F` and an element of the functor `F.cocones`. -/
def equiv (F : J ⥤ C) : cocone F ≅ Σ X, F.cocones.obj X :=
{ hom := λ c, ⟨c.X, c.ι⟩,
  inv := λ c, { X := c.1, ι := c.2 },
  hom_inv_id' := by { ext1, cases x, refl },
  inv_hom_id' := by { ext1, cases x, refl } }

/-- A map from the vertex of a cocone naturally induces a cocone by composition. -/
@[simps] def extensions (c : cocone F) : coyoneda.obj (op c.X) ⋙ ulift_functor.{u₁} ⟶ F.cocones :=
{ app := λ X f, c.ι ≫ (const J).map f.down }

/-- A map from the vertex of a cocone induces a cocone by composition. -/
@[simps] def extend (c : cocone F) {X : C} (f : c.X ⟶ X) : cocone F :=
{ X := X,
  ι := c.extensions.app X ⟨f⟩ }

/--
Whisker a cocone by precomposition of a functor. See `whiskering` for a functorial
version.
-/
@[simps] def whisker (E : K ⥤ J) (c : cocone F) : cocone (E ⋙ F) :=
{ X := c.X,
  ι := whisker_left E c.ι }

end cocone

/-- A cone morphism between two cones for the same diagram is a morphism of the cone points which
commutes with the cone legs. -/
@[ext] structure cone_morphism (A B : cone F) :=
(hom : A.X ⟶ B.X)
(w'  : ∀ j : J, hom ≫ B.π.app j = A.π.app j . obviously)

restate_axiom cone_morphism.w'
attribute [simp, reassoc] cone_morphism.w

instance inhabited_cone_morphism (A : cone F) : inhabited (cone_morphism A A) :=
⟨{ hom := 𝟙 _ }⟩

/-- The category of cones on a given diagram. -/
@[simps] instance cone.category : category (cone F) :=
{ hom  := λ A B, cone_morphism A B,
  comp := λ X Y Z f g, { hom := f.hom ≫ g.hom },
  id   := λ B, { hom := 𝟙 B.X } }

namespace cones
/-- To give an isomorphism between cones, it suffices to give an
  isomorphism between their vertices which commutes with the cone
  maps. -/
@[ext, simps] def ext {c c' : cone F}
  (φ : c.X ≅ c'.X) (w : ∀ j, c.π.app j = φ.hom ≫ c'.π.app j) : c ≅ c' :=
{ hom := { hom := φ.hom },
  inv := { hom := φ.inv, w' := λ j, φ.inv_comp_eq.mpr (w j) } }

/--
Given a cone morphism whose object part is an isomorphism, produce an
isomorphism of cones.
-/
lemma cone_iso_of_hom_iso {K : J ⥤ C} {c d : cone K} (f : c ⟶ d) [i : is_iso f.hom] :
  is_iso f :=
⟨⟨{ hom := inv f.hom,
    w' := λ j, (as_iso f.hom).inv_comp_eq.2 (f.w j).symm }, by tidy⟩⟩

/--
Functorially postcompose a cone for `F` by a natural transformation `F ⟶ G` to give a cone for `G`.
-/
@[simps] def postcompose {G : J ⥤ C} (α : F ⟶ G) : cone F ⥤ cone G :=
{ obj := λ c, { X := c.X, π := c.π ≫ α },
  map := λ c₁ c₂ f, { hom := f.hom } }

/-- Postcomposing a cone by the composite natural transformation `α ≫ β` is the same as
postcomposing by `α` and then by `β`. -/
@[simps]
def postcompose_comp {G H : J ⥤ C} (α : F ⟶ G) (β : G ⟶ H) :
  postcompose (α ≫ β) ≅ postcompose α ⋙ postcompose β :=
nat_iso.of_components (λ s, cones.ext (iso.refl _) (by tidy)) (by tidy)

/-- Postcomposing by the identity does not change the cone up to isomorphism. -/
@[simps]
def postcompose_id : postcompose (𝟙 F) ≅ 𝟭 (cone F) :=
nat_iso.of_components (λ s, cones.ext (iso.refl _) (by tidy)) (by tidy)

/--
If `F` and `G` are naturally isomorphic functors, then they have equivalent categories of
cones.
-/
@[simps]
def postcompose_equivalence {G : J ⥤ C} (α : F ≅ G) : cone F ≌ cone G :=
{ functor := postcompose α.hom,
  inverse := postcompose α.inv,
  unit_iso := nat_iso.of_components (λ s, cones.ext (iso.refl _) (by tidy)) (by tidy),
  counit_iso := nat_iso.of_components (λ s, cones.ext (iso.refl _) (by tidy)) (by tidy) }

/--
Whiskering on the left by `E : K ⥤ J` gives a functor from `cone F` to `cone (E ⋙ F)`.
-/
@[simps]
def whiskering (E : K ⥤ J) : cone F ⥤ cone (E ⋙ F) :=
{ obj := λ c, c.whisker E,
  map := λ c c' f, { hom := f.hom } }

/--
Whiskering by an equivalence gives an equivalence between categories of cones.
-/
@[simps]
def whiskering_equivalence (e : K ≌ J) :
  cone F ≌ cone (e.functor ⋙ F) :=
{ functor := whiskering e.functor,
  inverse := whiskering e.inverse ⋙ postcompose (e.inv_fun_id_assoc F).hom,
  unit_iso := nat_iso.of_components (λ s, cones.ext (iso.refl _) (by tidy)) (by tidy),
  counit_iso := nat_iso.of_components (λ s, cones.ext (iso.refl _)
  (begin
    intro k,
    dsimp, -- See library note [dsimp, simp]
    simpa [e.counit_app_functor] using s.w (e.unit_inv.app k),
  end)) (by tidy), }

/--
The categories of cones over `F` and `G` are equivalent if `F` and `G` are naturally isomorphic
(possibly after changing the indexing category by an equivalence).
-/
@[simps functor inverse unit_iso counit_iso]
def equivalence_of_reindexing {G : K ⥤ C}
  (e : K ≌ J) (α : e.functor ⋙ F ≅ G) : cone F ≌ cone G :=
(whiskering_equivalence e).trans (postcompose_equivalence α)

section
variable (F)

/-- Forget the cone structure and obtain just the cone point. -/
@[simps]
def forget : cone F ⥤ C :=
{ obj := λ t, t.X, map := λ s t f, f.hom }

variables (G : C ⥤ D)

/-- A functor `G : C ⥤ D` sends cones over `F` to cones over `F ⋙ G` functorially. -/
@[simps] def functoriality : cone F ⥤ cone (F ⋙ G) :=
{ obj := λ A,
  { X := G.obj A.X,
    π := { app := λ j, G.map (A.π.app j), naturality' := by intros; erw ←G.map_comp; tidy } },
  map := λ X Y f,
  { hom := G.map f.hom,
    w' := λ j, by simp [-cone_morphism.w, ←f.w j] } }

instance functoriality_full [full G] [faithful G] : full (functoriality F G) :=
{ preimage := λ X Y t,
  { hom := G.preimage t.hom,
    w' := λ j, G.map_injective (by simpa using t.w j) } }

instance functoriality_faithful [faithful G] : faithful (cones.functoriality F G) :=
{ map_injective' := λ X Y f g e, by { ext1, injection e, apply G.map_injective h_1 } }

/--
If `e : C ≌ D` is an equivalence of categories, then `functoriality F e.functor` induces an
equivalence between cones over `F` and cones over `F ⋙ e.functor`.
-/
@[simps]
def functoriality_equivalence (e : C ≌ D) : cone F ≌ cone (F ⋙ e.functor) :=
let f : (F ⋙ e.functor) ⋙ e.inverse ≅ F :=
  functor.associator _ _ _ ≪≫ iso_whisker_left _ (e.unit_iso).symm ≪≫ functor.right_unitor _ in
{ functor := functoriality F e.functor,
  inverse := (functoriality (F ⋙ e.functor) e.inverse) ⋙
    (postcompose_equivalence f).functor,
  unit_iso := nat_iso.of_components (λ c, cones.ext (e.unit_iso.app _) (by tidy)) (by tidy),
  counit_iso := nat_iso.of_components (λ c, cones.ext (e.counit_iso.app _) (by tidy)) (by tidy), }

/--
If `F` reflects isomorphisms, then `cones.functoriality F` reflects isomorphisms
as well.
-/
instance reflects_cone_isomorphism (F : C ⥤ D) [reflects_isomorphisms F] (K : J ⥤ C) :
  reflects_isomorphisms (cones.functoriality K F) :=
begin
  constructor,
  introsI,
  haveI : is_iso (F.map f.hom) :=
    (cones.forget (K ⋙ F)).map_is_iso ((cones.functoriality K F).map f),
  haveI := reflects_isomorphisms.reflects F f.hom,
  apply cone_iso_of_hom_iso
end

end

end cones

/-- A cocone morphism between two cocones for the same diagram is a morphism of the cocone points
which commutes with the cocone legs. -/
@[ext] structure cocone_morphism (A B : cocone F) :=
(hom : A.X ⟶ B.X)
(w'  : ∀ j : J, A.ι.app j ≫ hom = B.ι.app j . obviously)

instance inhabited_cocone_morphism (A : cocone F) : inhabited (cocone_morphism A A) :=
⟨{ hom := 𝟙 _ }⟩

restate_axiom cocone_morphism.w'
attribute [simp, reassoc] cocone_morphism.w

@[simps] instance cocone.category : category (cocone F) :=
{ hom  := λ A B, cocone_morphism A B,
  comp := λ _ _ _ f g,
  { hom := f.hom ≫ g.hom },
  id   := λ B, { hom := 𝟙 B.X } }

namespace cocones
/-- To give an isomorphism between cocones, it suffices to give an
  isomorphism between their vertices which commutes with the cocone
  maps. -/
@[ext, simps] def ext {c c' : cocone F}
  (φ : c.X ≅ c'.X) (w : ∀ j, c.ι.app j ≫ φ.hom = c'.ι.app j) : c ≅ c' :=
{ hom := { hom := φ.hom },
  inv := { hom := φ.inv, w' := λ j, φ.comp_inv_eq.mpr (w j).symm } }

/--
Given a cocone morphism whose object part is an isomorphism, produce an
isomorphism of cocones.
-/
lemma cocone_iso_of_hom_iso {K : J ⥤ C} {c d : cocone K} (f : c ⟶ d) [i : is_iso f.hom] :
  is_iso f :=
⟨⟨{ hom := inv f.hom,
    w' := λ j, (as_iso f.hom).comp_inv_eq.2 (f.w j).symm }, by tidy⟩⟩

/-- Functorially precompose a cocone for `F` by a natural transformation `G ⟶ F` to give a cocone
for `G`. -/
@[simps] def precompose {G : J ⥤ C} (α : G ⟶ F) : cocone F ⥤ cocone G :=
{ obj := λ c, { X := c.X, ι := α ≫ c.ι },
  map := λ c₁ c₂ f, { hom := f.hom } }

/-- Precomposing a cocone by the composite natural transformation `α ≫ β` is the same as
precomposing by `β` and then by `α`. -/
def precompose_comp {G H : J ⥤ C} (α : F ⟶ G) (β : G ⟶ H) :
  precompose (α ≫ β) ≅ precompose β ⋙ precompose α :=
nat_iso.of_components (λ s, cocones.ext (iso.refl _) (by tidy)) (by tidy)

/-- Precomposing by the identity does not change the cocone up to isomorphism. -/
def precompose_id : precompose (𝟙 F) ≅ 𝟭 (cocone F) :=
nat_iso.of_components (λ s, cocones.ext (iso.refl _) (by tidy)) (by tidy)

/--
If `F` and `G` are naturally isomorphic functors, then they have equivalent categories of
cocones.
-/
@[simps]
def precompose_equivalence {G : J ⥤ C} (α : G ≅ F) : cocone F ≌ cocone G :=
{ functor := precompose α.hom,
  inverse := precompose α.inv,
  unit_iso := nat_iso.of_components (λ s, cocones.ext (iso.refl _) (by tidy)) (by tidy),
  counit_iso := nat_iso.of_components (λ s, cocones.ext (iso.refl _) (by tidy)) (by tidy) }

/--
Whiskering on the left by `E : K ⥤ J` gives a functor from `cocone F` to `cocone (E ⋙ F)`.
-/
@[simps]
def whiskering (E : K ⥤ J) : cocone F ⥤ cocone (E ⋙ F) :=
{ obj := λ c, c.whisker E,
  map := λ c c' f, { hom := f.hom, } }

/--
Whiskering by an equivalence gives an equivalence between categories of cones.
-/
@[simps]
def whiskering_equivalence (e : K ≌ J) :
  cocone F ≌ cocone (e.functor ⋙ F) :=
{ functor := whiskering e.functor,
  inverse := whiskering e.inverse ⋙
    precompose ((functor.left_unitor F).inv ≫ (whisker_right (e.counit_iso).inv F) ≫
      (functor.associator _ _ _).inv),
  unit_iso := nat_iso.of_components (λ s, cocones.ext (iso.refl _) (by tidy)) (by tidy),
  counit_iso := nat_iso.of_components (λ s, cocones.ext (iso.refl _)
  (begin
    intro k,
    dsimp,
    simpa [e.counit_inv_app_functor k] using s.w (e.unit.app k),
  end)) (by tidy), }

/--
The categories of cocones over `F` and `G` are equivalent if `F` and `G` are naturally isomorphic
(possibly after changing the indexing category by an equivalence).
-/
@[simps functor_obj]
def equivalence_of_reindexing {G : K ⥤ C}
  (e : K ≌ J) (α : e.functor ⋙ F ≅ G) : cocone F ≌ cocone G :=
(whiskering_equivalence e).trans (precompose_equivalence α.symm)

section
variable (F)

/-- Forget the cocone structure and obtain just the cocone point. -/
@[simps]
def forget : cocone F ⥤ C :=
{ obj := λ t, t.X, map := λ s t f, f.hom }

variables (G : C ⥤ D)

/-- A functor `G : C ⥤ D` sends cocones over `F` to cocones over `F ⋙ G` functorially. -/
@[simps] def functoriality : cocone F ⥤ cocone (F ⋙ G) :=
{ obj := λ A,
  { X := G.obj A.X,
    ι := { app := λ j, G.map (A.ι.app j), naturality' := by intros; erw ←G.map_comp; tidy } },
  map := λ _ _ f,
  { hom := G.map f.hom,
    w'  := by intros; rw [←functor.map_comp, cocone_morphism.w] } }

instance functoriality_full [full G] [faithful G] : full (functoriality F G) :=
{ preimage := λ X Y t,
  { hom := G.preimage t.hom,
    w' := λ j, G.map_injective (by simpa using t.w j) } }

instance functoriality_faithful [faithful G] : faithful (functoriality F G) :=
{ map_injective' := λ X Y f g e, by { ext1, injection e, apply G.map_injective h_1 } }

/--
If `e : C ≌ D` is an equivalence of categories, then `functoriality F e.functor` induces an
equivalence between cocones over `F` and cocones over `F ⋙ e.functor`.
-/
@[simps]
def functoriality_equivalence (e : C ≌ D) : cocone F ≌ cocone (F ⋙ e.functor) :=
let f : (F ⋙ e.functor) ⋙ e.inverse ≅ F :=
  functor.associator _ _ _ ≪≫ iso_whisker_left _ (e.unit_iso).symm ≪≫ functor.right_unitor _ in
{ functor := functoriality F e.functor,
  inverse := (functoriality (F ⋙ e.functor) e.inverse) ⋙
    (precompose_equivalence f.symm).functor,
  unit_iso := nat_iso.of_components (λ c, cocones.ext (e.unit_iso.app _) (by tidy)) (by tidy),
  counit_iso := nat_iso.of_components (λ c, cocones.ext (e.counit_iso.app _)
  begin
    -- Unfortunately this doesn't work by `tidy`.
    -- In this configuration `simp` reaches a dead-end and needs help.
    intros j,
    dsimp,
    simp only [←equivalence.counit_inv_app_functor, iso.inv_hom_id_app, map_comp,
      equivalence.fun_inv_map, assoc, id_comp, iso.inv_hom_id_app_assoc],
    dsimp, simp, -- See note [dsimp, simp].
  end)
  (λ c c' f, by { ext, dsimp, simp, dsimp, simp, }), }

/--
If `F` reflects isomorphisms, then `cocones.functoriality F` reflects isomorphisms
as well.
-/
instance reflects_cocone_isomorphism (F : C ⥤ D) [reflects_isomorphisms F] (K : J ⥤ C) :
  reflects_isomorphisms (cocones.functoriality K F) :=
begin
  constructor,
  introsI,
  haveI : is_iso (F.map f.hom) :=
    (cocones.forget (K ⋙ F)).map_is_iso ((cocones.functoriality K F).map f),
  haveI := reflects_isomorphisms.reflects F f.hom,
  apply cocone_iso_of_hom_iso
end

end
end cocones

end limits

namespace functor

variables {F : J ⥤ C} {G : J ⥤ C} (H : C ⥤ D)

open category_theory.limits

/-- The image of a cone in C under a functor G : C ⥤ D is a cone in D. -/
@[simps]
def map_cone   (c : cone F)   : cone (F ⋙ H)   := (cones.functoriality F H).obj c
/-- The image of a cocone in C under a functor G : C ⥤ D is a cocone in D. -/
@[simps]
def map_cocone (c : cocone F) : cocone (F ⋙ H) := (cocones.functoriality F H).obj c

/-- Given a cone morphism `c ⟶ c'`, construct a cone morphism on the mapped cones functorially.  -/
def map_cone_morphism   {c c' : cone F}   (f : c ⟶ c')   :
  H.map_cone c ⟶ H.map_cone c' := (cones.functoriality F H).map f

/-- Given a cocone morphism `c ⟶ c'`, construct a cocone morphism on the mapped cocones
functorially. -/
def map_cocone_morphism {c c' : cocone F} (f : c ⟶ c') :
  H.map_cocone c ⟶ H.map_cocone c' := (cocones.functoriality F H).map f

/-- If `H` is an equivalence, we invert `H.map_cone` and get a cone for `F` from a cone
for `F ⋙ H`.-/
def map_cone_inv [is_equivalence H]
  (c : cone (F ⋙ H)) : cone F :=
(limits.cones.functoriality_equivalence F (as_equivalence H)).inverse.obj c

/-- `map_cone` is the left inverse to `map_cone_inv`. -/
def map_cone_map_cone_inv {F : J ⥤ D} (H : D ⥤ C) [is_equivalence H] (c : cone (F ⋙ H)) :
  map_cone H (map_cone_inv H c) ≅ c :=
(limits.cones.functoriality_equivalence F (as_equivalence H)).counit_iso.app c

/-- `map_cone` is the right inverse to `map_cone_inv`. -/
def map_cone_inv_map_cone {F : J ⥤ D} (H : D ⥤ C) [is_equivalence H] (c : cone F) :
  map_cone_inv H (map_cone H c) ≅ c :=
(limits.cones.functoriality_equivalence F (as_equivalence H)).unit_iso.symm.app c
/-- If `H` is an equivalence, we invert `H.map_cone` and get a cone for `F` from a cone
for `F ⋙ H`.-/

def map_cocone_inv [is_equivalence H]
  (c : cocone (F ⋙ H)) : cocone F :=
(limits.cocones.functoriality_equivalence F (as_equivalence H)).inverse.obj c

/-- `map_cocone` is the left inverse to `map_cocone_inv`. -/
def map_cocone_map_cocone_inv {F : J ⥤ D} (H : D ⥤ C) [is_equivalence H] (c : cocone (F ⋙ H)) :
  map_cocone H (map_cocone_inv H c) ≅ c :=
(limits.cocones.functoriality_equivalence F (as_equivalence H)).counit_iso.app c

/-- `map_cocone` is the right inverse to `map_cocone_inv`. -/
def map_cocone_inv_map_cocone {F : J ⥤ D} (H : D ⥤ C) [is_equivalence H] (c : cocone F) :
  map_cocone_inv H (map_cocone H c) ≅ c :=
(limits.cocones.functoriality_equivalence F (as_equivalence H)).unit_iso.symm.app c

/-- `functoriality F _ ⋙ postcompose (whisker_left F _)` simplifies to `functoriality F _`. -/
@[simps]
def functoriality_comp_postcompose {H H' : C ⥤ D} (α : H ≅ H') :
  cones.functoriality F H ⋙ cones.postcompose (whisker_left F α.hom) ≅ cones.functoriality F H' :=
nat_iso.of_components (λ c, cones.ext (α.app _) (by tidy)) (by tidy)

/--
For `F : J ⥤ C`, given a cone `c : cone F`, and a natural isomorphism `α : H ≅ H'` for functors
`H H' : C ⥤ D`, the postcomposition of the cone `H.map_cone` using the isomorphism `α` is
isomorphic to the cone `H'.map_cone`.
-/
@[simps]
def postcompose_whisker_left_map_cone {H H' : C ⥤ D} (α : H ≅ H') (c : cone F) :
  (cones.postcompose (whisker_left F α.hom : _)).obj (H.map_cone c) ≅ H'.map_cone c :=
(functoriality_comp_postcompose α).app c

/--
`map_cone` commutes with `postcompose`. In particular, for `F : J ⥤ C`, given a cone `c : cone F`, a
natural transformation `α : F ⟶ G` and a functor `H : C ⥤ D`, we have two obvious ways of producing
a cone over `G ⋙ H`, and they are both isomorphic.
-/
@[simps]
def map_cone_postcompose {α : F ⟶ G} {c} :
  H.map_cone ((cones.postcompose α).obj c) ≅
  (cones.postcompose (whisker_right α H : _)).obj (H.map_cone c) :=
cones.ext (iso.refl _) (by tidy)

/--
`map_cone` commutes with `postcompose_equivalence`
-/
@[simps]
def map_cone_postcompose_equivalence_functor {α : F ≅ G} {c} :
  H.map_cone ((cones.postcompose_equivalence α).functor.obj c) ≅
    (cones.postcompose_equivalence (iso_whisker_right α H : _)).functor.obj (H.map_cone c) :=
cones.ext (iso.refl _) (by tidy)

/-- `functoriality F _ ⋙ precompose (whisker_left F _)` simplifies to `functoriality F _`. -/
@[simps]
def functoriality_comp_precompose {H H' : C ⥤ D} (α : H ≅ H') :
   cocones.functoriality F H ⋙ cocones.precompose (whisker_left F α.inv)
 ≅ cocones.functoriality F H' :=
nat_iso.of_components (λ c, cocones.ext (α.app _) (by tidy)) (by tidy)

/--
For `F : J ⥤ C`, given a cocone `c : cocone F`, and a natural isomorphism `α : H ≅ H'` for functors
`H H' : C ⥤ D`, the precomposition of the cocone `H.map_cocone` using the isomorphism `α` is
isomorphic to the cocone `H'.map_cocone`.
-/
@[simps]
def precompose_whisker_left_map_cocone {H H' : C ⥤ D} (α : H ≅ H') (c : cocone F) :
  (cocones.precompose (whisker_left F α.inv : _)).obj (H.map_cocone c) ≅ H'.map_cocone c :=
(functoriality_comp_precompose α).app c

/--
`map_cocone` commutes with `precompose`. In particular, for `F : J ⥤ C`, given a cocone
`c : cocone F`, a natural transformation `α : F ⟶ G` and a functor `H : C ⥤ D`, we have two obvious
ways of producing a cocone over `G ⋙ H`, and they are both isomorphic.
-/
@[simps]
def map_cocone_precompose {α : F ⟶ G} {c} :
  H.map_cocone ((cocones.precompose α).obj c) ≅
  (cocones.precompose (whisker_right α H : _)).obj (H.map_cocone c) :=
cocones.ext (iso.refl _) (by tidy)

/--
`map_cocone` commutes with `precompose_equivalence`
-/
@[simps]
def map_cocone_precompose_equivalence_functor {α : F ≅ G} {c} :
  H.map_cocone ((cocones.precompose_equivalence α).functor.obj c) ≅
    (cocones.precompose_equivalence (iso_whisker_right α H : _)).functor.obj (H.map_cocone c) :=
cocones.ext (iso.refl _) (by tidy)

/--
`map_cone` commutes with `whisker`
-/
@[simps]
def map_cone_whisker {E : K ⥤ J} {c : cone F} :
  H.map_cone (c.whisker E) ≅ (H.map_cone c).whisker E :=
cones.ext (iso.refl _) (by tidy)

/--
`map_cocone` commutes with `whisker`
-/
@[simps]
def map_cocone_whisker {E : K ⥤ J} {c : cocone F} :
  H.map_cocone (c.whisker E) ≅ (H.map_cocone c).whisker E :=
cocones.ext (iso.refl _) (by tidy)

end functor

end category_theory

namespace category_theory.limits

section
variables {F : J ⥤ C}

/-- Change a `cocone F` into a `cone F.op`. -/
@[simps] def cocone.op (c : cocone F) : cone F.op :=
{ X := op c.X,
  π := nat_trans.op c.ι }

/-- Change a `cone F` into a `cocone F.op`. -/
@[simps] def cone.op (c : cone F) : cocone F.op :=
{ X := op c.X,
  ι := nat_trans.op c.π }

/-- Change a `cocone F.op` into a `cone F`. -/
@[simps] def cocone.unop (c : cocone F.op) : cone F :=
{ X := unop c.X,
  π := nat_trans.remove_op c.ι }

/-- Change a `cone F.op` into a `cocone F`. -/
@[simps] def cone.unop (c : cone F.op) : cocone F :=
{ X := unop c.X,
  ι := nat_trans.remove_op c.π }

variables (F)

/--
The category of cocones on `F`
is equivalent to the opposite category of
the category of cones on the opposite of `F`.
-/
@[simps]
def cocone_equivalence_op_cone_op : cocone F ≌ (cone F.op)ᵒᵖ :=
{ functor :=
  { obj := λ c, op (cocone.op c),
    map := λ X Y f, quiver.hom.op
    { hom := f.hom.op,
      w' := λ j, by { apply quiver.hom.unop_inj, dsimp, simp, }, } },
  inverse :=
  { obj := λ c, cone.unop (unop c),
    map := λ X Y f,
    { hom := f.unop.hom.unop,
      w' := λ j, by { apply quiver.hom.op_inj, dsimp, simp, }, } },
  unit_iso := nat_iso.of_components (λ c, cocones.ext (iso.refl _) (by tidy)) (by tidy),
  counit_iso := nat_iso.of_components (λ c,
    by { induction c using opposite.rec,
         dsimp, apply iso.op, exact cones.ext (iso.refl _) (by tidy), })
    (λ X Y f, quiver.hom.unop_inj (cone_morphism.ext _ _ (by { dsimp, simp }))),
  functor_unit_iso_comp' := λ c, begin apply quiver.hom.unop_inj, ext, dsimp, simp, end }

end

section
variables {F : J ⥤ Cᵒᵖ}

/-- Change a cocone on `F.left_op : Jᵒᵖ ⥤ C` to a cocone on `F : J ⥤ Cᵒᵖ`. -/
-- Here and below we only automatically generate the `@[simp]` lemma for the `X` field,
-- as we can write a simpler `rfl` lemma for the components of the natural transformation by hand.
@[simps {rhs_md := semireducible, simp_rhs := tt}]
def cone_of_cocone_left_op (c : cocone F.left_op) : cone F :=
{ X := op c.X,
  π := nat_trans.remove_left_op c.ι }

/-- Change a cone on `F : J ⥤ Cᵒᵖ` to a cocone on `F.left_op : Jᵒᵖ ⥤ C`. -/
@[simps {rhs_md := semireducible, simp_rhs := tt}]
def cocone_left_op_of_cone (c : cone F) : cocone (F.left_op) :=
{ X := unop c.X,
  ι := nat_trans.left_op c.π }

/-- Change a cone on `F.left_op : Jᵒᵖ ⥤ C` to a cocone on `F : J ⥤ Cᵒᵖ`. -/
/- When trying use `@[simps]` to generate the `ι_app` field of this definition, `@[simps]` tries to
  reduce the RHS using `expr.dsimp` and `expr.simp`, but for some reason the expression is not
  being simplified properly. -/
@[simps X]
def cocone_of_cone_left_op (c : cone F.left_op) : cocone F :=
{ X := op c.X,
  ι := nat_trans.remove_left_op c.π }

@[simp] lemma cocone_of_cone_left_op_ι_app (c : cone F.left_op) (j) :
  (cocone_of_cone_left_op c).ι.app j = (c.π.app (op j)).op :=
by { dsimp only [cocone_of_cone_left_op], simp }

/-- Change a cocone on `F : J ⥤ Cᵒᵖ` to a cone on `F.left_op : Jᵒᵖ ⥤ C`. -/
@[simps {rhs_md := semireducible, simp_rhs := tt}]
def cone_left_op_of_cocone (c : cocone F) : cone (F.left_op) :=
{ X := unop c.X,
  π := nat_trans.left_op c.ι }

end

section
variables {F : Jᵒᵖ ⥤ C}

/-- Change a cocone on `F.right_op : J ⥤ Cᵒᵖ` to a cone on `F : Jᵒᵖ ⥤ C`. -/
@[simps] def cone_of_cocone_right_op (c : cocone F.right_op) : cone F :=
{ X := unop c.X,
  π := nat_trans.remove_right_op c.ι }

/-- Change a cone on `F : Jᵒᵖ ⥤ C` to a cocone on `F.right_op : Jᵒᵖ ⥤ C`. -/
@[simps] def cocone_right_op_of_cone (c : cone F) : cocone (F.right_op) :=
{ X := op c.X,
  ι := nat_trans.right_op c.π }

/-- Change a cone on `F.right_op : J ⥤ Cᵒᵖ` to a cocone on `F : Jᵒᵖ ⥤ C`. -/
@[simps] def cocone_of_cone_right_op (c : cone F.right_op) : cocone F :=
{ X := unop c.X,
  ι := nat_trans.remove_right_op c.π }

/-- Change a cocone on `F : Jᵒᵖ ⥤ C` to a cone on `F.right_op : J ⥤ Cᵒᵖ`. -/
@[simps] def cone_right_op_of_cocone (c : cocone F) : cone (F.right_op) :=
{ X := op c.X,
  π := nat_trans.right_op c.ι }

end

section
variables {F : Jᵒᵖ ⥤ Cᵒᵖ}

/-- Change a cocone on `F.unop : J ⥤ C` into a cone on `F : Jᵒᵖ ⥤ Cᵒᵖ`. -/
@[simps] def cone_of_cocone_unop (c : cocone F.unop) : cone F :=
{ X := op c.X,
  π := nat_trans.remove_unop c.ι }

/-- Change a cone on `F : Jᵒᵖ ⥤ Cᵒᵖ` into a cocone on `F.unop : J ⥤ C`. -/
@[simps] def cocone_unop_of_cone (c : cone F) : cocone F.unop :=
{ X := unop c.X,
  ι := nat_trans.unop c.π }

/-- Change a cone on `F.unop : J ⥤ C` into a cocone on `F : Jᵒᵖ ⥤ Cᵒᵖ`. -/
@[simps] def cocone_of_cone_unop (c : cone F.unop) : cocone F :=
{ X := op c.X,
  ι := nat_trans.remove_unop c.π }

/-- Change a cocone on `F : Jᵒᵖ ⥤ Cᵒᵖ` into a cone on `F.unop : J ⥤ C`. -/
@[simps] def cone_unop_of_cocone (c : cocone F) : cone F.unop :=
{ X := unop c.X,
  π := nat_trans.unop c.ι }

end

end category_theory.limits

namespace category_theory.functor

open category_theory.limits

variables {F : J ⥤ C}

section
variables (G : C ⥤ D)

/-- The opposite cocone of the image of a cone is the image of the opposite cocone. -/
@[simps {rhs_md := semireducible}]
def map_cone_op (t : cone F) : (G.map_cone t).op ≅ (G.op.map_cocone t.op) :=
cocones.ext (iso.refl _) (by tidy)

/-- The opposite cone of the image of a cocone is the image of the opposite cone. -/
@[simps {rhs_md := semireducible}]
def map_cocone_op {t : cocone F} : (G.map_cocone t).op ≅ (G.op.map_cone t.op) :=
cones.ext (iso.refl _) (by tidy)

end

end category_theory.functor