l3lab/ntp-mathlib huggingface dataset:
/-- The yoneda embeddings jointly reflect limits. -/
def yonedaJointlyReflectsLimits (J : Type w) [SmallCategory J] (K : J ⥤ Cᵒᵖ) (c : Cone K)
    (t : ∀ X : C, IsLimit ((yoneda.obj X).mapCone c)) : IsLimit c :=
  let s' : ∀ s : Cone K, Cone (K ⋙ yoneda.obj s.pt.unop) := fun s =>
    ⟨PUnit, fun j _ => (s.π.app j).unop, fun j₁ j₂ α =>
      funext fun _ => Quiver.Hom.op_inj (s.w α).symm⟩
  { lift := fun s => ((t s.pt.unop).lift (s' s) PUnit.unit).op
    fac := fun s j => Quiver.Hom.unop_inj (congr_fun ((t s.pt.unop).fac (s' s) j) PUnit.unit)
    uniq := fun s m w => by
      apply Quiver.Hom.unop_inj
      suffices (fun _ : PUnit => m.unop) = (t s.pt.unop).lift (s' s) by
        apply congr_fun this PUnit.unit
      apply (t _).uniq (s' s) _ fun j => _
      intro j
      

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : Type w
inst✝ : SmallCategory J
K : J ⥤ Cᵒᵖ
c : Cone K
t : (X : C) → IsLimit ((yoneda.obj X).mapCone c)
s' : (s : Cone K) → Cone (K ⋙ yoneda.obj s.pt.unop) :=
  fun s => { pt := PUnit.{v + 1}, π := NatTrans.mk fun j x => (s.π.app j).unop }
s : Cone K
m : s.pt ⟶ c.pt
w : ∀ (j : J), m ≫ c.π.app j = s.π.app j
j : J
⊢ (fun x => m.unop) ≫ ((yoneda.obj s.pt.unop).mapCone c).π.app j = (s' s).π.app j

Next tactic:
funext
/-- The yoneda embeddings jointly reflect limits. -/
def yonedaJointlyReflectsLimits (J : Type w) [SmallCategory J] (K : J ⥤ Cᵒᵖ) (c : Cone K)
    (t : ∀ X : C, IsLimit ((yoneda.obj X).mapCone c)) : IsLimit c :=
  let s' : ∀ s : Cone K, Cone (K ⋙ yoneda.obj s.pt.unop) := fun s =>
    ⟨PUnit, fun j _ => (s.π.app j).unop, fun j₁ j₂ α =>
      funext fun _ => Quiver.Hom.op_inj (s.w α).symm⟩
  { lift := fun s => ((t s.pt.unop).lift (s' s) PUnit.unit).op
    fac := fun s j => Quiver.Hom.unop_inj (congr_fun ((t s.pt.unop).fac (s' s) j) PUnit.unit)
    uniq := fun s m w => by
      apply Quiver.Hom.unop_inj
      suffices (fun _ : PUnit => m.unop) = (t s.pt.unop).lift (s' s) by
        apply congr_fun this PUnit.unit
      apply (t _).uniq (s' s) _ fun j => _
      intro j
      funext
      

Proof state:
case h
C : Type u
inst✝¹ : Category.{v, u} C
J : Type w
inst✝ : SmallCategory J
K : J ⥤ Cᵒᵖ
c : Cone K
t : (X : C) → IsLimit ((yoneda.obj X).mapCone c)
s' : (s : Cone K) → Cone (K ⋙ yoneda.obj s.pt.unop) :=
  fun s => { pt := PUnit.{v + 1}, π := NatTrans.mk fun j x => (s.π.app j).unop }
s : Cone K
m : s.pt ⟶ c.pt
w : ∀ (j : J), m ≫ c.π.app j = s.π.app j
j : J
x✝ : (s' s).pt
⊢ ((fun x => m.unop) ≫ ((yoneda.obj s.pt.unop).mapCone c).π.app j) x✝ = (s' s).π.app j x✝

Next tactic:
exact Quiver.Hom.op_inj (w j)
/-- The coyoneda embeddings jointly reflect limits. -/
def coyonedaJointlyReflectsLimits (J : Type w) [SmallCategory J] (K : J ⥤ C) (c : Cone K)
    (t : ∀ X : Cᵒᵖ, IsLimit ((coyoneda.obj X).mapCone c)) : IsLimit c :=
  let s' : ∀ s : Cone K, Cone (K ⋙ coyoneda.obj (op s.pt)) := fun s =>
    ⟨PUnit, fun j _ => s.π.app j, fun j₁ j₂ α => funext fun _ => (s.w α).symm⟩
  { lift := fun s => (t (op s.pt)).lift (s' s) PUnit.unit
    fac := fun s j => congr_fun ((t _).fac (s' s) j) PUnit.unit
    uniq := fun s m w => by
      

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : Type w
inst✝ : SmallCategory J
K : J ⥤ C
c : Cone K
t : (X : Cᵒᵖ) → IsLimit ((coyoneda.obj X).mapCone c)
s' : (s : Cone K) → Cone (K ⋙ coyoneda.obj (op s.pt)) :=
  fun s => { pt := PUnit.{v + 1}, π := NatTrans.mk fun j x => s.π.app j }
s : Cone K
m : s.pt ⟶ c.pt
w : ∀ (j : J), m ≫ c.π.app j = s.π.app j
⊢ m = (fun s => IsLimit.lift (t (op s.pt)) (s' s) PUnit.unit) s

Next tactic:
suffices (fun _ : PUnit => m) = (t _).lift (s' s) by apply congr_fun this PUnit.unit
/-- The coyoneda embeddings jointly reflect limits. -/
def coyonedaJointlyReflectsLimits (J : Type w) [SmallCategory J] (K : J ⥤ C) (c : Cone K)
    (t : ∀ X : Cᵒᵖ, IsLimit ((coyoneda.obj X).mapCone c)) : IsLimit c :=
  let s' : ∀ s : Cone K, Cone (K ⋙ coyoneda.obj (op s.pt)) := fun s =>
    ⟨PUnit, fun j _ => s.π.app j, fun j₁ j₂ α => funext fun _ => (s.w α).symm⟩
  { lift := fun s => (t (op s.pt)).lift (s' s) PUnit.unit
    fac := fun s j => congr_fun ((t _).fac (s' s) j) PUnit.unit
    uniq := fun s m w => by
      suffices (fun _ : PUnit => m) = (t _).lift (s' s) by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : Type w
inst✝ : SmallCategory J
K : J ⥤ C
c : Cone K
t : (X : Cᵒᵖ) → IsLimit ((coyoneda.obj X).mapCone c)
s' : (s : Cone K) → Cone (K ⋙ coyoneda.obj (op s.pt)) :=
  fun s => { pt := PUnit.{v + 1}, π := NatTrans.mk fun j x => s.π.app j }
s : Cone K
m : s.pt ⟶ c.pt
w : ∀ (j : J), m ≫ c.π.app j = s.π.app j
this : (fun x => m) = IsLimit.lift (t (op s.pt)) (s' s)
⊢ m = (fun s => IsLimit.lift (t (op s.pt)) (s' s) PUnit.unit) s

Next tactic:
apply congr_fun this PUnit.unit
/-- The coyoneda embeddings jointly reflect limits. -/
def coyonedaJointlyReflectsLimits (J : Type w) [SmallCategory J] (K : J ⥤ C) (c : Cone K)
    (t : ∀ X : Cᵒᵖ, IsLimit ((coyoneda.obj X).mapCone c)) : IsLimit c :=
  let s' : ∀ s : Cone K, Cone (K ⋙ coyoneda.obj (op s.pt)) := fun s =>
    ⟨PUnit, fun j _ => s.π.app j, fun j₁ j₂ α => funext fun _ => (s.w α).symm⟩
  { lift := fun s => (t (op s.pt)).lift (s' s) PUnit.unit
    fac := fun s j => congr_fun ((t _).fac (s' s) j) PUnit.unit
    uniq := fun s m w => by
      suffices (fun _ : PUnit => m) = (t _).lift (s' s) by apply congr_fun this PUnit.unit
      

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : Type w
inst✝ : SmallCategory J
K : J ⥤ C
c : Cone K
t : (X : Cᵒᵖ) → IsLimit ((coyoneda.obj X).mapCone c)
s' : (s : Cone K) → Cone (K ⋙ coyoneda.obj (op s.pt)) :=
  fun s => { pt := PUnit.{v + 1}, π := NatTrans.mk fun j x => s.π.app j }
s : Cone K
m : s.pt ⟶ c.pt
w : ∀ (j : J), m ≫ c.π.app j = s.π.app j
⊢ (fun x => m) = IsLimit.lift (t (op s.pt)) (s' s)

Next tactic:
apply (t _).uniq (s' s) _ fun j => _
/-- The coyoneda embeddings jointly reflect limits. -/
def coyonedaJointlyReflectsLimits (J : Type w) [SmallCategory J] (K : J ⥤ C) (c : Cone K)
    (t : ∀ X : Cᵒᵖ, IsLimit ((coyoneda.obj X).mapCone c)) : IsLimit c :=
  let s' : ∀ s : Cone K, Cone (K ⋙ coyoneda.obj (op s.pt)) := fun s =>
    ⟨PUnit, fun j _ => s.π.app j, fun j₁ j₂ α => funext fun _ => (s.w α).symm⟩
  { lift := fun s => (t (op s.pt)).lift (s' s) PUnit.unit
    fac := fun s j => congr_fun ((t _).fac (s' s) j) PUnit.unit
    uniq := fun s m w => by
      suffices (fun _ : PUnit => m) = (t _).lift (s' s) by apply congr_fun this PUnit.unit
      apply (t _).uniq (s' s) _ fun j => _
      

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : Type w
inst✝ : SmallCategory J
K : J ⥤ C
c : Cone K
t : (X : Cᵒᵖ) → IsLimit ((coyoneda.obj X).mapCone c)
s' : (s : Cone K) → Cone (K ⋙ coyoneda.obj (op s.pt)) :=
  fun s => { pt := PUnit.{v + 1}, π := NatTrans.mk fun j x => s.π.app j }
s : Cone K
m : s.pt ⟶ c.pt
w : ∀ (j : J), m ≫ c.π.app j = s.π.app j
⊢ ∀ (j : J), (fun x => m) ≫ ((coyoneda.obj (op s.pt)).mapCone c).π.app j = (s' s).π.app j

Next tactic:
intro j
/-- The coyoneda embeddings jointly reflect limits. -/
def coyonedaJointlyReflectsLimits (J : Type w) [SmallCategory J] (K : J ⥤ C) (c : Cone K)
    (t : ∀ X : Cᵒᵖ, IsLimit ((coyoneda.obj X).mapCone c)) : IsLimit c :=
  let s' : ∀ s : Cone K, Cone (K ⋙ coyoneda.obj (op s.pt)) := fun s =>
    ⟨PUnit, fun j _ => s.π.app j, fun j₁ j₂ α => funext fun _ => (s.w α).symm⟩
  { lift := fun s => (t (op s.pt)).lift (s' s) PUnit.unit
    fac := fun s j => congr_fun ((t _).fac (s' s) j) PUnit.unit
    uniq := fun s m w => by
      suffices (fun _ : PUnit => m) = (t _).lift (s' s) by apply congr_fun this PUnit.unit
      apply (t _).uniq (s' s) _ fun j => _
      intro j
      

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : Type w
inst✝ : SmallCategory J
K : J ⥤ C
c : Cone K
t : (X : Cᵒᵖ) → IsLimit ((coyoneda.obj X).mapCone c)
s' : (s : Cone K) → Cone (K ⋙ coyoneda.obj (op s.pt)) :=
  fun s => { pt := PUnit.{v + 1}, π := NatTrans.mk fun j x => s.π.app j }
s : Cone K
m : s.pt ⟶ c.pt
w : ∀ (j : J), m ≫ c.π.app j = s.π.app j
j : J
⊢ (fun x => m) ≫ ((coyoneda.obj (op s.pt)).mapCone c).π.app j = (s' s).π.app j

Next tactic:
funext
/-- The coyoneda embeddings jointly reflect limits. -/
def coyonedaJointlyReflectsLimits (J : Type w) [SmallCategory J] (K : J ⥤ C) (c : Cone K)
    (t : ∀ X : Cᵒᵖ, IsLimit ((coyoneda.obj X).mapCone c)) : IsLimit c :=
  let s' : ∀ s : Cone K, Cone (K ⋙ coyoneda.obj (op s.pt)) := fun s =>
    ⟨PUnit, fun j _ => s.π.app j, fun j₁ j₂ α => funext fun _ => (s.w α).symm⟩
  { lift := fun s => (t (op s.pt)).lift (s' s) PUnit.unit
    fac := fun s j => congr_fun ((t _).fac (s' s) j) PUnit.unit
    uniq := fun s m w => by
      suffices (fun _ : PUnit => m) = (t _).lift (s' s) by apply congr_fun this PUnit.unit
      apply (t _).uniq (s' s) _ fun j => _
      intro j
      funext
      

Proof state:
case h
C : Type u
inst✝¹ : Category.{v, u} C
J : Type w
inst✝ : SmallCategory J
K : J ⥤ C
c : Cone K
t : (X : Cᵒᵖ) → IsLimit ((coyoneda.obj X).mapCone c)
s' : (s : Cone K) → Cone (K ⋙ coyoneda.obj (op s.pt)) :=
  fun s => { pt := PUnit.{v + 1}, π := NatTrans.mk fun j x => s.π.app j }
s : Cone K
m : s.pt ⟶ c.pt
w : ∀ (j : J), m ≫ c.π.app j = s.π.app j
j : J
x✝ : (s' s).pt
⊢ ((fun x => m) ≫ ((coyoneda.obj (op s.pt)).mapCone c).π.app j) x✝ = (s' s).π.app j x✝

Next tactic:
exact w j
instance yonedaFunctorPreservesLimits : PreservesLimits (@yoneda D _) := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u
inst✝ : SmallCategory D
⊢ PreservesLimits yoneda

Next tactic:
apply preservesLimitsOfEvaluation
instance yonedaFunctorPreservesLimits : PreservesLimits (@yoneda D _) := by
  apply preservesLimitsOfEvaluation
  

Proof state:
case x
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u
inst✝ : SmallCategory D
⊢ (k : Dᵒᵖ) → PreservesLimitsOfSize.{u, u, u, u, u, u + 1} (yoneda ⋙ (evaluation Dᵒᵖ (Type u)).obj k)

Next tactic:
intro K
instance yonedaFunctorPreservesLimits : PreservesLimits (@yoneda D _) := by
  apply preservesLimitsOfEvaluation
  intro K
  

Proof state:
case x
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u
inst✝ : SmallCategory D
K : Dᵒᵖ
⊢ PreservesLimitsOfSize.{u, u, u, u, u, u + 1} (yoneda ⋙ (evaluation Dᵒᵖ (Type u)).obj K)

Next tactic:
change PreservesLimits (coyoneda.obj K)
instance yonedaFunctorPreservesLimits : PreservesLimits (@yoneda D _) := by
  apply preservesLimitsOfEvaluation
  intro K
  change PreservesLimits (coyoneda.obj K)
  

Proof state:
case x
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u
inst✝ : SmallCategory D
K : Dᵒᵖ
⊢ PreservesLimits (coyoneda.obj K)

Next tactic:
infer_instance
instance coyonedaFunctorPreservesLimits : PreservesLimits (@coyoneda D _) := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u
inst✝ : SmallCategory D
⊢ PreservesLimits coyoneda

Next tactic:
apply preservesLimitsOfEvaluation
instance coyonedaFunctorPreservesLimits : PreservesLimits (@coyoneda D _) := by
  apply preservesLimitsOfEvaluation
  

Proof state:
case x
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u
inst✝ : SmallCategory D
⊢ (k : D) → PreservesLimitsOfSize.{u, u, u, u, u, u + 1} (coyoneda ⋙ (evaluation D (Type u)).obj k)

Next tactic:
intro K
instance coyonedaFunctorPreservesLimits : PreservesLimits (@coyoneda D _) := by
  apply preservesLimitsOfEvaluation
  intro K
  

Proof state:
case x
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u
inst✝ : SmallCategory D
K : D
⊢ PreservesLimitsOfSize.{u, u, u, u, u, u + 1} (coyoneda ⋙ (evaluation D (Type u)).obj K)

Next tactic:
change PreservesLimits (yoneda.obj K)
instance coyonedaFunctorPreservesLimits : PreservesLimits (@coyoneda D _) := by
  apply preservesLimitsOfEvaluation
  intro K
  change PreservesLimits (yoneda.obj K)
  

Proof state:
case x
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u
inst✝ : SmallCategory D
K : D
⊢ PreservesLimits (yoneda.obj K)

Next tactic:
infer_instance
/-- The forward map of a filter under a relation. Generalization of `Filter.map` to relations. Note
that `Rel.core` generalizes `Set.preimage`. -/
def rmap (r : Rel α β) (l : Filter α) : Filter β where
  sets := { s | r.core s ∈ l }
  univ_sets := by 

Proof state:
α : Type u
β : Type v
γ : Type w
r : Rel α β
l : Filter α
⊢ Set.univ ∈ {s | Rel.core r s ∈ l}

Next tactic:
simp
/-- The forward map of a filter under a relation. Generalization of `Filter.map` to relations. Note
that `Rel.core` generalizes `Set.preimage`. -/
def rmap (r : Rel α β) (l : Filter α) : Filter β where
  sets := { s | r.core s ∈ l }
  univ_sets := by simp
  sets_of_superset hs st := mem_of_superset hs (Rel.core_mono _ st)
  inter_sets hs ht := by
    

Proof state:
α : Type u
β : Type v
γ : Type w
r : Rel α β
l : Filter α
x✝ y✝ : Set β
hs : x✝ ∈ {s | Rel.core r s ∈ l}
ht : y✝ ∈ {s | Rel.core r s ∈ l}
⊢ x✝ ∩ y✝ ∈ {s | Rel.core r s ∈ l}

Next tactic:
simp only [Set.mem_setOf_eq]
/-- The forward map of a filter under a relation. Generalization of `Filter.map` to relations. Note
that `Rel.core` generalizes `Set.preimage`. -/
def rmap (r : Rel α β) (l : Filter α) : Filter β where
  sets := { s | r.core s ∈ l }
  univ_sets := by simp
  sets_of_superset hs st := mem_of_superset hs (Rel.core_mono _ st)
  inter_sets hs ht := by
    simp only [Set.mem_setOf_eq]
    

Proof state:
α : Type u
β : Type v
γ : Type w
r : Rel α β
l : Filter α
x✝ y✝ : Set β
hs : x✝ ∈ {s | Rel.core r s ∈ l}
ht : y✝ ∈ {s | Rel.core r s ∈ l}
⊢ Rel.core r (x✝ ∩ y✝) ∈ l

Next tactic:
convert inter_mem hs ht
/-- The forward map of a filter under a relation. Generalization of `Filter.map` to relations. Note
that `Rel.core` generalizes `Set.preimage`. -/
def rmap (r : Rel α β) (l : Filter α) : Filter β where
  sets := { s | r.core s ∈ l }
  univ_sets := by simp
  sets_of_superset hs st := mem_of_superset hs (Rel.core_mono _ st)
  inter_sets hs ht := by
    simp only [Set.mem_setOf_eq]
    convert inter_mem hs ht
    

Proof state:
case h.e'_4
α : Type u
β : Type v
γ : Type w
r : Rel α β
l : Filter α
x✝ y✝ : Set β
hs : x✝ ∈ {s | Rel.core r s ∈ l}
ht : y✝ ∈ {s | Rel.core r s ∈ l}
⊢ Rel.core r (x✝ ∩ y✝) = Rel.core r x✝ ∩ Rel.core r y✝

Next tactic:
rw [← Rel.core_inter]
@[simp]
theorem rmap_rmap (r : Rel α β) (s : Rel β γ) (l : Filter α) :
    rmap s (rmap r l) = rmap (r.comp s) l :=
  filter_eq <| by 

Proof state:
α : Type u
β : Type v
γ : Type w
r : Rel α β
s : Rel β γ
l : Filter α
⊢ (rmap s (rmap r l)).sets = (rmap (Rel.comp r s) l).sets

Next tactic:
simp [rmap_sets, Set.preimage, Rel.core_comp]
theorem rcomap_rcomap (r : Rel α β) (s : Rel β γ) (l : Filter γ) :
    rcomap r (rcomap s l) = rcomap (r.comp s) l :=
  filter_eq <| by
    

Proof state:
α : Type u
β : Type v
γ : Type w
r : Rel α β
s : Rel β γ
l : Filter γ
⊢ (rcomap r (rcomap s l)).sets = (rcomap (Rel.comp r s) l).sets

Next tactic:
ext t
theorem rcomap_rcomap (r : Rel α β) (s : Rel β γ) (l : Filter γ) :
    rcomap r (rcomap s l) = rcomap (r.comp s) l :=
  filter_eq <| by
    ext t; 

Proof state:
case h
α : Type u
β : Type v
γ : Type w
r : Rel α β
s : Rel β γ
l : Filter γ
t : Set α
⊢ t ∈ (rcomap r (rcomap s l)).sets ↔ t ∈ (rcomap (Rel.comp r s) l).sets

Next tactic:
simp [rcomap_sets, Rel.image, Rel.core_comp]
theorem rcomap_rcomap (r : Rel α β) (s : Rel β γ) (l : Filter γ) :
    rcomap r (rcomap s l) = rcomap (r.comp s) l :=
  filter_eq <| by
    ext t; simp [rcomap_sets, Rel.image, Rel.core_comp]; 

Proof state:
case h
α : Type u
β : Type v
γ : Type w
r : Rel α β
s : Rel β γ
l : Filter γ
t : Set α
⊢ (∃ x, (∃ x_1 ∈ l, Rel.core s x_1 ⊆ x) ∧ Rel.core r x ⊆ t) ↔ ∃ x ∈ l, Rel.core r (Rel.core s x) ⊆ t

Next tactic:
constructor
theorem rcomap_rcomap (r : Rel α β) (s : Rel β γ) (l : Filter γ) :
    rcomap r (rcomap s l) = rcomap (r.comp s) l :=
  filter_eq <| by
    ext t; simp [rcomap_sets, Rel.image, Rel.core_comp]; constructor
    · 

Proof state:
case h.mp
α : Type u
β : Type v
γ : Type w
r : Rel α β
s : Rel β γ
l : Filter γ
t : Set α
⊢ (∃ x, (∃ x_1 ∈ l, Rel.core s x_1 ⊆ x) ∧ Rel.core r x ⊆ t) → ∃ x ∈ l, Rel.core r (Rel.core s x) ⊆ t

Next tactic:
rintro ⟨u, ⟨v, vsets, hv⟩, h⟩
theorem rcomap_rcomap (r : Rel α β) (s : Rel β γ) (l : Filter γ) :
    rcomap r (rcomap s l) = rcomap (r.comp s) l :=
  filter_eq <| by
    ext t; simp [rcomap_sets, Rel.image, Rel.core_comp]; constructor
    · rintro ⟨u, ⟨v, vsets, hv⟩, h⟩
      

Proof state:
case h.mp.intro.intro.intro.intro
α : Type u
β : Type v
γ : Type w
r : Rel α β
s : Rel β γ
l : Filter γ
t : Set α
u : Set β
h : Rel.core r u ⊆ t
v : Set γ
vsets : v ∈ l
hv : Rel.core s v ⊆ u
⊢ ∃ x ∈ l, Rel.core r (Rel.core s x) ⊆ t

Next tactic:
exact ⟨v, vsets, Set.Subset.trans (Rel.core_mono _ hv) h⟩
theorem rcomap_rcomap (r : Rel α β) (s : Rel β γ) (l : Filter γ) :
    rcomap r (rcomap s l) = rcomap (r.comp s) l :=
  filter_eq <| by
    ext t; simp [rcomap_sets, Rel.image, Rel.core_comp]; constructor
    · rintro ⟨u, ⟨v, vsets, hv⟩, h⟩
      exact ⟨v, vsets, Set.Subset.trans (Rel.core_mono _ hv) h⟩
    

Proof state:
case h.mpr
α : Type u
β : Type v
γ : Type w
r : Rel α β
s : Rel β γ
l : Filter γ
t : Set α
⊢ (∃ x ∈ l, Rel.core r (Rel.core s x) ⊆ t) → ∃ x, (∃ x_1 ∈ l, Rel.core s x_1 ⊆ x) ∧ Rel.core r x ⊆ t

Next tactic:
rintro ⟨t, tsets, ht⟩
theorem rcomap_rcomap (r : Rel α β) (s : Rel β γ) (l : Filter γ) :
    rcomap r (rcomap s l) = rcomap (r.comp s) l :=
  filter_eq <| by
    ext t; simp [rcomap_sets, Rel.image, Rel.core_comp]; constructor
    · rintro ⟨u, ⟨v, vsets, hv⟩, h⟩
      exact ⟨v, vsets, Set.Subset.trans (Rel.core_mono _ hv) h⟩
    rintro ⟨t, tsets, ht⟩
    

Proof state:
case h.mpr.intro.intro
α : Type u
β : Type v
γ : Type w
r : Rel α β
s : Rel β γ
l : Filter γ
t✝ : Set α
t : Set γ
tsets : t ∈ l
ht : Rel.core r (Rel.core s t) ⊆ t✝
⊢ ∃ x, (∃ x_1 ∈ l, Rel.core s x_1 ⊆ x) ∧ Rel.core r x ⊆ t✝

Next tactic:
exact ⟨Rel.core s t, ⟨t, tsets, Set.Subset.rfl⟩, ht⟩
theorem rtendsto_iff_le_rcomap (r : Rel α β) (l₁ : Filter α) (l₂ : Filter β) :
    RTendsto r l₁ l₂ ↔ l₁ ≤ l₂.rcomap r := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
r : Rel α β
l₁ : Filter α
l₂ : Filter β
⊢ RTendsto r l₁ l₂ ↔ l₁ ≤ rcomap r l₂

Next tactic:
rw [rtendsto_def]
theorem rtendsto_iff_le_rcomap (r : Rel α β) (l₁ : Filter α) (l₂ : Filter β) :
    RTendsto r l₁ l₂ ↔ l₁ ≤ l₂.rcomap r := by
  rw [rtendsto_def]
  

Proof state:
α : Type u
β : Type v
γ : Type w
r : Rel α β
l₁ : Filter α
l₂ : Filter β
⊢ (∀ s ∈ l₂, Rel.core r s ∈ l₁) ↔ l₁ ≤ rcomap r l₂

Next tactic:
simp_rw [← l₂.mem_sets]
theorem rtendsto_iff_le_rcomap (r : Rel α β) (l₁ : Filter α) (l₂ : Filter β) :
    RTendsto r l₁ l₂ ↔ l₁ ≤ l₂.rcomap r := by
  rw [rtendsto_def]
  simp_rw [← l₂.mem_sets]
  

Proof state:
α : Type u
β : Type v
γ : Type w
r : Rel α β
l₁ : Filter α
l₂ : Filter β
⊢ (∀ s ∈ l₂.sets, Rel.core r s ∈ l₁) ↔ l₁ ≤ rcomap r l₂

Next tactic:
simp [Filter.le_def, rcomap, Rel.mem_image]
theorem rtendsto_iff_le_rcomap (r : Rel α β) (l₁ : Filter α) (l₂ : Filter β) :
    RTendsto r l₁ l₂ ↔ l₁ ≤ l₂.rcomap r := by
  rw [rtendsto_def]
  simp_rw [← l₂.mem_sets]
  simp [Filter.le_def, rcomap, Rel.mem_image]; 

Proof state:
α : Type u
β : Type v
γ : Type w
r : Rel α β
l₁ : Filter α
l₂ : Filter β
⊢ (∀ s ∈ l₂, Rel.core r s ∈ l₁) ↔ ∀ (x : Set α), ∀ x_1 ∈ l₂, Rel.core r x_1 ⊆ x → x ∈ l₁

Next tactic:
constructor
theorem rtendsto_iff_le_rcomap (r : Rel α β) (l₁ : Filter α) (l₂ : Filter β) :
    RTendsto r l₁ l₂ ↔ l₁ ≤ l₂.rcomap r := by
  rw [rtendsto_def]
  simp_rw [← l₂.mem_sets]
  simp [Filter.le_def, rcomap, Rel.mem_image]; constructor
  · 

Proof state:
case mp
α : Type u
β : Type v
γ : Type w
r : Rel α β
l₁ : Filter α
l₂ : Filter β
⊢ (∀ s ∈ l₂, Rel.core r s ∈ l₁) → ∀ (x : Set α), ∀ x_1 ∈ l₂, Rel.core r x_1 ⊆ x → x ∈ l₁

Next tactic:
exact fun h s t tl₂ => mem_of_superset (h t tl₂)
theorem rtendsto_iff_le_rcomap (r : Rel α β) (l₁ : Filter α) (l₂ : Filter β) :
    RTendsto r l₁ l₂ ↔ l₁ ≤ l₂.rcomap r := by
  rw [rtendsto_def]
  simp_rw [← l₂.mem_sets]
  simp [Filter.le_def, rcomap, Rel.mem_image]; constructor
  · exact fun h s t tl₂ => mem_of_superset (h t tl₂)
  · 

Proof state:
case mpr
α : Type u
β : Type v
γ : Type w
r : Rel α β
l₁ : Filter α
l₂ : Filter β
⊢ (∀ (x : Set α), ∀ x_1 ∈ l₂, Rel.core r x_1 ⊆ x → x ∈ l₁) → ∀ s ∈ l₂, Rel.core r s ∈ l₁

Next tactic:
exact fun h t tl₂ => h _ t tl₂ Set.Subset.rfl
@[simp]
theorem rcomap'_rcomap' (r : Rel α β) (s : Rel β γ) (l : Filter γ) :
    rcomap' r (rcomap' s l) = rcomap' (r.comp s) l :=
  Filter.ext fun t => by
    

Proof state:
α : Type u
β : Type v
γ : Type w
r : Rel α β
s : Rel β γ
l : Filter γ
t : Set α
⊢ t ∈ rcomap' r (rcomap' s l) ↔ t ∈ rcomap' (Rel.comp r s) l

Next tactic:
simp only [mem_rcomap', Rel.preimage_comp]
@[simp]
theorem rcomap'_rcomap' (r : Rel α β) (s : Rel β γ) (l : Filter γ) :
    rcomap' r (rcomap' s l) = rcomap' (r.comp s) l :=
  Filter.ext fun t => by
    simp only [mem_rcomap', Rel.preimage_comp]
    

Proof state:
α : Type u
β : Type v
γ : Type w
r : Rel α β
s : Rel β γ
l : Filter γ
t : Set α
⊢ (∃ t_1, (∃ t ∈ l, Rel.preimage s t ⊆ t_1) ∧ Rel.preimage r t_1 ⊆ t) ↔
    ∃ t_1 ∈ l, Rel.preimage r (Rel.preimage s t_1) ⊆ t

Next tactic:
constructor
@[simp]
theorem rcomap'_rcomap' (r : Rel α β) (s : Rel β γ) (l : Filter γ) :
    rcomap' r (rcomap' s l) = rcomap' (r.comp s) l :=
  Filter.ext fun t => by
    simp only [mem_rcomap', Rel.preimage_comp]
    constructor
    · 

Proof state:
case mp
α : Type u
β : Type v
γ : Type w
r : Rel α β
s : Rel β γ
l : Filter γ
t : Set α
⊢ (∃ t_1, (∃ t ∈ l, Rel.preimage s t ⊆ t_1) ∧ Rel.preimage r t_1 ⊆ t) →
    ∃ t_1 ∈ l, Rel.preimage r (Rel.preimage s t_1) ⊆ t

Next tactic:
rintro ⟨u, ⟨v, vsets, hv⟩, h⟩
@[simp]
theorem rcomap'_rcomap' (r : Rel α β) (s : Rel β γ) (l : Filter γ) :
    rcomap' r (rcomap' s l) = rcomap' (r.comp s) l :=
  Filter.ext fun t => by
    simp only [mem_rcomap', Rel.preimage_comp]
    constructor
    · rintro ⟨u, ⟨v, vsets, hv⟩, h⟩
      

Proof state:
case mp.intro.intro.intro.intro
α : Type u
β : Type v
γ : Type w
r : Rel α β
s : Rel β γ
l : Filter γ
t : Set α
u : Set β
h : Rel.preimage r u ⊆ t
v : Set γ
vsets : v ∈ l
hv : Rel.preimage s v ⊆ u
⊢ ∃ t_1 ∈ l, Rel.preimage r (Rel.preimage s t_1) ⊆ t

Next tactic:
exact ⟨v, vsets, (Rel.preimage_mono _ hv).trans h⟩
@[simp]
theorem rcomap'_rcomap' (r : Rel α β) (s : Rel β γ) (l : Filter γ) :
    rcomap' r (rcomap' s l) = rcomap' (r.comp s) l :=
  Filter.ext fun t => by
    simp only [mem_rcomap', Rel.preimage_comp]
    constructor
    · rintro ⟨u, ⟨v, vsets, hv⟩, h⟩
      exact ⟨v, vsets, (Rel.preimage_mono _ hv).trans h⟩
    

Proof state:
case mpr
α : Type u
β : Type v
γ : Type w
r : Rel α β
s : Rel β γ
l : Filter γ
t : Set α
⊢ (∃ t_1 ∈ l, Rel.preimage r (Rel.preimage s t_1) ⊆ t) →
    ∃ t_1, (∃ t ∈ l, Rel.preimage s t ⊆ t_1) ∧ Rel.preimage r t_1 ⊆ t

Next tactic:
rintro ⟨t, tsets, ht⟩
@[simp]
theorem rcomap'_rcomap' (r : Rel α β) (s : Rel β γ) (l : Filter γ) :
    rcomap' r (rcomap' s l) = rcomap' (r.comp s) l :=
  Filter.ext fun t => by
    simp only [mem_rcomap', Rel.preimage_comp]
    constructor
    · rintro ⟨u, ⟨v, vsets, hv⟩, h⟩
      exact ⟨v, vsets, (Rel.preimage_mono _ hv).trans h⟩
    rintro ⟨t, tsets, ht⟩
    

Proof state:
case mpr.intro.intro
α : Type u
β : Type v
γ : Type w
r : Rel α β
s : Rel β γ
l : Filter γ
t✝ : Set α
t : Set γ
tsets : t ∈ l
ht : Rel.preimage r (Rel.preimage s t) ⊆ t✝
⊢ ∃ t, (∃ t_1 ∈ l, Rel.preimage s t_1 ⊆ t) ∧ Rel.preimage r t ⊆ t✝

Next tactic:
exact ⟨s.preimage t, ⟨t, tsets, Set.Subset.rfl⟩, ht⟩
theorem rtendsto'_def (r : Rel α β) (l₁ : Filter α) (l₂ : Filter β) :
    RTendsto' r l₁ l₂ ↔ ∀ s ∈ l₂, r.preimage s ∈ l₁ := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
r : Rel α β
l₁ : Filter α
l₂ : Filter β
⊢ RTendsto' r l₁ l₂ ↔ ∀ s ∈ l₂, Rel.preimage r s ∈ l₁

Next tactic:
unfold RTendsto' rcomap'