l3lab/ntp-mathlib huggingface dataset:
theorem isCountablyGenerated_iff_exists_antitone_basis {f : Filter α} :
    IsCountablyGenerated f ↔ ∃ x : ℕ → Set α, f.HasAntitoneBasis x := by
  constructor
  · intro h
    exact f.exists_antitone_basis
  · rintro ⟨x, h⟩
    

Proof state:
case mpr.intro
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Type u_4
ι' : Sort u_5
f : Filter α
x : ℕ → Set α
h : HasAntitoneBasis f x
⊢ IsCountablyGenerated f

Next tactic:
rw [h.1.eq_iInf]
theorem isCountablyGenerated_iff_exists_antitone_basis {f : Filter α} :
    IsCountablyGenerated f ↔ ∃ x : ℕ → Set α, f.HasAntitoneBasis x := by
  constructor
  · intro h
    exact f.exists_antitone_basis
  · rintro ⟨x, h⟩
    rw [h.1.eq_iInf]
    

Proof state:
case mpr.intro
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Type u_4
ι' : Sort u_5
f : Filter α
x : ℕ → Set α
h : HasAntitoneBasis f x
⊢ IsCountablyGenerated (⨅ i, 𝓟 (x i))

Next tactic:
exact isCountablyGenerated_seq x
@[instance]
theorem isCountablyGenerated_pure (a : α) : IsCountablyGenerated (pure a) := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Type u_4
ι' : Sort u_5
a : α
⊢ IsCountablyGenerated (pure a)

Next tactic:
rw [← principal_singleton]
@[instance]
theorem isCountablyGenerated_pure (a : α) : IsCountablyGenerated (pure a) := by
  rw [← principal_singleton]
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Type u_4
ι' : Sort u_5
a : α
⊢ IsCountablyGenerated (𝓟 {a})

Next tactic:
exact isCountablyGenerated_principal _
instance iInf.isCountablyGenerated {ι : Sort u} {α : Type v} [Countable ι] (f : ι → Filter α)
    [∀ i, IsCountablyGenerated (f i)] : IsCountablyGenerated (⨅ i, f i) := by
  

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
ι✝ : Type u_4
ι' : Sort u_5
ι : Sort u
α : Type v
inst✝¹ : Countable ι
f : ι → Filter α
inst✝ : ∀ (i : ι), IsCountablyGenerated (f i)
⊢ IsCountablyGenerated (⨅ i, f i)

Next tactic:
choose s hs using fun i => exists_antitone_basis (f i)
instance iInf.isCountablyGenerated {ι : Sort u} {α : Type v} [Countable ι] (f : ι → Filter α)
    [∀ i, IsCountablyGenerated (f i)] : IsCountablyGenerated (⨅ i, f i) := by
  choose s hs using fun i => exists_antitone_basis (f i)
  

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
ι✝ : Type u_4
ι' : Sort u_5
ι : Sort u
α : Type v
inst✝¹ : Countable ι
f : ι → Filter α
inst✝ : ∀ (i : ι), IsCountablyGenerated (f i)
s : ι → ℕ → Set α
hs : ∀ (i : ι), HasAntitoneBasis (f i) (s i)
⊢ IsCountablyGenerated (⨅ i, f i)

Next tactic:
rw [← PLift.down_surjective.iInf_comp]
instance iInf.isCountablyGenerated {ι : Sort u} {α : Type v} [Countable ι] (f : ι → Filter α)
    [∀ i, IsCountablyGenerated (f i)] : IsCountablyGenerated (⨅ i, f i) := by
  choose s hs using fun i => exists_antitone_basis (f i)
  rw [← PLift.down_surjective.iInf_comp]
  

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
ι✝ : Type u_4
ι' : Sort u_5
ι : Sort u
α : Type v
inst✝¹ : Countable ι
f : ι → Filter α
inst✝ : ∀ (i : ι), IsCountablyGenerated (f i)
s : ι → ℕ → Set α
hs : ∀ (i : ι), HasAntitoneBasis (f i) (s i)
⊢ IsCountablyGenerated (⨅ x, f x.down)

Next tactic:
refine' HasCountableBasis.isCountablyGenerated ⟨hasBasis_iInf fun n => (hs _).1, _⟩
instance iInf.isCountablyGenerated {ι : Sort u} {α : Type v} [Countable ι] (f : ι → Filter α)
    [∀ i, IsCountablyGenerated (f i)] : IsCountablyGenerated (⨅ i, f i) := by
  choose s hs using fun i => exists_antitone_basis (f i)
  rw [← PLift.down_surjective.iInf_comp]
  refine' HasCountableBasis.isCountablyGenerated ⟨hasBasis_iInf fun n => (hs _).1, _⟩
  

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
ι✝ : Type u_4
ι' : Sort u_5
ι : Sort u
α : Type v
inst✝¹ : Countable ι
f : ι → Filter α
inst✝ : ∀ (i : ι), IsCountablyGenerated (f i)
s : ι → ℕ → Set α
hs : ∀ (i : ι), HasAntitoneBasis (f i) (s i)
⊢ Set.Countable {If | Set.Finite If.fst ∧ (↑If.fst → True)}

Next tactic:
refine' (countable_range <| Sigma.map ((↑) : Finset (PLift ι) → Set (PLift ι)) fun _ => id).mono _
instance iInf.isCountablyGenerated {ι : Sort u} {α : Type v} [Countable ι] (f : ι → Filter α)
    [∀ i, IsCountablyGenerated (f i)] : IsCountablyGenerated (⨅ i, f i) := by
  choose s hs using fun i => exists_antitone_basis (f i)
  rw [← PLift.down_surjective.iInf_comp]
  refine' HasCountableBasis.isCountablyGenerated ⟨hasBasis_iInf fun n => (hs _).1, _⟩
  refine' (countable_range <| Sigma.map ((↑) : Finset (PLift ι) → Set (PLift ι)) fun _ => id).mono _
  

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
ι✝ : Type u_4
ι' : Sort u_5
ι : Sort u
α : Type v
inst✝¹ : Countable ι
f : ι → Filter α
inst✝ : ∀ (i : ι), IsCountablyGenerated (f i)
s : ι → ℕ → Set α
hs : ∀ (i : ι), HasAntitoneBasis (f i) (s i)
⊢ {If | Set.Finite If.fst ∧ (↑If.fst → True)} ⊆ range (Sigma.map Finset.toSet fun x => id)

Next tactic:
rintro ⟨I, f⟩ ⟨hI, -⟩
instance iInf.isCountablyGenerated {ι : Sort u} {α : Type v} [Countable ι] (f : ι → Filter α)
    [∀ i, IsCountablyGenerated (f i)] : IsCountablyGenerated (⨅ i, f i) := by
  choose s hs using fun i => exists_antitone_basis (f i)
  rw [← PLift.down_surjective.iInf_comp]
  refine' HasCountableBasis.isCountablyGenerated ⟨hasBasis_iInf fun n => (hs _).1, _⟩
  refine' (countable_range <| Sigma.map ((↑) : Finset (PLift ι) → Set (PLift ι)) fun _ => id).mono _
  rintro ⟨I, f⟩ ⟨hI, -⟩
  

Proof state:
case mk.intro
α✝ : Type u_1
β : Type u_2
γ : Type u_3
ι✝ : Type u_4
ι' : Sort u_5
ι : Sort u
α : Type v
inst✝¹ : Countable ι
f✝ : ι → Filter α
inst✝ : ∀ (i : ι), IsCountablyGenerated (f✝ i)
s : ι → ℕ → Set α
hs : ∀ (i : ι), HasAntitoneBasis (f✝ i) (s i)
I : Set (PLift ι)
f : ↑I → ℕ
hI : Set.Finite { fst := I, snd := f }.fst
⊢ { fst := I, snd := f } ∈ range (Sigma.map Finset.toSet fun x => id)

Next tactic:
lift I to Finset (PLift ι) using hI
instance iInf.isCountablyGenerated {ι : Sort u} {α : Type v} [Countable ι] (f : ι → Filter α)
    [∀ i, IsCountablyGenerated (f i)] : IsCountablyGenerated (⨅ i, f i) := by
  choose s hs using fun i => exists_antitone_basis (f i)
  rw [← PLift.down_surjective.iInf_comp]
  refine' HasCountableBasis.isCountablyGenerated ⟨hasBasis_iInf fun n => (hs _).1, _⟩
  refine' (countable_range <| Sigma.map ((↑) : Finset (PLift ι) → Set (PLift ι)) fun _ => id).mono _
  rintro ⟨I, f⟩ ⟨hI, -⟩
  lift I to Finset (PLift ι) using hI
  

Proof state:
case mk.intro.intro
α✝ : Type u_1
β : Type u_2
γ : Type u_3
ι✝ : Type u_4
ι' : Sort u_5
ι : Sort u
α : Type v
inst✝¹ : Countable ι
f✝ : ι → Filter α
inst✝ : ∀ (i : ι), IsCountablyGenerated (f✝ i)
s : ι → ℕ → Set α
hs : ∀ (i : ι), HasAntitoneBasis (f✝ i) (s i)
I : Finset (PLift ι)
f : ↑↑I → ℕ
⊢ { fst := ↑I, snd := f } ∈ range (Sigma.map Finset.toSet fun x => id)

Next tactic:
exact ⟨⟨I, f⟩, rfl⟩
@[higher_order fst_comp_fst]
theorem comp_fst {α₀ α₁ α₂ β} (f : α₀ → α₁) (f' : α₁ → α₂) (x : F α₀ β) :
    fst f' (fst f x) = fst (f' ∘ f) x := by 

Proof state:
F : Type u₀ → Type u₁ → Type u₂
inst✝¹ : Bifunctor F
inst✝ : LawfulBifunctor F
α₀ α₁ α₂ : Type u₀
β : Type u₁
f : α₀ → α₁
f' : α₁ → α₂
x : F α₀ β
⊢ fst f' (fst f x) = fst (f' ∘ f) x

Next tactic:
simp [fst, bimap_bimap]
@[higher_order fst_comp_snd]
theorem fst_snd {α₀ α₁ β₀ β₁} (f : α₀ → α₁) (f' : β₀ → β₁) (x : F α₀ β₀) :
    fst f (snd f' x) = bimap f f' x := by 

Proof state:
F : Type u₀ → Type u₁ → Type u₂
inst✝¹ : Bifunctor F
inst✝ : LawfulBifunctor F
α₀ α₁ : Type u₀
β₀ β₁ : Type u₁
f : α₀ → α₁
f' : β₀ → β₁
x : F α₀ β₀
⊢ fst f (snd f' x) = bimap f f' x

Next tactic:
simp [fst, bimap_bimap]
@[higher_order snd_comp_fst]
theorem snd_fst {α₀ α₁ β₀ β₁} (f : α₀ → α₁) (f' : β₀ → β₁) (x : F α₀ β₀) :
    snd f' (fst f x) = bimap f f' x := by 

Proof state:
F : Type u₀ → Type u₁ → Type u₂
inst✝¹ : Bifunctor F
inst✝ : LawfulBifunctor F
α₀ α₁ : Type u₀
β₀ β₁ : Type u₁
f : α₀ → α₁
f' : β₀ → β₁
x : F α₀ β₀
⊢ snd f' (fst f x) = bimap f f' x

Next tactic:
simp [snd, bimap_bimap]
@[higher_order snd_comp_snd]
theorem comp_snd {α β₀ β₁ β₂} (g : β₀ → β₁) (g' : β₁ → β₂) (x : F α β₀) :
    snd g' (snd g x) = snd (g' ∘ g) x := by 

Proof state:
F : Type u₀ → Type u₁ → Type u₂
inst✝¹ : Bifunctor F
inst✝ : LawfulBifunctor F
α : Type u₀
β₀ β₁ β₂ : Type u₁
g : β₀ → β₁
g' : β₁ → β₂
x : F α β₀
⊢ snd g' (snd g x) = snd (g' ∘ g) x

Next tactic:
simp [snd, bimap_bimap]
instance Prod.lawfulBifunctor : LawfulBifunctor Prod := by
  

Proof state:
F : Type u₀ → Type u₁ → Type u₂
inst✝ : Bifunctor F
⊢ LawfulBifunctor Prod

Next tactic:
refine' { .. }
instance Prod.lawfulBifunctor : LawfulBifunctor Prod := by
  refine' { .. } <;> 

Proof state:
case refine'_1
F : Type u₀ → Type u₁ → Type u₂
inst✝ : Bifunctor F
⊢ ∀ {α : Type ?u.3863} {β : Type ?u.3862} (x : α × β), bimap id id x = x

Next tactic:
intros
instance Prod.lawfulBifunctor : LawfulBifunctor Prod := by
  refine' { .. } <;> 

Proof state:
case refine'_2
F : Type u₀ → Type u₁ → Type u₂
inst✝ : Bifunctor F
⊢ ∀ {α₀ α₁ α₂ : Type ?u.3863} {β₀ β₁ β₂ : Type ?u.3862} (f : α₀ → α₁) (f' : α₁ → α₂) (g : β₀ → β₁) (g' : β₁ → β₂)
    (x : α₀ × β₀), bimap f' g' (bimap f g x) = bimap (f' ∘ f) (g' ∘ g) x

Next tactic:
intros
instance Prod.lawfulBifunctor : LawfulBifunctor Prod := by
  refine' { .. } <;> intros <;> 

Proof state:
case refine'_1
F : Type u₀ → Type u₁ → Type u₂
inst✝ : Bifunctor F
α✝ : Type ?u.3863
β✝ : Type ?u.3862
x✝ : α✝ × β✝
⊢ bimap id id x✝ = x✝

Next tactic:
rfl
instance Prod.lawfulBifunctor : LawfulBifunctor Prod := by
  refine' { .. } <;> intros <;> 

Proof state:
case refine'_2
F : Type u₀ → Type u₁ → Type u₂
inst✝ : Bifunctor F
α₀✝ α₁✝ α₂✝ : Type ?u.3863
β₀✝ β₁✝ β₂✝ : Type ?u.3862
f✝ : α₀✝ → α₁✝
f'✝ : α₁✝ → α₂✝
g✝ : β₀✝ → β₁✝
g'✝ : β₁✝ → β₂✝
x✝ : α₀✝ × β₀✝
⊢ bimap f'✝ g'✝ (bimap f✝ g✝ x✝) = bimap (f'✝ ∘ f✝) (g'✝ ∘ g✝) x✝

Next tactic:
rfl
instance LawfulBifunctor.const : LawfulBifunctor Const := by 

Proof state:
F : Type u₀ → Type u₁ → Type u₂
inst✝ : Bifunctor F
⊢ LawfulBifunctor Const

Next tactic:
refine' { .. }
instance LawfulBifunctor.const : LawfulBifunctor Const := by refine' { .. } <;> 

Proof state:
case refine'_1
F : Type u₀ → Type u₁ → Type u₂
inst✝ : Bifunctor F
⊢ ∀ {α : Type ?u.4164} {β : Type ?u.4165} (x : Const α β), bimap id id x = x

Next tactic:
intros
instance LawfulBifunctor.const : LawfulBifunctor Const := by refine' { .. } <;> 

Proof state:
case refine'_2
F : Type u₀ → Type u₁ → Type u₂
inst✝ : Bifunctor F
⊢ ∀ {α₀ α₁ α₂ : Type ?u.4164} {β₀ β₁ β₂ : Type ?u.4165} (f : α₀ → α₁) (f' : α₁ → α₂) (g : β₀ → β₁) (g' : β₁ → β₂)
    (x : Const α₀ β₀), bimap f' g' (bimap f g x) = bimap (f' ∘ f) (g' ∘ g) x

Next tactic:
intros
instance LawfulBifunctor.const : LawfulBifunctor Const := by refine' { .. } <;> intros <;> 

Proof state:
case refine'_1
F : Type u₀ → Type u₁ → Type u₂
inst✝ : Bifunctor F
α✝ : Type ?u.4164
β✝ : Type ?u.4165
x✝ : Const α✝ β✝
⊢ bimap id id x✝ = x✝

Next tactic:
rfl
instance LawfulBifunctor.const : LawfulBifunctor Const := by refine' { .. } <;> intros <;> 

Proof state:
case refine'_2
F : Type u₀ → Type u₁ → Type u₂
inst✝ : Bifunctor F
α₀✝ α₁✝ α₂✝ : Type ?u.4164
β₀✝ β₁✝ β₂✝ : Type ?u.4165
f✝ : α₀✝ → α₁✝
f'✝ : α₁✝ → α₂✝
g✝ : β₀✝ → β₁✝
g'✝ : β₁✝ → β₂✝
x✝ : Const α₀✝ β₀✝
⊢ bimap f'✝ g'✝ (bimap f✝ g✝ x✝) = bimap (f'✝ ∘ f✝) (g'✝ ∘ g✝) x✝

Next tactic:
rfl
instance LawfulBifunctor.flip [LawfulBifunctor F] : LawfulBifunctor (flip F) := by
  

Proof state:
F : Type u₀ → Type u₁ → Type u₂
inst✝¹ : Bifunctor F
inst✝ : LawfulBifunctor F
⊢ LawfulBifunctor (_root_.flip F)

Next tactic:
refine' { .. }
instance LawfulBifunctor.flip [LawfulBifunctor F] : LawfulBifunctor (flip F) := by
  refine' { .. } <;> 

Proof state:
case refine'_1
F : Type u₀ → Type u₁ → Type u₂
inst✝¹ : Bifunctor F
inst✝ : LawfulBifunctor F
⊢ ∀ {α : Type u₁} {β : Type u₀} (x : _root_.flip F α β), bimap id id x = x

Next tactic:
intros
instance LawfulBifunctor.flip [LawfulBifunctor F] : LawfulBifunctor (flip F) := by
  refine' { .. } <;> 

Proof state:
case refine'_2
F : Type u₀ → Type u₁ → Type u₂
inst✝¹ : Bifunctor F
inst✝ : LawfulBifunctor F
⊢ ∀ {α₀ α₁ α₂ : Type u₁} {β₀ β₁ β₂ : Type u₀} (f : α₀ → α₁) (f' : α₁ → α₂) (g : β₀ → β₁) (g' : β₁ → β₂)
    (x : _root_.flip F α₀ β₀), bimap f' g' (bimap f g x) = bimap (f' ∘ f) (g' ∘ g) x

Next tactic:
intros
instance LawfulBifunctor.flip [LawfulBifunctor F] : LawfulBifunctor (flip F) := by
  refine' { .. } <;> intros <;> 

Proof state:
case refine'_1
F : Type u₀ → Type u₁ → Type u₂
inst✝¹ : Bifunctor F
inst✝ : LawfulBifunctor F
α✝ : Type u₁
β✝ : Type u₀
x✝ : _root_.flip F α✝ β✝
⊢ bimap id id x✝ = x✝

Next tactic:
simp [bimap, functor_norm]
instance LawfulBifunctor.flip [LawfulBifunctor F] : LawfulBifunctor (flip F) := by
  refine' { .. } <;> intros <;> 

Proof state:
case refine'_2
F : Type u₀ → Type u₁ → Type u₂
inst✝¹ : Bifunctor F
inst✝ : LawfulBifunctor F
α₀✝ α₁✝ α₂✝ : Type u₁
β₀✝ β₁✝ β₂✝ : Type u₀
f✝ : α₀✝ → α₁✝
f'✝ : α₁✝ → α₂✝
g✝ : β₀✝ → β₁✝
g'✝ : β₁✝ → β₂✝
x✝ : _root_.flip F α₀✝ β₀✝
⊢ bimap f'✝ g'✝ (bimap f✝ g✝ x✝) = bimap (f'✝ ∘ f✝) (g'✝ ∘ g✝) x✝

Next tactic:
simp [bimap, functor_norm]
instance Sum.lawfulBifunctor : LawfulBifunctor Sum := by
  

Proof state:
F : Type u₀ → Type u₁ → Type u₂
inst✝ : Bifunctor F
⊢ LawfulBifunctor Sum

Next tactic:
refine' { .. }
instance Sum.lawfulBifunctor : LawfulBifunctor Sum := by
  refine' { .. } <;> 

Proof state:
case refine'_1
F : Type u₀ → Type u₁ → Type u₂
inst✝ : Bifunctor F
⊢ ∀ {α : Type ?u.4972} {β : Type ?u.4971} (x : α ⊕ β), bimap id id x = x

Next tactic:
aesop
instance Sum.lawfulBifunctor : LawfulBifunctor Sum := by
  refine' { .. } <;> 

Proof state:
case refine'_2
F : Type u₀ → Type u₁ → Type u₂
inst✝ : Bifunctor F
⊢ ∀ {α₀ α₁ α₂ : Type ?u.4972} {β₀ β₁ β₂ : Type ?u.4971} (f : α₀ → α₁) (f' : α₁ → α₂) (g : β₀ → β₁) (g' : β₁ → β₂)
    (x : α₀ ⊕ β₀), bimap f' g' (bimap f g x) = bimap (f' ∘ f) (g' ∘ g) x

Next tactic:
aesop
instance (priority := 10) Bifunctor.lawfulFunctor [LawfulBifunctor F] {α} : LawfulFunctor (F α) :=
  -- Porting note: `mapConst` is required to prove new theorem
  by 

Proof state:
F : Type u₀ → Type u₁ → Type u₂
inst✝¹ : Bifunctor F
inst✝ : LawfulBifunctor F
α : Type u₀
⊢ LawfulFunctor (F α)

Next tactic:
refine' { .. }
instance (priority := 10) Bifunctor.lawfulFunctor [LawfulBifunctor F] {α} : LawfulFunctor (F α) :=
  -- Porting note: `mapConst` is required to prove new theorem
  by refine' { .. } <;> 

Proof state:
case refine'_1
F : Type u₀ → Type u₁ → Type u₂
inst✝¹ : Bifunctor F
inst✝ : LawfulBifunctor F
α : Type u₀
⊢ ∀ {α_1 β : Type u₁}, mapConst = map ∘ Function.const β

Next tactic:
intros
instance (priority := 10) Bifunctor.lawfulFunctor [LawfulBifunctor F] {α} : LawfulFunctor (F α) :=
  -- Porting note: `mapConst` is required to prove new theorem
  by refine' { .. } <;> 

Proof state:
case refine'_2
F : Type u₀ → Type u₁ → Type u₂
inst✝¹ : Bifunctor F
inst✝ : LawfulBifunctor F
α : Type u₀
⊢ ∀ {α_1 : Type u₁} (x : F α α_1), id <$> x = x

Next tactic:
intros
instance (priority := 10) Bifunctor.lawfulFunctor [LawfulBifunctor F] {α} : LawfulFunctor (F α) :=
  -- Porting note: `mapConst` is required to prove new theorem
  by refine' { .. } <;> 

Proof state:
case refine'_3
F : Type u₀ → Type u₁ → Type u₂
inst✝¹ : Bifunctor F
inst✝ : LawfulBifunctor F
α : Type u₀
⊢ ∀ {α_1 β γ : Type u₁} (g : α_1 → β) (h : β → γ) (x : F α α_1), (h ∘ g) <$> x = h <$> g <$> x

Next tactic:
intros
instance (priority := 10) Bifunctor.lawfulFunctor [LawfulBifunctor F] {α} : LawfulFunctor (F α) :=
  -- Porting note: `mapConst` is required to prove new theorem
  by refine' { .. } <;> intros <;> 

Proof state:
case refine'_1
F : Type u₀ → Type u₁ → Type u₂
inst✝¹ : Bifunctor F
inst✝ : LawfulBifunctor F
α : Type u₀
α✝ β✝ : Type u₁
⊢ mapConst = map ∘ Function.const β✝

Next tactic:
simp [mapConst, Functor.map, functor_norm]
instance (priority := 10) Bifunctor.lawfulFunctor [LawfulBifunctor F] {α} : LawfulFunctor (F α) :=
  -- Porting note: `mapConst` is required to prove new theorem
  by refine' { .. } <;> intros <;> 

Proof state:
case refine'_2
F : Type u₀ → Type u₁ → Type u₂
inst✝¹ : Bifunctor F
inst✝ : LawfulBifunctor F
α : Type u₀
α✝ : Type u₁
x✝ : F α α✝
⊢ id <$> x✝ = x✝

Next tactic:
simp [mapConst, Functor.map, functor_norm]
instance (priority := 10) Bifunctor.lawfulFunctor [LawfulBifunctor F] {α} : LawfulFunctor (F α) :=
  -- Porting note: `mapConst` is required to prove new theorem
  by refine' { .. } <;> intros <;> 

Proof state:
case refine'_3
F : Type u₀ → Type u₁ → Type u₂
inst✝¹ : Bifunctor F
inst✝ : LawfulBifunctor F
α : Type u₀
α✝ β✝ γ✝ : Type u₁
g✝ : α✝ → β✝
h✝ : β✝ → γ✝
x✝ : F α α✝
⊢ (h✝ ∘ g✝) <$> x✝ = h✝ <$> g✝ <$> x✝

Next tactic:
simp [mapConst, Functor.map, functor_norm]
instance Function.bicompl.lawfulBifunctor [LawfulFunctor G] [LawfulFunctor H] [LawfulBifunctor F] :
    LawfulBifunctor (bicompl F G H) := by
  

Proof state:
F : Type u₀ → Type u₁ → Type u₂
inst✝⁵ : Bifunctor F
G : Type u_1 → Type u₀
H : Type u_2 → Type u₁
inst✝⁴ : Functor G
inst✝³ : Functor H
inst✝² : LawfulFunctor G
inst✝¹ : LawfulFunctor H
inst✝ : LawfulBifunctor F
⊢ LawfulBifunctor (bicompl F G H)

Next tactic:
constructor
instance Function.bicompl.lawfulBifunctor [LawfulFunctor G] [LawfulFunctor H] [LawfulBifunctor F] :
    LawfulBifunctor (bicompl F G H) := by
  constructor <;> 

Proof state:
case id_bimap
F : Type u₀ → Type u₁ → Type u₂
inst✝⁵ : Bifunctor F
G : Type u_1 → Type u₀
H : Type u_2 → Type u₁
inst✝⁴ : Functor G
inst✝³ : Functor H
inst✝² : LawfulFunctor G
inst✝¹ : LawfulFunctor H
inst✝ : LawfulBifunctor F
⊢ ∀ {α : Type u_1} {β : Type u_2} (x : bicompl F G H α β), bimap id id x = x

Next tactic:
intros
instance Function.bicompl.lawfulBifunctor [LawfulFunctor G] [LawfulFunctor H] [LawfulBifunctor F] :
    LawfulBifunctor (bicompl F G H) := by
  constructor <;> 

Proof state:
case bimap_bimap
F : Type u₀ → Type u₁ → Type u₂
inst✝⁵ : Bifunctor F
G : Type u_1 → Type u₀
H : Type u_2 → Type u₁
inst✝⁴ : Functor G
inst✝³ : Functor H
inst✝² : LawfulFunctor G
inst✝¹ : LawfulFunctor H
inst✝ : LawfulBifunctor F
⊢ ∀ {α₀ α₁ α₂ : Type u_1} {β₀ β₁ β₂ : Type u_2} (f : α₀ → α₁) (f' : α₁ → α₂) (g : β₀ → β₁) (g' : β₁ → β₂)
    (x : bicompl F G H α₀ β₀), bimap f' g' (bimap f g x) = bimap (f' ∘ f) (g' ∘ g) x

Next tactic:
intros
instance Function.bicompl.lawfulBifunctor [LawfulFunctor G] [LawfulFunctor H] [LawfulBifunctor F] :
    LawfulBifunctor (bicompl F G H) := by
  constructor <;> intros <;> 

Proof state:
case id_bimap
F : Type u₀ → Type u₁ → Type u₂
inst✝⁵ : Bifunctor F
G : Type u_1 → Type u₀
H : Type u_2 → Type u₁
inst✝⁴ : Functor G
inst✝³ : Functor H
inst✝² : LawfulFunctor G
inst✝¹ : LawfulFunctor H
inst✝ : LawfulBifunctor F
α✝ : Type u_1
β✝ : Type u_2
x✝ : bicompl F G H α✝ β✝
⊢ bimap id id x✝ = x✝

Next tactic:
simp [bimap, map_id, map_comp_map, functor_norm]
instance Function.bicompl.lawfulBifunctor [LawfulFunctor G] [LawfulFunctor H] [LawfulBifunctor F] :
    LawfulBifunctor (bicompl F G H) := by
  constructor <;> intros <;> 

Proof state:
case bimap_bimap
F : Type u₀ → Type u₁ → Type u₂
inst✝⁵ : Bifunctor F
G : Type u_1 → Type u₀
H : Type u_2 → Type u₁
inst✝⁴ : Functor G
inst✝³ : Functor H
inst✝² : LawfulFunctor G
inst✝¹ : LawfulFunctor H
inst✝ : LawfulBifunctor F
α₀✝ α₁✝ α₂✝ : Type u_1
β₀✝ β₁✝ β₂✝ : Type u_2
f✝ : α₀✝ → α₁✝
f'✝ : α₁✝ → α₂✝
g✝ : β₀✝ → β₁✝
g'✝ : β₁✝ → β₂✝
x✝ : bicompl F G H α₀✝ β₀✝
⊢ bimap f'✝ g'✝ (bimap f✝ g✝ x✝) = bimap (f'✝ ∘ f✝) (g'✝ ∘ g✝) x✝

Next tactic:
simp [bimap, map_id, map_comp_map, functor_norm]
instance Function.bicompr.lawfulBifunctor [LawfulFunctor G] [LawfulBifunctor F] :
    LawfulBifunctor (bicompr G F) := by
  

Proof state:
F : Type u₀ → Type u₁ → Type u₂
inst✝³ : Bifunctor F
G : Type u₂ → Type u_1
inst✝² : Functor G
inst✝¹ : LawfulFunctor G
inst✝ : LawfulBifunctor F
⊢ LawfulBifunctor (bicompr G F)

Next tactic:
constructor
instance Function.bicompr.lawfulBifunctor [LawfulFunctor G] [LawfulBifunctor F] :
    LawfulBifunctor (bicompr G F) := by
  constructor <;> 

Proof state:
case id_bimap
F : Type u₀ → Type u₁ → Type u₂
inst✝³ : Bifunctor F
G : Type u₂ → Type u_1
inst✝² : Functor G
inst✝¹ : LawfulFunctor G
inst✝ : LawfulBifunctor F
⊢ ∀ {α : Type u₀} {β : Type u₁} (x : bicompr G F α β), bimap id id x = x

Next tactic:
intros
instance Function.bicompr.lawfulBifunctor [LawfulFunctor G] [LawfulBifunctor F] :
    LawfulBifunctor (bicompr G F) := by
  constructor <;> 

Proof state:
case bimap_bimap
F : Type u₀ → Type u₁ → Type u₂
inst✝³ : Bifunctor F
G : Type u₂ → Type u_1
inst✝² : Functor G
inst✝¹ : LawfulFunctor G
inst✝ : LawfulBifunctor F
⊢ ∀ {α₀ α₁ α₂ : Type u₀} {β₀ β₁ β₂ : Type u₁} (f : α₀ → α₁) (f' : α₁ → α₂) (g : β₀ → β₁) (g' : β₁ → β₂)
    (x : bicompr G F α₀ β₀), bimap f' g' (bimap f g x) = bimap (f' ∘ f) (g' ∘ g) x

Next tactic:
intros
instance Function.bicompr.lawfulBifunctor [LawfulFunctor G] [LawfulBifunctor F] :
    LawfulBifunctor (bicompr G F) := by
  constructor <;> intros <;> 

Proof state:
case id_bimap
F : Type u₀ → Type u₁ → Type u₂
inst✝³ : Bifunctor F
G : Type u₂ → Type u_1
inst✝² : Functor G
inst✝¹ : LawfulFunctor G
inst✝ : LawfulBifunctor F
α✝ : Type u₀
β✝ : Type u₁
x✝ : bicompr G F α✝ β✝
⊢ bimap id id x✝ = x✝

Next tactic:
simp [bimap, functor_norm]
instance Function.bicompr.lawfulBifunctor [LawfulFunctor G] [LawfulBifunctor F] :
    LawfulBifunctor (bicompr G F) := by
  constructor <;> intros <;> 

Proof state:
case bimap_bimap
F : Type u₀ → Type u₁ → Type u₂
inst✝³ : Bifunctor F
G : Type u₂ → Type u_1
inst✝² : Functor G
inst✝¹ : LawfulFunctor G
inst✝ : LawfulBifunctor F
α₀✝ α₁✝ α₂✝ : Type u₀
β₀✝ β₁✝ β₂✝ : Type u₁
f✝ : α₀✝ → α₁✝
f'✝ : α₁✝ → α₂✝
g✝ : β₀✝ → β₁✝
g'✝ : β₁✝ → β₂✝
x✝ : bicompr G F α₀✝ β₀✝
⊢ bimap f'✝ g'✝ (bimap f✝ g✝ x✝) = bimap (f'✝ ∘ f✝) (g'✝ ∘ g✝) x✝

Next tactic:
simp [bimap, functor_norm]
@[reassoc (attr := simp)]
lemma map_condition : G.map c.ι ≫ G.map f = 0 := by
  

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
inst✝¹ : HasZeroMorphisms D
X Y : C
f : X ⟶ Y
c : KernelFork f
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
⊢ G.map (Fork.ι c) ≫ G.map f = 0

Next tactic:
rw [← G.map_comp, c.condition, G.map_zero]
/-- The underlying cone of a kernel fork is mapped to a limit cone if and only if
the mapped kernel fork is limit. -/
def isLimitMapConeEquiv :
    IsLimit (G.mapCone c) ≃ IsLimit (c.map G) := by
  

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
inst✝¹ : HasZeroMorphisms D
X Y : C
f : X ⟶ Y
c : KernelFork f
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
⊢ IsLimit (G.mapCone c) ≃ IsLimit (map c G)

Next tactic:
refine' (IsLimit.postcomposeHomEquiv _ _).symm.trans (IsLimit.equivIsoLimit _)
/-- The underlying cone of a kernel fork is mapped to a limit cone if and only if
the mapped kernel fork is limit. -/
def isLimitMapConeEquiv :
    IsLimit (G.mapCone c) ≃ IsLimit (c.map G) := by
  refine' (IsLimit.postcomposeHomEquiv _ _).symm.trans (IsLimit.equivIsoLimit _)
  

Proof state:
case refine'_1
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
inst✝¹ : HasZeroMorphisms D
X Y : C
f : X ⟶ Y
c : KernelFork f
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
⊢ parallelPair f 0 ⋙ G ≅ parallelPair (G.map f) 0

Next tactic:
refine' parallelPair.ext (Iso.refl _) (Iso.refl _) _ _
/-- The underlying cone of a kernel fork is mapped to a limit cone if and only if
the mapped kernel fork is limit. -/
def isLimitMapConeEquiv :
    IsLimit (G.mapCone c) ≃ IsLimit (c.map G) := by
  refine' (IsLimit.postcomposeHomEquiv _ _).symm.trans (IsLimit.equivIsoLimit _)
  refine' parallelPair.ext (Iso.refl _) (Iso.refl _) _ _ <;> 

Proof state:
case refine'_1.refine'_1
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
inst✝¹ : HasZeroMorphisms D
X Y : C
f : X ⟶ Y
c : KernelFork f
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
⊢ (parallelPair f 0 ⋙ G).map WalkingParallelPairHom.left ≫
      (Iso.refl ((parallelPair f 0 ⋙ G).obj WalkingParallelPair.one)).hom =
    (Iso.refl ((parallelPair f 0 ⋙ G).obj WalkingParallelPair.zero)).hom ≫
      (parallelPair (G.map f) 0).map WalkingParallelPairHom.left

Next tactic:
simp