l3lab/ntp-mathlib huggingface dataset:
/-- The inverse limit of nonempty finite types is nonempty.

See `nonempty_sections_of_finite_cofiltered_system` for a generalization to cofiltered limits.
That version applies in almost all cases, and the only difference is that this version
allows `J` to be empty.

This may be regarded as a generalization of Kőnig's lemma.
To specialize: given a locally finite connected graph, take `Jᵒᵖ` to be `ℕ` and
`F j` to be length-`j` paths that start from an arbitrary fixed vertex.
Elements of `F.sections` can be read off as infinite rays in the graph. -/
theorem nonempty_sections_of_finite_inverse_system {J : Type u} [Preorder J] [IsDirected J (· ≤ ·)]
    (F : Jᵒᵖ ⥤ Type v) [∀ j : Jᵒᵖ, Finite (F.obj j)] [∀ j : Jᵒᵖ, Nonempty (F.obj j)] :
    F.sections.Nonempty := by
  cases isEmpty_or_nonempty J
  · 

Proof state:
case inl
J : Type u
inst✝³ : Preorder J
inst✝² : IsDirected J fun x x_1 => x ≤ x_1
F : Jᵒᵖ ⥤ Type v
inst✝¹ : ∀ (j : Jᵒᵖ), Finite (F.obj j)
inst✝ : ∀ (j : Jᵒᵖ), Nonempty (F.obj j)
h✝ : IsEmpty J
⊢ Set.Nonempty (Functor.sections F)

Next tactic:
haveI : IsEmpty Jᵒᵖ := ⟨fun j => isEmptyElim j.unop⟩
/-- The inverse limit of nonempty finite types is nonempty.

See `nonempty_sections_of_finite_cofiltered_system` for a generalization to cofiltered limits.
That version applies in almost all cases, and the only difference is that this version
allows `J` to be empty.

This may be regarded as a generalization of Kőnig's lemma.
To specialize: given a locally finite connected graph, take `Jᵒᵖ` to be `ℕ` and
`F j` to be length-`j` paths that start from an arbitrary fixed vertex.
Elements of `F.sections` can be read off as infinite rays in the graph. -/
theorem nonempty_sections_of_finite_inverse_system {J : Type u} [Preorder J] [IsDirected J (· ≤ ·)]
    (F : Jᵒᵖ ⥤ Type v) [∀ j : Jᵒᵖ, Finite (F.obj j)] [∀ j : Jᵒᵖ, Nonempty (F.obj j)] :
    F.sections.Nonempty := by
  cases isEmpty_or_nonempty J
  · haveI : IsEmpty Jᵒᵖ := ⟨fun j => isEmptyElim j.unop⟩ -- TODO: this should be a global instance
    

Proof state:
case inl
J : Type u
inst✝³ : Preorder J
inst✝² : IsDirected J fun x x_1 => x ≤ x_1
F : Jᵒᵖ ⥤ Type v
inst✝¹ : ∀ (j : Jᵒᵖ), Finite (F.obj j)
inst✝ : ∀ (j : Jᵒᵖ), Nonempty (F.obj j)
h✝ : IsEmpty J
this : IsEmpty Jᵒᵖ
⊢ Set.Nonempty (Functor.sections F)

Next tactic:
exact ⟨isEmptyElim, by apply isEmptyElim⟩
/-- The inverse limit of nonempty finite types is nonempty.

See `nonempty_sections_of_finite_cofiltered_system` for a generalization to cofiltered limits.
That version applies in almost all cases, and the only difference is that this version
allows `J` to be empty.

This may be regarded as a generalization of Kőnig's lemma.
To specialize: given a locally finite connected graph, take `Jᵒᵖ` to be `ℕ` and
`F j` to be length-`j` paths that start from an arbitrary fixed vertex.
Elements of `F.sections` can be read off as infinite rays in the graph. -/
theorem nonempty_sections_of_finite_inverse_system {J : Type u} [Preorder J] [IsDirected J (· ≤ ·)]
    (F : Jᵒᵖ ⥤ Type v) [∀ j : Jᵒᵖ, Finite (F.obj j)] [∀ j : Jᵒᵖ, Nonempty (F.obj j)] :
    F.sections.Nonempty := by
  cases isEmpty_or_nonempty J
  · haveI : IsEmpty Jᵒᵖ := ⟨fun j => isEmptyElim j.unop⟩ -- TODO: this should be a global instance
    exact ⟨isEmptyElim, by 

Proof state:
J : Type u
inst✝³ : Preorder J
inst✝² : IsDirected J fun x x_1 => x ≤ x_1
F : Jᵒᵖ ⥤ Type v
inst✝¹ : ∀ (j : Jᵒᵖ), Finite (F.obj j)
inst✝ : ∀ (j : Jᵒᵖ), Nonempty (F.obj j)
h✝ : IsEmpty J
this : IsEmpty Jᵒᵖ
⊢ (fun a => isEmptyElim a) ∈ Functor.sections F

Next tactic:
apply isEmptyElim
/-- The inverse limit of nonempty finite types is nonempty.

See `nonempty_sections_of_finite_cofiltered_system` for a generalization to cofiltered limits.
That version applies in almost all cases, and the only difference is that this version
allows `J` to be empty.

This may be regarded as a generalization of Kőnig's lemma.
To specialize: given a locally finite connected graph, take `Jᵒᵖ` to be `ℕ` and
`F j` to be length-`j` paths that start from an arbitrary fixed vertex.
Elements of `F.sections` can be read off as infinite rays in the graph. -/
theorem nonempty_sections_of_finite_inverse_system {J : Type u} [Preorder J] [IsDirected J (· ≤ ·)]
    (F : Jᵒᵖ ⥤ Type v) [∀ j : Jᵒᵖ, Finite (F.obj j)] [∀ j : Jᵒᵖ, Nonempty (F.obj j)] :
    F.sections.Nonempty := by
  cases isEmpty_or_nonempty J
  · haveI : IsEmpty Jᵒᵖ := ⟨fun j => isEmptyElim j.unop⟩ -- TODO: this should be a global instance
    exact ⟨isEmptyElim, by apply isEmptyElim⟩
  · 

Proof state:
case inr
J : Type u
inst✝³ : Preorder J
inst✝² : IsDirected J fun x x_1 => x ≤ x_1
F : Jᵒᵖ ⥤ Type v
inst✝¹ : ∀ (j : Jᵒᵖ), Finite (F.obj j)
inst✝ : ∀ (j : Jᵒᵖ), Nonempty (F.obj j)
h✝ : Nonempty J
⊢ Set.Nonempty (Functor.sections F)

Next tactic:
exact nonempty_sections_of_finite_cofiltered_system _
theorem IsMittagLeffler.subset_image_eventualRange (h : F.IsMittagLeffler) (f : j ⟶ i) :
    F.eventualRange i ⊆ F.map f '' F.eventualRange j := by
  

Proof state:
J : Type u
inst✝ : Category.{u_1, u} J
F : J ⥤ Type v
i j k : J
s : Set (F.obj i)
h : IsMittagLeffler F
f : j ⟶ i
⊢ eventualRange F i ⊆ F.map f '' eventualRange F j

Next tactic:
obtain ⟨k, g, hg⟩ := F.isMittagLeffler_iff_eventualRange.1 h j
theorem IsMittagLeffler.subset_image_eventualRange (h : F.IsMittagLeffler) (f : j ⟶ i) :
    F.eventualRange i ⊆ F.map f '' F.eventualRange j := by
  obtain ⟨k, g, hg⟩ := F.isMittagLeffler_iff_eventualRange.1 h j
  

Proof state:
case intro.intro
J : Type u
inst✝ : Category.{u_1, u} J
F : J ⥤ Type v
i j k✝ : J
s : Set (F.obj i)
h : IsMittagLeffler F
f : j ⟶ i
k : J
g : k ⟶ j
hg : eventualRange F j = range (F.map g)
⊢ eventualRange F i ⊆ F.map f '' eventualRange F j

Next tactic:
rw [hg]
theorem IsMittagLeffler.subset_image_eventualRange (h : F.IsMittagLeffler) (f : j ⟶ i) :
    F.eventualRange i ⊆ F.map f '' F.eventualRange j := by
  obtain ⟨k, g, hg⟩ := F.isMittagLeffler_iff_eventualRange.1 h j
  rw [hg]; 

Proof state:
case intro.intro
J : Type u
inst✝ : Category.{u_1, u} J
F : J ⥤ Type v
i j k✝ : J
s : Set (F.obj i)
h : IsMittagLeffler F
f : j ⟶ i
k : J
g : k ⟶ j
hg : eventualRange F j = range (F.map g)
⊢ eventualRange F i ⊆ F.map f '' range (F.map g)

Next tactic:
intro x hx
theorem IsMittagLeffler.subset_image_eventualRange (h : F.IsMittagLeffler) (f : j ⟶ i) :
    F.eventualRange i ⊆ F.map f '' F.eventualRange j := by
  obtain ⟨k, g, hg⟩ := F.isMittagLeffler_iff_eventualRange.1 h j
  rw [hg]; intro x hx
  

Proof state:
case intro.intro
J : Type u
inst✝ : Category.{u_1, u} J
F : J ⥤ Type v
i j k✝ : J
s : Set (F.obj i)
h : IsMittagLeffler F
f : j ⟶ i
k : J
g : k ⟶ j
hg : eventualRange F j = range (F.map g)
x : F.obj i
hx : x ∈ eventualRange F i
⊢ x ∈ F.map f '' range (F.map g)

Next tactic:
obtain ⟨x, rfl⟩ := F.mem_eventualRange_iff.1 hx (g ≫ f)
theorem IsMittagLeffler.subset_image_eventualRange (h : F.IsMittagLeffler) (f : j ⟶ i) :
    F.eventualRange i ⊆ F.map f '' F.eventualRange j := by
  obtain ⟨k, g, hg⟩ := F.isMittagLeffler_iff_eventualRange.1 h j
  rw [hg]; intro x hx
  obtain ⟨x, rfl⟩ := F.mem_eventualRange_iff.1 hx (g ≫ f)
  

Proof state:
case intro.intro.intro
J : Type u
inst✝ : Category.{u_1, u} J
F : J ⥤ Type v
i j k✝ : J
s : Set (F.obj i)
h : IsMittagLeffler F
f : j ⟶ i
k : J
g : k ⟶ j
hg : eventualRange F j = range (F.map g)
x : F.obj k
hx : F.map (g ≫ f) x ∈ eventualRange F i
⊢ F.map (g ≫ f) x ∈ F.map f '' range (F.map g)

Next tactic:
refine' ⟨_, ⟨x, rfl⟩, by rw [map_comp_apply] ⟩
theorem IsMittagLeffler.subset_image_eventualRange (h : F.IsMittagLeffler) (f : j ⟶ i) :
    F.eventualRange i ⊆ F.map f '' F.eventualRange j := by
  obtain ⟨k, g, hg⟩ := F.isMittagLeffler_iff_eventualRange.1 h j
  rw [hg]; intro x hx
  obtain ⟨x, rfl⟩ := F.mem_eventualRange_iff.1 hx (g ≫ f)
  refine' ⟨_, ⟨x, rfl⟩, by 

Proof state:
J : Type u
inst✝ : Category.{u_1, u} J
F : J ⥤ Type v
i j k✝ : J
s : Set (F.obj i)
h : IsMittagLeffler F
f : j ⟶ i
k : J
g : k ⟶ j
hg : eventualRange F j = range (F.map g)
x : F.obj k
hx : F.map (g ≫ f) x ∈ eventualRange F i
⊢ F.map f (F.map g x) = F.map (g ≫ f) x

Next tactic:
rw [map_comp_apply]
theorem eventualRange_eq_range_precomp (f : i ⟶ j) (g : j ⟶ k)
    (h : F.eventualRange k = range (F.map g)) : F.eventualRange k = range (F.map <| f ≫ g) := by
  

Proof state:
J : Type u
inst✝ : Category.{u_1, u} J
F : J ⥤ Type v
i j k : J
s : Set (F.obj i)
f : i ⟶ j
g : j ⟶ k
h : eventualRange F k = range (F.map g)
⊢ eventualRange F k = range (F.map (f ≫ g))

Next tactic:
apply subset_antisymm
theorem eventualRange_eq_range_precomp (f : i ⟶ j) (g : j ⟶ k)
    (h : F.eventualRange k = range (F.map g)) : F.eventualRange k = range (F.map <| f ≫ g) := by
  apply subset_antisymm
  · 

Proof state:
case a
J : Type u
inst✝ : Category.{u_1, u} J
F : J ⥤ Type v
i j k : J
s : Set (F.obj i)
f : i ⟶ j
g : j ⟶ k
h : eventualRange F k = range (F.map g)
⊢ eventualRange F k ⊆ range (F.map (f ≫ g))

Next tactic:
apply iInter₂_subset
theorem eventualRange_eq_range_precomp (f : i ⟶ j) (g : j ⟶ k)
    (h : F.eventualRange k = range (F.map g)) : F.eventualRange k = range (F.map <| f ≫ g) := by
  apply subset_antisymm
  · apply iInter₂_subset
  · 

Proof state:
case a
J : Type u
inst✝ : Category.{u_1, u} J
F : J ⥤ Type v
i j k : J
s : Set (F.obj i)
f : i ⟶ j
g : j ⟶ k
h : eventualRange F k = range (F.map g)
⊢ range (F.map (f ≫ g)) ⊆ eventualRange F k

Next tactic:
rw [h, F.map_comp]
theorem eventualRange_eq_range_precomp (f : i ⟶ j) (g : j ⟶ k)
    (h : F.eventualRange k = range (F.map g)) : F.eventualRange k = range (F.map <| f ≫ g) := by
  apply subset_antisymm
  · apply iInter₂_subset
  · rw [h, F.map_comp]
    

Proof state:
case a
J : Type u
inst✝ : Category.{u_1, u} J
F : J ⥤ Type v
i j k : J
s : Set (F.obj i)
f : i ⟶ j
g : j ⟶ k
h : eventualRange F k = range (F.map g)
⊢ range (F.map f ≫ F.map g) ⊆ range (F.map g)

Next tactic:
apply range_comp_subset_range
theorem isMittagLeffler_of_surjective (h : ∀ ⦃i j : J⦄ (f : i ⟶ j), (F.map f).Surjective) :
    F.IsMittagLeffler :=
  fun j => ⟨j, 𝟙 j, fun k g => by 

Proof state:
J : Type u
inst✝ : Category.{u_1, u} J
F : J ⥤ Type v
i j✝ k✝ : J
s : Set (F.obj i)
h : ∀ ⦃i j : J⦄ (f : i ⟶ j), Function.Surjective (F.map f)
j k : J
g : k ⟶ j
⊢ range (F.map (𝟙 j)) ⊆ range (F.map g)

Next tactic:
rw [map_id, types_id, range_id, (h g).range_eq]
/-- The subfunctor of `F` obtained by restricting to the preimages of a set `s ∈ F.obj i`. -/
@[simps]
def toPreimages : J ⥤ Type v where
  obj j := ⋂ f : j ⟶ i, F.map f ⁻¹' s
  map g := MapsTo.restrict (F.map g) _ _ fun x h => by
    

Proof state:
J : Type u
inst✝ : Category.{?u.10420, u} J
F : J ⥤ Type v
i j k : J
s : Set (F.obj i)
X✝ Y✝ : J
g : X✝ ⟶ Y✝
x : F.obj X✝
h : x ∈ ⋂ f, F.map f ⁻¹' s
⊢ F.map g x ∈ ⋂ f, F.map f ⁻¹' s

Next tactic:
rw [mem_iInter] at h ⊢
/-- The subfunctor of `F` obtained by restricting to the preimages of a set `s ∈ F.obj i`. -/
@[simps]
def toPreimages : J ⥤ Type v where
  obj j := ⋂ f : j ⟶ i, F.map f ⁻¹' s
  map g := MapsTo.restrict (F.map g) _ _ fun x h => by
    rw [mem_iInter] at h ⊢
    

Proof state:
J : Type u
inst✝ : Category.{?u.10420, u} J
F : J ⥤ Type v
i j k : J
s : Set (F.obj i)
X✝ Y✝ : J
g : X✝ ⟶ Y✝
x : F.obj X✝
h : ∀ (i_1 : X✝ ⟶ i), x ∈ F.map i_1 ⁻¹' s
⊢ ∀ (i_1 : Y✝ ⟶ i), F.map g x ∈ F.map i_1 ⁻¹' s

Next tactic:
intro f
/-- The subfunctor of `F` obtained by restricting to the preimages of a set `s ∈ F.obj i`. -/
@[simps]
def toPreimages : J ⥤ Type v where
  obj j := ⋂ f : j ⟶ i, F.map f ⁻¹' s
  map g := MapsTo.restrict (F.map g) _ _ fun x h => by
    rw [mem_iInter] at h ⊢
    intro f
    

Proof state:
J : Type u
inst✝ : Category.{?u.10420, u} J
F : J ⥤ Type v
i j k : J
s : Set (F.obj i)
X✝ Y✝ : J
g : X✝ ⟶ Y✝
x : F.obj X✝
h : ∀ (i_1 : X✝ ⟶ i), x ∈ F.map i_1 ⁻¹' s
f : Y✝ ⟶ i
⊢ F.map g x ∈ F.map f ⁻¹' s

Next tactic:
rw [← mem_preimage, preimage_preimage, mem_preimage]
/-- The subfunctor of `F` obtained by restricting to the preimages of a set `s ∈ F.obj i`. -/
@[simps]
def toPreimages : J ⥤ Type v where
  obj j := ⋂ f : j ⟶ i, F.map f ⁻¹' s
  map g := MapsTo.restrict (F.map g) _ _ fun x h => by
    rw [mem_iInter] at h ⊢
    intro f
    rw [← mem_preimage, preimage_preimage, mem_preimage]
    

Proof state:
J : Type u
inst✝ : Category.{?u.10420, u} J
F : J ⥤ Type v
i j k : J
s : Set (F.obj i)
X✝ Y✝ : J
g : X✝ ⟶ Y✝
x : F.obj X✝
h : ∀ (i_1 : X✝ ⟶ i), x ∈ F.map i_1 ⁻¹' s
f : Y✝ ⟶ i
⊢ F.map f (F.map g x) ∈ s

Next tactic:
convert h (g ≫ f)
/-- The subfunctor of `F` obtained by restricting to the preimages of a set `s ∈ F.obj i`. -/
@[simps]
def toPreimages : J ⥤ Type v where
  obj j := ⋂ f : j ⟶ i, F.map f ⁻¹' s
  map g := MapsTo.restrict (F.map g) _ _ fun x h => by
    rw [mem_iInter] at h ⊢
    intro f
    rw [← mem_preimage, preimage_preimage, mem_preimage]
    convert h (g ≫ f); 

Proof state:
case a
J : Type u
inst✝ : Category.{?u.10420, u} J
F : J ⥤ Type v
i j k : J
s : Set (F.obj i)
X✝ Y✝ : J
g : X✝ ⟶ Y✝
x : F.obj X✝
h : ∀ (i_1 : X✝ ⟶ i), x ∈ F.map i_1 ⁻¹' s
f : Y✝ ⟶ i
⊢ F.map f (F.map g x) ∈ s ↔ x ∈ F.map (g ≫ f) ⁻¹' s

Next tactic:
rw [F.map_comp]
/-- The subfunctor of `F` obtained by restricting to the preimages of a set `s ∈ F.obj i`. -/
@[simps]
def toPreimages : J ⥤ Type v where
  obj j := ⋂ f : j ⟶ i, F.map f ⁻¹' s
  map g := MapsTo.restrict (F.map g) _ _ fun x h => by
    rw [mem_iInter] at h ⊢
    intro f
    rw [← mem_preimage, preimage_preimage, mem_preimage]
    convert h (g ≫ f); rw [F.map_comp]; 

Proof state:
case a
J : Type u
inst✝ : Category.{?u.10420, u} J
F : J ⥤ Type v
i j k : J
s : Set (F.obj i)
X✝ Y✝ : J
g : X✝ ⟶ Y✝
x : F.obj X✝
h : ∀ (i_1 : X✝ ⟶ i), x ∈ F.map i_1 ⁻¹' s
f : Y✝ ⟶ i
⊢ F.map f (F.map g x) ∈ s ↔ x ∈ (F.map g ≫ F.map f) ⁻¹' s

Next tactic:
rfl
/-- The subfunctor of `F` obtained by restricting to the preimages of a set `s ∈ F.obj i`. -/
@[simps]
def toPreimages : J ⥤ Type v where
  obj j := ⋂ f : j ⟶ i, F.map f ⁻¹' s
  map g := MapsTo.restrict (F.map g) _ _ fun x h => by
    rw [mem_iInter] at h ⊢
    intro f
    rw [← mem_preimage, preimage_preimage, mem_preimage]
    convert h (g ≫ f); rw [F.map_comp]; rfl
  map_id j := by
    

Proof state:
J : Type u
inst✝ : Category.{?u.10420, u} J
F : J ⥤ Type v
i j✝ k : J
s : Set (F.obj i)
j : J
⊢ { obj := fun j => ↑(⋂ f, F.map f ⁻¹' s),
          map := fun {X Y} g =>
            MapsTo.restrict (F.map g) (⋂ f, F.map f ⁻¹' s) (⋂ f, F.map f ⁻¹' s)
              (_ : ∀ x ∈ ⋂ f, F.map f ⁻¹' s, F.map g x ∈ ⋂ f, F.map f ⁻¹' s) }.map
      (𝟙 j) =
    𝟙
      ({ obj := fun j => ↑(⋂ f, F.map f ⁻¹' s),
            map := fun {X Y} g =>
              MapsTo.restrict (F.map g) (⋂ f, F.map f ⁻¹' s) (⋂ f, F.map f ⁻¹' s)
                (_ : ∀ x ∈ ⋂ f, F.map f ⁻¹' s, F.map g x ∈ ⋂ f, F.map f ⁻¹' s) }.obj
        j)

Next tactic:
simp (config := { unfoldPartialApp := true }) only [MapsTo.restrict, Subtype.map, F.map_id]
/-- The subfunctor of `F` obtained by restricting to the preimages of a set `s ∈ F.obj i`. -/
@[simps]
def toPreimages : J ⥤ Type v where
  obj j := ⋂ f : j ⟶ i, F.map f ⁻¹' s
  map g := MapsTo.restrict (F.map g) _ _ fun x h => by
    rw [mem_iInter] at h ⊢
    intro f
    rw [← mem_preimage, preimage_preimage, mem_preimage]
    convert h (g ≫ f); rw [F.map_comp]; rfl
  map_id j := by
    simp (config := { unfoldPartialApp := true }) only [MapsTo.restrict, Subtype.map, F.map_id]
    

Proof state:
J : Type u
inst✝ : Category.{?u.10420, u} J
F : J ⥤ Type v
i j✝ k : J
s : Set (F.obj i)
j : J
⊢ (fun x => { val := 𝟙 (F.obj j) ↑x, property := (_ : (fun x => x ∈ ⋂ f, F.map f ⁻¹' s) (𝟙 (F.obj j) ↑x)) }) =
    𝟙 ↑(⋂ f, F.map f ⁻¹' s)

Next tactic:
ext
/-- The subfunctor of `F` obtained by restricting to the preimages of a set `s ∈ F.obj i`. -/
@[simps]
def toPreimages : J ⥤ Type v where
  obj j := ⋂ f : j ⟶ i, F.map f ⁻¹' s
  map g := MapsTo.restrict (F.map g) _ _ fun x h => by
    rw [mem_iInter] at h ⊢
    intro f
    rw [← mem_preimage, preimage_preimage, mem_preimage]
    convert h (g ≫ f); rw [F.map_comp]; rfl
  map_id j := by
    simp (config := { unfoldPartialApp := true }) only [MapsTo.restrict, Subtype.map, F.map_id]
    ext
    

Proof state:
case h.a
J : Type u
inst✝ : Category.{?u.10420, u} J
F : J ⥤ Type v
i j✝ k : J
s : Set (F.obj i)
j : J
a✝ : { x // x ∈ ⋂ f, F.map f ⁻¹' s }
⊢ ↑{ val := 𝟙 (F.obj j) ↑a✝, property := (_ : (fun x => x ∈ ⋂ f, F.map f ⁻¹' s) (𝟙 (F.obj j) ↑a✝)) } =
    ↑(𝟙 (↑(⋂ f, F.map f ⁻¹' s)) a✝)

Next tactic:
rfl
/-- The subfunctor of `F` obtained by restricting to the preimages of a set `s ∈ F.obj i`. -/
@[simps]
def toPreimages : J ⥤ Type v where
  obj j := ⋂ f : j ⟶ i, F.map f ⁻¹' s
  map g := MapsTo.restrict (F.map g) _ _ fun x h => by
    rw [mem_iInter] at h ⊢
    intro f
    rw [← mem_preimage, preimage_preimage, mem_preimage]
    convert h (g ≫ f); rw [F.map_comp]; rfl
  map_id j := by
    simp (config := { unfoldPartialApp := true }) only [MapsTo.restrict, Subtype.map, F.map_id]
    ext
    rfl
  map_comp f g := by
    

Proof state:
J : Type u
inst✝ : Category.{?u.10420, u} J
F : J ⥤ Type v
i j k : J
s : Set (F.obj i)
X✝ Y✝ Z✝ : J
f : X✝ ⟶ Y✝
g : Y✝ ⟶ Z✝
⊢ { obj := fun j => ↑(⋂ f, F.map f ⁻¹' s),
          map := fun {X Y} g =>
            MapsTo.restrict (F.map g) (⋂ f, F.map f ⁻¹' s) (⋂ f, F.map f ⁻¹' s)
              (_ : ∀ x ∈ ⋂ f, F.map f ⁻¹' s, F.map g x ∈ ⋂ f, F.map f ⁻¹' s) }.map
      (f ≫ g) =
    { obj := fun j => ↑(⋂ f, F.map f ⁻¹' s),
            map := fun {X Y} g =>
              MapsTo.restrict (F.map g) (⋂ f, F.map f ⁻¹' s) (⋂ f, F.map f ⁻¹' s)
                (_ : ∀ x ∈ ⋂ f, F.map f ⁻¹' s, F.map g x ∈ ⋂ f, F.map f ⁻¹' s) }.map
        f ≫
      { obj := fun j => ↑(⋂ f, F.map f ⁻¹' s),
            map := fun {X Y} g =>
              MapsTo.restrict (F.map g) (⋂ f, F.map f ⁻¹' s) (⋂ f, F.map f ⁻¹' s)
                (_ : ∀ x ∈ ⋂ f, F.map f ⁻¹' s, F.map g x ∈ ⋂ f, F.map f ⁻¹' s) }.map
        g

Next tactic:
simp (config := { unfoldPartialApp := true }) only [MapsTo.restrict, Subtype.map, F.map_comp]
/-- The subfunctor of `F` obtained by restricting to the preimages of a set `s ∈ F.obj i`. -/
@[simps]
def toPreimages : J ⥤ Type v where
  obj j := ⋂ f : j ⟶ i, F.map f ⁻¹' s
  map g := MapsTo.restrict (F.map g) _ _ fun x h => by
    rw [mem_iInter] at h ⊢
    intro f
    rw [← mem_preimage, preimage_preimage, mem_preimage]
    convert h (g ≫ f); rw [F.map_comp]; rfl
  map_id j := by
    simp (config := { unfoldPartialApp := true }) only [MapsTo.restrict, Subtype.map, F.map_id]
    ext
    rfl
  map_comp f g := by
    simp (config := { unfoldPartialApp := true }) only [MapsTo.restrict, Subtype.map, F.map_comp]
    

Proof state:
J : Type u
inst✝ : Category.{?u.10420, u} J
F : J ⥤ Type v
i j k : J
s : Set (F.obj i)
X✝ Y✝ Z✝ : J
f : X✝ ⟶ Y✝
g : Y✝ ⟶ Z✝
⊢ (fun x =>
      { val := (F.map f ≫ F.map g) ↑x, property := (_ : (fun x => x ∈ ⋂ f, F.map f ⁻¹' s) ((F.map f ≫ F.map g) ↑x)) }) =
    (fun x => { val := F.map f ↑x, property := (_ : F.map f ↑x ∈ ⋂ f, F.map f ⁻¹' s) }) ≫ fun x =>
      { val := F.map g ↑x, property := (_ : F.map g ↑x ∈ ⋂ f, F.map f ⁻¹' s) }

Next tactic:
rfl
theorem eventualRange_mapsTo (f : j ⟶ i) :
    (F.eventualRange j).MapsTo (F.map f) (F.eventualRange i) := fun x hx => by
  

Proof state:
J : Type u
inst✝¹ : Category.{u_1, u} J
F : J ⥤ Type v
i j k : J
s : Set (F.obj i)
inst✝ : IsCofilteredOrEmpty J
f : j ⟶ i
x : F.obj j
hx : x ∈ eventualRange F j
⊢ F.map f x ∈ eventualRange F i

Next tactic:
rw [mem_eventualRange_iff] at hx ⊢
theorem eventualRange_mapsTo (f : j ⟶ i) :
    (F.eventualRange j).MapsTo (F.map f) (F.eventualRange i) := fun x hx => by
  rw [mem_eventualRange_iff] at hx ⊢
  

Proof state:
J : Type u
inst✝¹ : Category.{u_1, u} J
F : J ⥤ Type v
i j k : J
s : Set (F.obj i)
inst✝ : IsCofilteredOrEmpty J
f : j ⟶ i
x : F.obj j
hx : ∀ ⦃i : J⦄ (f : i ⟶ j), x ∈ range (F.map f)
⊢ ∀ ⦃i_1 : J⦄ (f_1 : i_1 ⟶ i), F.map f x ∈ range (F.map f_1)

Next tactic:
intro k f'
theorem eventualRange_mapsTo (f : j ⟶ i) :
    (F.eventualRange j).MapsTo (F.map f) (F.eventualRange i) := fun x hx => by
  rw [mem_eventualRange_iff] at hx ⊢
  intro k f'
  

Proof state:
J : Type u
inst✝¹ : Category.{u_1, u} J
F : J ⥤ Type v
i j k✝ : J
s : Set (F.obj i)
inst✝ : IsCofilteredOrEmpty J
f : j ⟶ i
x : F.obj j
hx : ∀ ⦃i : J⦄ (f : i ⟶ j), x ∈ range (F.map f)
k : J
f' : k ⟶ i
⊢ F.map f x ∈ range (F.map f')

Next tactic:
obtain ⟨l, g, g', he⟩ := cospan f f'
theorem eventualRange_mapsTo (f : j ⟶ i) :
    (F.eventualRange j).MapsTo (F.map f) (F.eventualRange i) := fun x hx => by
  rw [mem_eventualRange_iff] at hx ⊢
  intro k f'
  obtain ⟨l, g, g', he⟩ := cospan f f'
  

Proof state:
case intro.intro.intro
J : Type u
inst✝¹ : Category.{u_1, u} J
F : J ⥤ Type v
i j k✝ : J
s : Set (F.obj i)
inst✝ : IsCofilteredOrEmpty J
f : j ⟶ i
x : F.obj j
hx : ∀ ⦃i : J⦄ (f : i ⟶ j), x ∈ range (F.map f)
k : J
f' : k ⟶ i
l : J
g : l ⟶ j
g' : l ⟶ k
he : g ≫ f = g' ≫ f'
⊢ F.map f x ∈ range (F.map f')

Next tactic:
obtain ⟨x, rfl⟩ := hx g
theorem eventualRange_mapsTo (f : j ⟶ i) :
    (F.eventualRange j).MapsTo (F.map f) (F.eventualRange i) := fun x hx => by
  rw [mem_eventualRange_iff] at hx ⊢
  intro k f'
  obtain ⟨l, g, g', he⟩ := cospan f f'
  obtain ⟨x, rfl⟩ := hx g
  

Proof state:
case intro.intro.intro.intro
J : Type u
inst✝¹ : Category.{u_1, u} J
F : J ⥤ Type v
i j k✝ : J
s : Set (F.obj i)
inst✝ : IsCofilteredOrEmpty J
f : j ⟶ i
k : J
f' : k ⟶ i
l : J
g : l ⟶ j
g' : l ⟶ k
he : g ≫ f = g' ≫ f'
x : F.obj l
hx : ∀ ⦃i : J⦄ (f : i ⟶ j), F.map g x ∈ range (F.map f)
⊢ F.map f (F.map g x) ∈ range (F.map f')

Next tactic:
rw [← map_comp_apply, he, F.map_comp]
theorem eventualRange_mapsTo (f : j ⟶ i) :
    (F.eventualRange j).MapsTo (F.map f) (F.eventualRange i) := fun x hx => by
  rw [mem_eventualRange_iff] at hx ⊢
  intro k f'
  obtain ⟨l, g, g', he⟩ := cospan f f'
  obtain ⟨x, rfl⟩ := hx g
  rw [← map_comp_apply, he, F.map_comp]
  

Proof state:
case intro.intro.intro.intro
J : Type u
inst✝¹ : Category.{u_1, u} J
F : J ⥤ Type v
i j k✝ : J
s : Set (F.obj i)
inst✝ : IsCofilteredOrEmpty J
f : j ⟶ i
k : J
f' : k ⟶ i
l : J
g : l ⟶ j
g' : l ⟶ k
he : g ≫ f = g' ≫ f'
x : F.obj l
hx : ∀ ⦃i : J⦄ (f : i ⟶ j), F.map g x ∈ range (F.map f)
⊢ (F.map g' ≫ F.map f') x ∈ range (F.map f')

Next tactic:
exact ⟨_, rfl⟩
theorem eventualRange_eq_iff {f : i ⟶ j} :
    F.eventualRange j = range (F.map f) ↔
      ∀ ⦃k⦄ (g : k ⟶ i), range (F.map f) ⊆ range (F.map <| g ≫ f) := by
  

Proof state:
J : Type u
inst✝¹ : Category.{u_1, u} J
F : J ⥤ Type v
i j k : J
s : Set (F.obj i)
inst✝ : IsCofilteredOrEmpty J
f : i ⟶ j
⊢ eventualRange F j = range (F.map f) ↔ ∀ ⦃k : J⦄ (g : k ⟶ i), range (F.map f) ⊆ range (F.map (g ≫ f))

Next tactic:
rw [subset_antisymm_iff, eventualRange, and_iff_right (iInter₂_subset _ _), subset_iInter₂_iff]
theorem eventualRange_eq_iff {f : i ⟶ j} :
    F.eventualRange j = range (F.map f) ↔
      ∀ ⦃k⦄ (g : k ⟶ i), range (F.map f) ⊆ range (F.map <| g ≫ f) := by
  rw [subset_antisymm_iff, eventualRange, and_iff_right (iInter₂_subset _ _), subset_iInter₂_iff]
  

Proof state:
J : Type u
inst✝¹ : Category.{u_1, u} J
F : J ⥤ Type v
i j k : J
s : Set (F.obj i)
inst✝ : IsCofilteredOrEmpty J
f : i ⟶ j
⊢ (∀ (i_1 : J) (j_1 : i_1 ⟶ j), range (F.map f) ⊆ range (F.map j_1)) ↔
    ∀ ⦃k : J⦄ (g : k ⟶ i), range (F.map f) ⊆ range (F.map (g ≫ f))

Next tactic:
refine' ⟨fun h k g => h _ _, fun h j' f' => _⟩
theorem eventualRange_eq_iff {f : i ⟶ j} :
    F.eventualRange j = range (F.map f) ↔
      ∀ ⦃k⦄ (g : k ⟶ i), range (F.map f) ⊆ range (F.map <| g ≫ f) := by
  rw [subset_antisymm_iff, eventualRange, and_iff_right (iInter₂_subset _ _), subset_iInter₂_iff]
  refine' ⟨fun h k g => h _ _, fun h j' f' => _⟩
  

Proof state:
J : Type u
inst✝¹ : Category.{u_1, u} J
F : J ⥤ Type v
i j k : J
s : Set (F.obj i)
inst✝ : IsCofilteredOrEmpty J
f : i ⟶ j
h : ∀ ⦃k : J⦄ (g : k ⟶ i), range (F.map f) ⊆ range (F.map (g ≫ f))
j' : J
f' : j' ⟶ j
⊢ range (F.map f) ⊆ range (F.map f')

Next tactic:
obtain ⟨k, g, g', he⟩ := cospan f f'