l3lab/ntp-mathlib huggingface dataset:
theorem isCoseparating_op_iff (𝒢 : Set C) : IsCoseparating 𝒢.op ↔ IsSeparating 𝒢 := by
  refine' ⟨fun h𝒢 X Y f g hfg => _, fun h𝒢 X Y f g hfg => _⟩
  · refine' Quiver.Hom.op_inj (h𝒢 _ _ fun G hG h => Quiver.Hom.unop_inj _)
    

Proof state:
case refine'_1
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsCoseparating (Set.op 𝒢)
X Y : C
f g : X ⟶ Y
hfg : ∀ G ∈ 𝒢, ∀ (h : G ⟶ X), h ≫ f = h ≫ g
G : Cᵒᵖ
hG : G ∈ Set.op 𝒢
h : op X ⟶ G
⊢ (f.op ≫ h).unop = (g.op ≫ h).unop

Next tactic:
simpa only [unop_comp, Quiver.Hom.unop_op] using hfg _ (Set.mem_op.1 hG) _
theorem isCoseparating_op_iff (𝒢 : Set C) : IsCoseparating 𝒢.op ↔ IsSeparating 𝒢 := by
  refine' ⟨fun h𝒢 X Y f g hfg => _, fun h𝒢 X Y f g hfg => _⟩
  · refine' Quiver.Hom.op_inj (h𝒢 _ _ fun G hG h => Quiver.Hom.unop_inj _)
    simpa only [unop_comp, Quiver.Hom.unop_op] using hfg _ (Set.mem_op.1 hG) _
  · 

Proof state:
case refine'_2
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsSeparating 𝒢
X Y : Cᵒᵖ
f g : X ⟶ Y
hfg : ∀ G ∈ Set.op 𝒢, ∀ (h : Y ⟶ G), f ≫ h = g ≫ h
⊢ f = g

Next tactic:
refine' Quiver.Hom.unop_inj (h𝒢 _ _ fun G hG h => Quiver.Hom.op_inj _)
theorem isCoseparating_op_iff (𝒢 : Set C) : IsCoseparating 𝒢.op ↔ IsSeparating 𝒢 := by
  refine' ⟨fun h𝒢 X Y f g hfg => _, fun h𝒢 X Y f g hfg => _⟩
  · refine' Quiver.Hom.op_inj (h𝒢 _ _ fun G hG h => Quiver.Hom.unop_inj _)
    simpa only [unop_comp, Quiver.Hom.unop_op] using hfg _ (Set.mem_op.1 hG) _
  · refine' Quiver.Hom.unop_inj (h𝒢 _ _ fun G hG h => Quiver.Hom.op_inj _)
    

Proof state:
case refine'_2
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsSeparating 𝒢
X Y : Cᵒᵖ
f g : X ⟶ Y
hfg : ∀ G ∈ Set.op 𝒢, ∀ (h : Y ⟶ G), f ≫ h = g ≫ h
G : C
hG : G ∈ 𝒢
h : G ⟶ Y.unop
⊢ (h ≫ f.unop).op = (h ≫ g.unop).op

Next tactic:
simpa only [op_comp, Quiver.Hom.op_unop] using hfg _ (Set.op_mem_op.2 hG) _
theorem isCoseparating_unop_iff (𝒢 : Set Cᵒᵖ) : IsCoseparating 𝒢.unop ↔ IsSeparating 𝒢 := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set Cᵒᵖ
⊢ IsCoseparating (Set.unop 𝒢) ↔ IsSeparating 𝒢

Next tactic:
rw [← isSeparating_op_iff, Set.unop_op]
theorem isSeparating_unop_iff (𝒢 : Set Cᵒᵖ) : IsSeparating 𝒢.unop ↔ IsCoseparating 𝒢 := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set Cᵒᵖ
⊢ IsSeparating (Set.unop 𝒢) ↔ IsCoseparating 𝒢

Next tactic:
rw [← isCoseparating_op_iff, Set.unop_op]
theorem isDetecting_op_iff (𝒢 : Set C) : IsDetecting 𝒢.op ↔ IsCodetecting 𝒢 := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
⊢ IsDetecting (Set.op 𝒢) ↔ IsCodetecting 𝒢

Next tactic:
refine' ⟨fun h𝒢 X Y f hf => _, fun h𝒢 X Y f hf => _⟩
theorem isDetecting_op_iff (𝒢 : Set C) : IsDetecting 𝒢.op ↔ IsCodetecting 𝒢 := by
  refine' ⟨fun h𝒢 X Y f hf => _, fun h𝒢 X Y f hf => _⟩
  · 

Proof state:
case refine'_1
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsDetecting (Set.op 𝒢)
X Y : C
f : X ⟶ Y
hf : ∀ G ∈ 𝒢, ∀ (h : X ⟶ G), ∃! h', f ≫ h' = h
⊢ IsIso f

Next tactic:
refine' (isIso_op_iff _).1 (h𝒢 _ fun G hG h => _)
theorem isDetecting_op_iff (𝒢 : Set C) : IsDetecting 𝒢.op ↔ IsCodetecting 𝒢 := by
  refine' ⟨fun h𝒢 X Y f hf => _, fun h𝒢 X Y f hf => _⟩
  · refine' (isIso_op_iff _).1 (h𝒢 _ fun G hG h => _)
    

Proof state:
case refine'_1
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsDetecting (Set.op 𝒢)
X Y : C
f : X ⟶ Y
hf : ∀ G ∈ 𝒢, ∀ (h : X ⟶ G), ∃! h', f ≫ h' = h
G : Cᵒᵖ
hG : G ∈ Set.op 𝒢
h : G ⟶ op X
⊢ ∃! h', h' ≫ f.op = h

Next tactic:
obtain ⟨t, ht, ht'⟩ := hf (unop G) (Set.mem_op.1 hG) h.unop
theorem isDetecting_op_iff (𝒢 : Set C) : IsDetecting 𝒢.op ↔ IsCodetecting 𝒢 := by
  refine' ⟨fun h𝒢 X Y f hf => _, fun h𝒢 X Y f hf => _⟩
  · refine' (isIso_op_iff _).1 (h𝒢 _ fun G hG h => _)
    obtain ⟨t, ht, ht'⟩ := hf (unop G) (Set.mem_op.1 hG) h.unop
    

Proof state:
case refine'_1.intro.intro
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsDetecting (Set.op 𝒢)
X Y : C
f : X ⟶ Y
hf : ∀ G ∈ 𝒢, ∀ (h : X ⟶ G), ∃! h', f ≫ h' = h
G : Cᵒᵖ
hG : G ∈ Set.op 𝒢
h : G ⟶ op X
t : Y ⟶ G.unop
ht : f ≫ t = h.unop
ht' : ∀ (y : Y ⟶ G.unop), (fun h' => f ≫ h' = h.unop) y → y = t
⊢ ∃! h', h' ≫ f.op = h

Next tactic:
exact
      ⟨t.op, Quiver.Hom.unop_inj ht, fun y hy => Quiver.Hom.unop_inj (ht' _ (Quiver.Hom.op_inj hy))⟩
theorem isDetecting_op_iff (𝒢 : Set C) : IsDetecting 𝒢.op ↔ IsCodetecting 𝒢 := by
  refine' ⟨fun h𝒢 X Y f hf => _, fun h𝒢 X Y f hf => _⟩
  · refine' (isIso_op_iff _).1 (h𝒢 _ fun G hG h => _)
    obtain ⟨t, ht, ht'⟩ := hf (unop G) (Set.mem_op.1 hG) h.unop
    exact
      ⟨t.op, Quiver.Hom.unop_inj ht, fun y hy => Quiver.Hom.unop_inj (ht' _ (Quiver.Hom.op_inj hy))⟩
  · 

Proof state:
case refine'_2
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsCodetecting 𝒢
X Y : Cᵒᵖ
f : X ⟶ Y
hf : ∀ G ∈ Set.op 𝒢, ∀ (h : G ⟶ Y), ∃! h', h' ≫ f = h
⊢ IsIso f

Next tactic:
refine' (isIso_unop_iff _).1 (h𝒢 _ fun G hG h => _)
theorem isDetecting_op_iff (𝒢 : Set C) : IsDetecting 𝒢.op ↔ IsCodetecting 𝒢 := by
  refine' ⟨fun h𝒢 X Y f hf => _, fun h𝒢 X Y f hf => _⟩
  · refine' (isIso_op_iff _).1 (h𝒢 _ fun G hG h => _)
    obtain ⟨t, ht, ht'⟩ := hf (unop G) (Set.mem_op.1 hG) h.unop
    exact
      ⟨t.op, Quiver.Hom.unop_inj ht, fun y hy => Quiver.Hom.unop_inj (ht' _ (Quiver.Hom.op_inj hy))⟩
  · refine' (isIso_unop_iff _).1 (h𝒢 _ fun G hG h => _)
    

Proof state:
case refine'_2
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsCodetecting 𝒢
X Y : Cᵒᵖ
f : X ⟶ Y
hf : ∀ G ∈ Set.op 𝒢, ∀ (h : G ⟶ Y), ∃! h', h' ≫ f = h
G : C
hG : G ∈ 𝒢
h : Y.unop ⟶ G
⊢ ∃! h', f.unop ≫ h' = h

Next tactic:
obtain ⟨t, ht, ht'⟩ := hf (op G) (Set.op_mem_op.2 hG) h.op
theorem isDetecting_op_iff (𝒢 : Set C) : IsDetecting 𝒢.op ↔ IsCodetecting 𝒢 := by
  refine' ⟨fun h𝒢 X Y f hf => _, fun h𝒢 X Y f hf => _⟩
  · refine' (isIso_op_iff _).1 (h𝒢 _ fun G hG h => _)
    obtain ⟨t, ht, ht'⟩ := hf (unop G) (Set.mem_op.1 hG) h.unop
    exact
      ⟨t.op, Quiver.Hom.unop_inj ht, fun y hy => Quiver.Hom.unop_inj (ht' _ (Quiver.Hom.op_inj hy))⟩
  · refine' (isIso_unop_iff _).1 (h𝒢 _ fun G hG h => _)
    obtain ⟨t, ht, ht'⟩ := hf (op G) (Set.op_mem_op.2 hG) h.op
    

Proof state:
case refine'_2.intro.intro
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsCodetecting 𝒢
X Y : Cᵒᵖ
f : X ⟶ Y
hf : ∀ G ∈ Set.op 𝒢, ∀ (h : G ⟶ Y), ∃! h', h' ≫ f = h
G : C
hG : G ∈ 𝒢
h : Y.unop ⟶ G
t : op G ⟶ X
ht : t ≫ f = h.op
ht' : ∀ (y : op G ⟶ X), (fun h' => h' ≫ f = h.op) y → y = t
⊢ ∃! h', f.unop ≫ h' = h

Next tactic:
refine' ⟨t.unop, Quiver.Hom.op_inj ht, fun y hy => Quiver.Hom.op_inj (ht' _ _)⟩
theorem isDetecting_op_iff (𝒢 : Set C) : IsDetecting 𝒢.op ↔ IsCodetecting 𝒢 := by
  refine' ⟨fun h𝒢 X Y f hf => _, fun h𝒢 X Y f hf => _⟩
  · refine' (isIso_op_iff _).1 (h𝒢 _ fun G hG h => _)
    obtain ⟨t, ht, ht'⟩ := hf (unop G) (Set.mem_op.1 hG) h.unop
    exact
      ⟨t.op, Quiver.Hom.unop_inj ht, fun y hy => Quiver.Hom.unop_inj (ht' _ (Quiver.Hom.op_inj hy))⟩
  · refine' (isIso_unop_iff _).1 (h𝒢 _ fun G hG h => _)
    obtain ⟨t, ht, ht'⟩ := hf (op G) (Set.op_mem_op.2 hG) h.op
    refine' ⟨t.unop, Quiver.Hom.op_inj ht, fun y hy => Quiver.Hom.op_inj (ht' _ _)⟩
    

Proof state:
case refine'_2.intro.intro
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsCodetecting 𝒢
X Y : Cᵒᵖ
f : X ⟶ Y
hf : ∀ G ∈ Set.op 𝒢, ∀ (h : G ⟶ Y), ∃! h', h' ≫ f = h
G : C
hG : G ∈ 𝒢
h : Y.unop ⟶ G
t : op G ⟶ X
ht : t ≫ f = h.op
ht' : ∀ (y : op G ⟶ X), (fun h' => h' ≫ f = h.op) y → y = t
y : X.unop ⟶ G
hy : (fun h' => f.unop ≫ h' = h) y
⊢ (fun h' => h' ≫ f = h.op) y.op

Next tactic:
exact Quiver.Hom.unop_inj (by simpa only using hy)
theorem isDetecting_op_iff (𝒢 : Set C) : IsDetecting 𝒢.op ↔ IsCodetecting 𝒢 := by
  refine' ⟨fun h𝒢 X Y f hf => _, fun h𝒢 X Y f hf => _⟩
  · refine' (isIso_op_iff _).1 (h𝒢 _ fun G hG h => _)
    obtain ⟨t, ht, ht'⟩ := hf (unop G) (Set.mem_op.1 hG) h.unop
    exact
      ⟨t.op, Quiver.Hom.unop_inj ht, fun y hy => Quiver.Hom.unop_inj (ht' _ (Quiver.Hom.op_inj hy))⟩
  · refine' (isIso_unop_iff _).1 (h𝒢 _ fun G hG h => _)
    obtain ⟨t, ht, ht'⟩ := hf (op G) (Set.op_mem_op.2 hG) h.op
    refine' ⟨t.unop, Quiver.Hom.op_inj ht, fun y hy => Quiver.Hom.op_inj (ht' _ _)⟩
    exact Quiver.Hom.unop_inj (by 

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsCodetecting 𝒢
X Y : Cᵒᵖ
f : X ⟶ Y
hf : ∀ G ∈ Set.op 𝒢, ∀ (h : G ⟶ Y), ∃! h', h' ≫ f = h
G : C
hG : G ∈ 𝒢
h : Y.unop ⟶ G
t : op G ⟶ X
ht : t ≫ f = h.op
ht' : ∀ (y : op G ⟶ X), (fun h' => h' ≫ f = h.op) y → y = t
y : X.unop ⟶ G
hy : (fun h' => f.unop ≫ h' = h) y
⊢ (y.op ≫ f).unop = h.op.unop

Next tactic:
simpa only using hy
theorem isCodetecting_op_iff (𝒢 : Set C) : IsCodetecting 𝒢.op ↔ IsDetecting 𝒢 := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
⊢ IsCodetecting (Set.op 𝒢) ↔ IsDetecting 𝒢

Next tactic:
refine' ⟨fun h𝒢 X Y f hf => _, fun h𝒢 X Y f hf => _⟩
theorem isCodetecting_op_iff (𝒢 : Set C) : IsCodetecting 𝒢.op ↔ IsDetecting 𝒢 := by
  refine' ⟨fun h𝒢 X Y f hf => _, fun h𝒢 X Y f hf => _⟩
  · 

Proof state:
case refine'_1
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsCodetecting (Set.op 𝒢)
X Y : C
f : X ⟶ Y
hf : ∀ G ∈ 𝒢, ∀ (h : G ⟶ Y), ∃! h', h' ≫ f = h
⊢ IsIso f

Next tactic:
refine' (isIso_op_iff _).1 (h𝒢 _ fun G hG h => _)
theorem isCodetecting_op_iff (𝒢 : Set C) : IsCodetecting 𝒢.op ↔ IsDetecting 𝒢 := by
  refine' ⟨fun h𝒢 X Y f hf => _, fun h𝒢 X Y f hf => _⟩
  · refine' (isIso_op_iff _).1 (h𝒢 _ fun G hG h => _)
    

Proof state:
case refine'_1
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsCodetecting (Set.op 𝒢)
X Y : C
f : X ⟶ Y
hf : ∀ G ∈ 𝒢, ∀ (h : G ⟶ Y), ∃! h', h' ≫ f = h
G : Cᵒᵖ
hG : G ∈ Set.op 𝒢
h : op Y ⟶ G
⊢ ∃! h', f.op ≫ h' = h

Next tactic:
obtain ⟨t, ht, ht'⟩ := hf (unop G) (Set.mem_op.1 hG) h.unop
theorem isCodetecting_op_iff (𝒢 : Set C) : IsCodetecting 𝒢.op ↔ IsDetecting 𝒢 := by
  refine' ⟨fun h𝒢 X Y f hf => _, fun h𝒢 X Y f hf => _⟩
  · refine' (isIso_op_iff _).1 (h𝒢 _ fun G hG h => _)
    obtain ⟨t, ht, ht'⟩ := hf (unop G) (Set.mem_op.1 hG) h.unop
    

Proof state:
case refine'_1.intro.intro
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsCodetecting (Set.op 𝒢)
X Y : C
f : X ⟶ Y
hf : ∀ G ∈ 𝒢, ∀ (h : G ⟶ Y), ∃! h', h' ≫ f = h
G : Cᵒᵖ
hG : G ∈ Set.op 𝒢
h : op Y ⟶ G
t : G.unop ⟶ X
ht : t ≫ f = h.unop
ht' : ∀ (y : G.unop ⟶ X), (fun h' => h' ≫ f = h.unop) y → y = t
⊢ ∃! h', f.op ≫ h' = h

Next tactic:
exact
      ⟨t.op, Quiver.Hom.unop_inj ht, fun y hy => Quiver.Hom.unop_inj (ht' _ (Quiver.Hom.op_inj hy))⟩
theorem isCodetecting_op_iff (𝒢 : Set C) : IsCodetecting 𝒢.op ↔ IsDetecting 𝒢 := by
  refine' ⟨fun h𝒢 X Y f hf => _, fun h𝒢 X Y f hf => _⟩
  · refine' (isIso_op_iff _).1 (h𝒢 _ fun G hG h => _)
    obtain ⟨t, ht, ht'⟩ := hf (unop G) (Set.mem_op.1 hG) h.unop
    exact
      ⟨t.op, Quiver.Hom.unop_inj ht, fun y hy => Quiver.Hom.unop_inj (ht' _ (Quiver.Hom.op_inj hy))⟩
  · 

Proof state:
case refine'_2
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsDetecting 𝒢
X Y : Cᵒᵖ
f : X ⟶ Y
hf : ∀ G ∈ Set.op 𝒢, ∀ (h : X ⟶ G), ∃! h', f ≫ h' = h
⊢ IsIso f

Next tactic:
refine' (isIso_unop_iff _).1 (h𝒢 _ fun G hG h => _)
theorem isCodetecting_op_iff (𝒢 : Set C) : IsCodetecting 𝒢.op ↔ IsDetecting 𝒢 := by
  refine' ⟨fun h𝒢 X Y f hf => _, fun h𝒢 X Y f hf => _⟩
  · refine' (isIso_op_iff _).1 (h𝒢 _ fun G hG h => _)
    obtain ⟨t, ht, ht'⟩ := hf (unop G) (Set.mem_op.1 hG) h.unop
    exact
      ⟨t.op, Quiver.Hom.unop_inj ht, fun y hy => Quiver.Hom.unop_inj (ht' _ (Quiver.Hom.op_inj hy))⟩
  · refine' (isIso_unop_iff _).1 (h𝒢 _ fun G hG h => _)
    

Proof state:
case refine'_2
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsDetecting 𝒢
X Y : Cᵒᵖ
f : X ⟶ Y
hf : ∀ G ∈ Set.op 𝒢, ∀ (h : X ⟶ G), ∃! h', f ≫ h' = h
G : C
hG : G ∈ 𝒢
h : G ⟶ X.unop
⊢ ∃! h', h' ≫ f.unop = h

Next tactic:
obtain ⟨t, ht, ht'⟩ := hf (op G) (Set.op_mem_op.2 hG) h.op
theorem isCodetecting_op_iff (𝒢 : Set C) : IsCodetecting 𝒢.op ↔ IsDetecting 𝒢 := by
  refine' ⟨fun h𝒢 X Y f hf => _, fun h𝒢 X Y f hf => _⟩
  · refine' (isIso_op_iff _).1 (h𝒢 _ fun G hG h => _)
    obtain ⟨t, ht, ht'⟩ := hf (unop G) (Set.mem_op.1 hG) h.unop
    exact
      ⟨t.op, Quiver.Hom.unop_inj ht, fun y hy => Quiver.Hom.unop_inj (ht' _ (Quiver.Hom.op_inj hy))⟩
  · refine' (isIso_unop_iff _).1 (h𝒢 _ fun G hG h => _)
    obtain ⟨t, ht, ht'⟩ := hf (op G) (Set.op_mem_op.2 hG) h.op
    

Proof state:
case refine'_2.intro.intro
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsDetecting 𝒢
X Y : Cᵒᵖ
f : X ⟶ Y
hf : ∀ G ∈ Set.op 𝒢, ∀ (h : X ⟶ G), ∃! h', f ≫ h' = h
G : C
hG : G ∈ 𝒢
h : G ⟶ X.unop
t : Y ⟶ op G
ht : f ≫ t = h.op
ht' : ∀ (y : Y ⟶ op G), (fun h' => f ≫ h' = h.op) y → y = t
⊢ ∃! h', h' ≫ f.unop = h

Next tactic:
refine' ⟨t.unop, Quiver.Hom.op_inj ht, fun y hy => Quiver.Hom.op_inj (ht' _ _)⟩
theorem isCodetecting_op_iff (𝒢 : Set C) : IsCodetecting 𝒢.op ↔ IsDetecting 𝒢 := by
  refine' ⟨fun h𝒢 X Y f hf => _, fun h𝒢 X Y f hf => _⟩
  · refine' (isIso_op_iff _).1 (h𝒢 _ fun G hG h => _)
    obtain ⟨t, ht, ht'⟩ := hf (unop G) (Set.mem_op.1 hG) h.unop
    exact
      ⟨t.op, Quiver.Hom.unop_inj ht, fun y hy => Quiver.Hom.unop_inj (ht' _ (Quiver.Hom.op_inj hy))⟩
  · refine' (isIso_unop_iff _).1 (h𝒢 _ fun G hG h => _)
    obtain ⟨t, ht, ht'⟩ := hf (op G) (Set.op_mem_op.2 hG) h.op
    refine' ⟨t.unop, Quiver.Hom.op_inj ht, fun y hy => Quiver.Hom.op_inj (ht' _ _)⟩
    

Proof state:
case refine'_2.intro.intro
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsDetecting 𝒢
X Y : Cᵒᵖ
f : X ⟶ Y
hf : ∀ G ∈ Set.op 𝒢, ∀ (h : X ⟶ G), ∃! h', f ≫ h' = h
G : C
hG : G ∈ 𝒢
h : G ⟶ X.unop
t : Y ⟶ op G
ht : f ≫ t = h.op
ht' : ∀ (y : Y ⟶ op G), (fun h' => f ≫ h' = h.op) y → y = t
y : G ⟶ Y.unop
hy : (fun h' => h' ≫ f.unop = h) y
⊢ (fun h' => f ≫ h' = h.op) y.op

Next tactic:
exact Quiver.Hom.unop_inj (by simpa only using hy)
theorem isCodetecting_op_iff (𝒢 : Set C) : IsCodetecting 𝒢.op ↔ IsDetecting 𝒢 := by
  refine' ⟨fun h𝒢 X Y f hf => _, fun h𝒢 X Y f hf => _⟩
  · refine' (isIso_op_iff _).1 (h𝒢 _ fun G hG h => _)
    obtain ⟨t, ht, ht'⟩ := hf (unop G) (Set.mem_op.1 hG) h.unop
    exact
      ⟨t.op, Quiver.Hom.unop_inj ht, fun y hy => Quiver.Hom.unop_inj (ht' _ (Quiver.Hom.op_inj hy))⟩
  · refine' (isIso_unop_iff _).1 (h𝒢 _ fun G hG h => _)
    obtain ⟨t, ht, ht'⟩ := hf (op G) (Set.op_mem_op.2 hG) h.op
    refine' ⟨t.unop, Quiver.Hom.op_inj ht, fun y hy => Quiver.Hom.op_inj (ht' _ _)⟩
    exact Quiver.Hom.unop_inj (by 

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsDetecting 𝒢
X Y : Cᵒᵖ
f : X ⟶ Y
hf : ∀ G ∈ Set.op 𝒢, ∀ (h : X ⟶ G), ∃! h', f ≫ h' = h
G : C
hG : G ∈ 𝒢
h : G ⟶ X.unop
t : Y ⟶ op G
ht : f ≫ t = h.op
ht' : ∀ (y : Y ⟶ op G), (fun h' => f ≫ h' = h.op) y → y = t
y : G ⟶ Y.unop
hy : (fun h' => h' ≫ f.unop = h) y
⊢ (f ≫ y.op).unop = h.op.unop

Next tactic:
simpa only using hy
theorem isDetecting_unop_iff (𝒢 : Set Cᵒᵖ) : IsDetecting 𝒢.unop ↔ IsCodetecting 𝒢 := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set Cᵒᵖ
⊢ IsDetecting (Set.unop 𝒢) ↔ IsCodetecting 𝒢

Next tactic:
rw [← isCodetecting_op_iff, Set.unop_op]
theorem isCodetecting_unop_iff {𝒢 : Set Cᵒᵖ} : IsCodetecting 𝒢.unop ↔ IsDetecting 𝒢 := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set Cᵒᵖ
⊢ IsCodetecting (Set.unop 𝒢) ↔ IsDetecting 𝒢

Next tactic:
rw [← isDetecting_op_iff, Set.unop_op]
theorem IsCodetecting.isCoseparating [HasCoequalizers C] {𝒢 : Set C} :
    IsCodetecting 𝒢 → IsCoseparating 𝒢 := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
inst✝ : HasCoequalizers C
𝒢 : Set C
⊢ IsCodetecting 𝒢 → IsCoseparating 𝒢

Next tactic:
simpa only [← isSeparating_op_iff, ← isDetecting_op_iff] using IsDetecting.isSeparating
theorem IsSeparating.isDetecting [Balanced C] {𝒢 : Set C} (h𝒢 : IsSeparating 𝒢) :
    IsDetecting 𝒢 := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
inst✝ : Balanced C
𝒢 : Set C
h𝒢 : IsSeparating 𝒢
⊢ IsDetecting 𝒢

Next tactic:
intro X Y f hf
theorem IsSeparating.isDetecting [Balanced C] {𝒢 : Set C} (h𝒢 : IsSeparating 𝒢) :
    IsDetecting 𝒢 := by
  intro X Y f hf
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
inst✝ : Balanced C
𝒢 : Set C
h𝒢 : IsSeparating 𝒢
X Y : C
f : X ⟶ Y
hf : ∀ G ∈ 𝒢, ∀ (h : G ⟶ Y), ∃! h', h' ≫ f = h
⊢ IsIso f

Next tactic:
refine'
    (isIso_iff_mono_and_epi _).2 ⟨⟨fun g h hgh => h𝒢 _ _ fun G hG i => _⟩, ⟨fun g h hgh => _⟩⟩
theorem IsSeparating.isDetecting [Balanced C] {𝒢 : Set C} (h𝒢 : IsSeparating 𝒢) :
    IsDetecting 𝒢 := by
  intro X Y f hf
  refine'
    (isIso_iff_mono_and_epi _).2 ⟨⟨fun g h hgh => h𝒢 _ _ fun G hG i => _⟩, ⟨fun g h hgh => _⟩⟩
  · 

Proof state:
case refine'_1
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
inst✝ : Balanced C
𝒢 : Set C
h𝒢 : IsSeparating 𝒢
X Y : C
f : X ⟶ Y
hf : ∀ G ∈ 𝒢, ∀ (h : G ⟶ Y), ∃! h', h' ≫ f = h
Z✝ : C
g h : Z✝ ⟶ X
hgh : g ≫ f = h ≫ f
G : C
hG : G ∈ 𝒢
i : G ⟶ Z✝
⊢ i ≫ g = i ≫ h

Next tactic:
obtain ⟨t, -, ht⟩ := hf G hG (i ≫ g ≫ f)
theorem IsSeparating.isDetecting [Balanced C] {𝒢 : Set C} (h𝒢 : IsSeparating 𝒢) :
    IsDetecting 𝒢 := by
  intro X Y f hf
  refine'
    (isIso_iff_mono_and_epi _).2 ⟨⟨fun g h hgh => h𝒢 _ _ fun G hG i => _⟩, ⟨fun g h hgh => _⟩⟩
  · obtain ⟨t, -, ht⟩ := hf G hG (i ≫ g ≫ f)
    

Proof state:
case refine'_1.intro.intro
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
inst✝ : Balanced C
𝒢 : Set C
h𝒢 : IsSeparating 𝒢
X Y : C
f : X ⟶ Y
hf : ∀ G ∈ 𝒢, ∀ (h : G ⟶ Y), ∃! h', h' ≫ f = h
Z✝ : C
g h : Z✝ ⟶ X
hgh : g ≫ f = h ≫ f
G : C
hG : G ∈ 𝒢
i : G ⟶ Z✝
t : G ⟶ X
ht : ∀ (y : G ⟶ X), (fun h' => h' ≫ f = i ≫ g ≫ f) y → y = t
⊢ i ≫ g = i ≫ h

Next tactic:
rw [ht (i ≫ g) (Category.assoc _ _ _), ht (i ≫ h) (hgh.symm ▸ Category.assoc _ _ _)]
theorem IsSeparating.isDetecting [Balanced C] {𝒢 : Set C} (h𝒢 : IsSeparating 𝒢) :
    IsDetecting 𝒢 := by
  intro X Y f hf
  refine'
    (isIso_iff_mono_and_epi _).2 ⟨⟨fun g h hgh => h𝒢 _ _ fun G hG i => _⟩, ⟨fun g h hgh => _⟩⟩
  · obtain ⟨t, -, ht⟩ := hf G hG (i ≫ g ≫ f)
    rw [ht (i ≫ g) (Category.assoc _ _ _), ht (i ≫ h) (hgh.symm ▸ Category.assoc _ _ _)]
  · 

Proof state:
case refine'_2
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
inst✝ : Balanced C
𝒢 : Set C
h𝒢 : IsSeparating 𝒢
X Y : C
f : X ⟶ Y
hf : ∀ G ∈ 𝒢, ∀ (h : G ⟶ Y), ∃! h', h' ≫ f = h
Z✝ : C
g h : Y ⟶ Z✝
hgh : f ≫ g = f ≫ h
⊢ g = h

Next tactic:
refine' h𝒢 _ _ fun G hG i => _
theorem IsSeparating.isDetecting [Balanced C] {𝒢 : Set C} (h𝒢 : IsSeparating 𝒢) :
    IsDetecting 𝒢 := by
  intro X Y f hf
  refine'
    (isIso_iff_mono_and_epi _).2 ⟨⟨fun g h hgh => h𝒢 _ _ fun G hG i => _⟩, ⟨fun g h hgh => _⟩⟩
  · obtain ⟨t, -, ht⟩ := hf G hG (i ≫ g ≫ f)
    rw [ht (i ≫ g) (Category.assoc _ _ _), ht (i ≫ h) (hgh.symm ▸ Category.assoc _ _ _)]
  · refine' h𝒢 _ _ fun G hG i => _
    

Proof state:
case refine'_2
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
inst✝ : Balanced C
𝒢 : Set C
h𝒢 : IsSeparating 𝒢
X Y : C
f : X ⟶ Y
hf : ∀ G ∈ 𝒢, ∀ (h : G ⟶ Y), ∃! h', h' ≫ f = h
Z✝ : C
g h : Y ⟶ Z✝
hgh : f ≫ g = f ≫ h
G : C
hG : G ∈ 𝒢
i : G ⟶ Y
⊢ i ≫ g = i ≫ h

Next tactic:
obtain ⟨t, rfl, -⟩ := hf G hG i
theorem IsSeparating.isDetecting [Balanced C] {𝒢 : Set C} (h𝒢 : IsSeparating 𝒢) :
    IsDetecting 𝒢 := by
  intro X Y f hf
  refine'
    (isIso_iff_mono_and_epi _).2 ⟨⟨fun g h hgh => h𝒢 _ _ fun G hG i => _⟩, ⟨fun g h hgh => _⟩⟩
  · obtain ⟨t, -, ht⟩ := hf G hG (i ≫ g ≫ f)
    rw [ht (i ≫ g) (Category.assoc _ _ _), ht (i ≫ h) (hgh.symm ▸ Category.assoc _ _ _)]
  · refine' h𝒢 _ _ fun G hG i => _
    obtain ⟨t, rfl, -⟩ := hf G hG i
    

Proof state:
case refine'_2.intro.intro
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
inst✝ : Balanced C
𝒢 : Set C
h𝒢 : IsSeparating 𝒢
X Y : C
f : X ⟶ Y
hf : ∀ G ∈ 𝒢, ∀ (h : G ⟶ Y), ∃! h', h' ≫ f = h
Z✝ : C
g h : Y ⟶ Z✝
hgh : f ≫ g = f ≫ h
G : C
hG : G ∈ 𝒢
t : G ⟶ X
⊢ (t ≫ f) ≫ g = (t ≫ f) ≫ h

Next tactic:
rw [Category.assoc, hgh, Category.assoc]
theorem IsCoseparating.isCodetecting [Balanced C] {𝒢 : Set C} :
    IsCoseparating 𝒢 → IsCodetecting 𝒢 := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
inst✝ : Balanced C
𝒢 : Set C
⊢ IsCoseparating 𝒢 → IsCodetecting 𝒢

Next tactic:
simpa only [← isDetecting_op_iff, ← isSeparating_op_iff] using IsSeparating.isDetecting
theorem isSeparating_iff_epi (𝒢 : Set C)
    [∀ A : C, HasCoproduct fun f : ΣG : 𝒢, (G : C) ⟶ A => (f.1 : C)] :
    IsSeparating 𝒢 ↔ ∀ A : C, Epi (Sigma.desc (@Sigma.snd 𝒢 fun G => (G : C) ⟶ A)) := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
𝒢 : Set C
inst✝ : ∀ (A : C), HasCoproduct fun f => ↑f.fst
⊢ IsSeparating 𝒢 ↔ ∀ (A : C), Epi (Sigma.desc Sigma.snd)

Next tactic:
refine' ⟨fun h A => ⟨fun u v huv => h _ _ fun G hG f => _⟩, fun h X Y f g hh => _⟩
theorem isSeparating_iff_epi (𝒢 : Set C)
    [∀ A : C, HasCoproduct fun f : ΣG : 𝒢, (G : C) ⟶ A => (f.1 : C)] :
    IsSeparating 𝒢 ↔ ∀ A : C, Epi (Sigma.desc (@Sigma.snd 𝒢 fun G => (G : C) ⟶ A)) := by
  refine' ⟨fun h A => ⟨fun u v huv => h _ _ fun G hG f => _⟩, fun h X Y f g hh => _⟩
  · 

Proof state:
case refine'_1
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
𝒢 : Set C
inst✝ : ∀ (A : C), HasCoproduct fun f => ↑f.fst
h : IsSeparating 𝒢
A Z✝ : C
u v : A ⟶ Z✝
huv : Sigma.desc Sigma.snd ≫ u = Sigma.desc Sigma.snd ≫ v
G : C
hG : G ∈ 𝒢
f : G ⟶ A
⊢ f ≫ u = f ≫ v

Next tactic:
simpa using Sigma.ι (fun f : ΣG : 𝒢, (G : C) ⟶ A => (f.1 : C)) ⟨⟨G, hG⟩, f⟩ ≫= huv
theorem isSeparating_iff_epi (𝒢 : Set C)
    [∀ A : C, HasCoproduct fun f : ΣG : 𝒢, (G : C) ⟶ A => (f.1 : C)] :
    IsSeparating 𝒢 ↔ ∀ A : C, Epi (Sigma.desc (@Sigma.snd 𝒢 fun G => (G : C) ⟶ A)) := by
  refine' ⟨fun h A => ⟨fun u v huv => h _ _ fun G hG f => _⟩, fun h X Y f g hh => _⟩
  · simpa using Sigma.ι (fun f : ΣG : 𝒢, (G : C) ⟶ A => (f.1 : C)) ⟨⟨G, hG⟩, f⟩ ≫= huv
  · 

Proof state:
case refine'_2
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
𝒢 : Set C
inst✝ : ∀ (A : C), HasCoproduct fun f => ↑f.fst
h : ∀ (A : C), Epi (Sigma.desc Sigma.snd)
X Y : C
f g : X ⟶ Y
hh : ∀ G ∈ 𝒢, ∀ (h : G ⟶ X), h ≫ f = h ≫ g
⊢ f = g

Next tactic:
haveI := h X
theorem isSeparating_iff_epi (𝒢 : Set C)
    [∀ A : C, HasCoproduct fun f : ΣG : 𝒢, (G : C) ⟶ A => (f.1 : C)] :
    IsSeparating 𝒢 ↔ ∀ A : C, Epi (Sigma.desc (@Sigma.snd 𝒢 fun G => (G : C) ⟶ A)) := by
  refine' ⟨fun h A => ⟨fun u v huv => h _ _ fun G hG f => _⟩, fun h X Y f g hh => _⟩
  · simpa using Sigma.ι (fun f : ΣG : 𝒢, (G : C) ⟶ A => (f.1 : C)) ⟨⟨G, hG⟩, f⟩ ≫= huv
  · haveI := h X
    

Proof state:
case refine'_2
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
𝒢 : Set C
inst✝ : ∀ (A : C), HasCoproduct fun f => ↑f.fst
h : ∀ (A : C), Epi (Sigma.desc Sigma.snd)
X Y : C
f g : X ⟶ Y
hh : ∀ G ∈ 𝒢, ∀ (h : G ⟶ X), h ≫ f = h ≫ g
this : Epi (Sigma.desc Sigma.snd)
⊢ f = g

Next tactic:
refine'
      (cancel_epi (Sigma.desc (@Sigma.snd 𝒢 fun G => (G : C) ⟶ X))).1 (colimit.hom_ext fun j => _)