l3lab/ntp-mathlib huggingface dataset:
/-- The **alternating series test** for monotone sequences.
See also `Monotone.tendsto_alternating_series_of_tendsto_zero`. -/
theorem Monotone.cauchySeq_alternating_series_of_tendsto_zero (hfa : Monotone f)
    (hf0 : Tendsto f atTop (𝓝 0)) : CauchySeq fun n ↦ ∑ i in range (n + 1), (-1) ^ i * f i := by
  simp_rw [mul_comm]
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
E : Type u_4
inst✝¹ : NormedAddCommGroup E
inst✝ : NormedSpace ℝ E
b : ℝ
f : ℕ → ℝ
z : ℕ → E
hfa : Monotone f
hf0 : Tendsto f atTop (𝓝 0)
⊢ CauchySeq fun n => ∑ x in Finset.range (n + 1), f x * (-1) ^ x

Next tactic:
exact hfa.cauchySeq_series_mul_of_tendsto_zero_of_bounded hf0 norm_sum_neg_one_pow_le
/-- The **alternating series test** for antitone sequences.
See also `Antitone.tendsto_alternating_series_of_tendsto_zero`. -/
theorem Antitone.cauchySeq_alternating_series_of_tendsto_zero (hfa : Antitone f)
    (hf0 : Tendsto f atTop (𝓝 0)) : CauchySeq fun n ↦ ∑ i in range (n + 1), (-1) ^ i * f i := by
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
E : Type u_4
inst✝¹ : NormedAddCommGroup E
inst✝ : NormedSpace ℝ E
b : ℝ
f : ℕ → ℝ
z : ℕ → E
hfa : Antitone f
hf0 : Tendsto f atTop (𝓝 0)
⊢ CauchySeq fun n => ∑ i in Finset.range (n + 1), (-1) ^ i * f i

Next tactic:
simp_rw [mul_comm]
/-- The **alternating series test** for antitone sequences.
See also `Antitone.tendsto_alternating_series_of_tendsto_zero`. -/
theorem Antitone.cauchySeq_alternating_series_of_tendsto_zero (hfa : Antitone f)
    (hf0 : Tendsto f atTop (𝓝 0)) : CauchySeq fun n ↦ ∑ i in range (n + 1), (-1) ^ i * f i := by
  simp_rw [mul_comm]
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
E : Type u_4
inst✝¹ : NormedAddCommGroup E
inst✝ : NormedSpace ℝ E
b : ℝ
f : ℕ → ℝ
z : ℕ → E
hfa : Antitone f
hf0 : Tendsto f atTop (𝓝 0)
⊢ CauchySeq fun n => ∑ x in Finset.range (n + 1), f x * (-1) ^ x

Next tactic:
exact hfa.cauchySeq_series_mul_of_tendsto_zero_of_bounded hf0 norm_sum_neg_one_pow_le
/-- The series `∑' n, x ^ n / n!` is summable of any `x : ℝ`. See also `exp_series_div_summable`
for a version that also works in `ℂ`, and `exp_series_summable'` for a version that works in
any normed algebra over `ℝ` or `ℂ`. -/
theorem Real.summable_pow_div_factorial (x : ℝ) : Summable (fun n ↦ x ^ n / n ! : ℕ → ℝ) := by
  -- We start with trivial estimates
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
x : ℝ
⊢ Summable fun n => x ^ n / ↑n !

Next tactic:
have A : (0 : ℝ) < ⌊‖x‖⌋₊ + 1 := zero_lt_one.trans_le (by simp)
/-- The series `∑' n, x ^ n / n!` is summable of any `x : ℝ`. See also `exp_series_div_summable`
for a version that also works in `ℂ`, and `exp_series_summable'` for a version that works in
any normed algebra over `ℝ` or `ℂ`. -/
theorem Real.summable_pow_div_factorial (x : ℝ) : Summable (fun n ↦ x ^ n / n ! : ℕ → ℝ) := by
  -- We start with trivial estimates
  have A : (0 : ℝ) < ⌊‖x‖⌋₊ + 1 := zero_lt_one.trans_le (by 

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
x : ℝ
⊢ 1 ≤ ↑⌊‖x‖⌋₊ + 1

Next tactic:
simp
/-- The series `∑' n, x ^ n / n!` is summable of any `x : ℝ`. See also `exp_series_div_summable`
for a version that also works in `ℂ`, and `exp_series_summable'` for a version that works in
any normed algebra over `ℝ` or `ℂ`. -/
theorem Real.summable_pow_div_factorial (x : ℝ) : Summable (fun n ↦ x ^ n / n ! : ℕ → ℝ) := by
  -- We start with trivial estimates
  have A : (0 : ℝ) < ⌊‖x‖⌋₊ + 1 := zero_lt_one.trans_le (by simp)
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
x : ℝ
A : 0 < ↑⌊‖x‖⌋₊ + 1
⊢ Summable fun n => x ^ n / ↑n !

Next tactic:
have B : ‖x‖ / (⌊‖x‖⌋₊ + 1) < 1 := (div_lt_one A).2 (Nat.lt_floor_add_one _)
/-- The series `∑' n, x ^ n / n!` is summable of any `x : ℝ`. See also `exp_series_div_summable`
for a version that also works in `ℂ`, and `exp_series_summable'` for a version that works in
any normed algebra over `ℝ` or `ℂ`. -/
theorem Real.summable_pow_div_factorial (x : ℝ) : Summable (fun n ↦ x ^ n / n ! : ℕ → ℝ) := by
  -- We start with trivial estimates
  have A : (0 : ℝ) < ⌊‖x‖⌋₊ + 1 := zero_lt_one.trans_le (by simp)
  have B : ‖x‖ / (⌊‖x‖⌋₊ + 1) < 1 := (div_lt_one A).2 (Nat.lt_floor_add_one _)
  -- Then we apply the ratio test. The estimate works for `n ≥ ⌊‖x‖⌋₊`.
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
x : ℝ
A : 0 < ↑⌊‖x‖⌋₊ + 1
B : ‖x‖ / (↑⌊‖x‖⌋₊ + 1) < 1
⊢ Summable fun n => x ^ n / ↑n !

Next tactic:
suffices : ∀ n ≥ ⌊‖x‖⌋₊, ‖x ^ (n + 1) / (n + 1)!‖ ≤ ‖x‖ / (⌊‖x‖⌋₊ + 1) * ‖x ^ n / ↑n !‖
/-- The series `∑' n, x ^ n / n!` is summable of any `x : ℝ`. See also `exp_series_div_summable`
for a version that also works in `ℂ`, and `exp_series_summable'` for a version that works in
any normed algebra over `ℝ` or `ℂ`. -/
theorem Real.summable_pow_div_factorial (x : ℝ) : Summable (fun n ↦ x ^ n / n ! : ℕ → ℝ) := by
  -- We start with trivial estimates
  have A : (0 : ℝ) < ⌊‖x‖⌋₊ + 1 := zero_lt_one.trans_le (by simp)
  have B : ‖x‖ / (⌊‖x‖⌋₊ + 1) < 1 := (div_lt_one A).2 (Nat.lt_floor_add_one _)
  -- Then we apply the ratio test. The estimate works for `n ≥ ⌊‖x‖⌋₊`.
  suffices : ∀ n ≥ ⌊‖x‖⌋₊, ‖x ^ (n + 1) / (n + 1)!‖ ≤ ‖x‖ / (⌊‖x‖⌋₊ + 1) * ‖x ^ n / ↑n !‖
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
x : ℝ
A : 0 < ↑⌊‖x‖⌋₊ + 1
B : ‖x‖ / (↑⌊‖x‖⌋₊ + 1) < 1
this : ∀ n ≥ ⌊‖x‖⌋₊, ‖x ^ (n + 1) / ↑(n + 1)!‖ ≤ ‖x‖ / (↑⌊‖x‖⌋₊ + 1) * ‖x ^ n / ↑n !‖
⊢ Summable fun n => x ^ n / ↑n !
case this
α : Type u_1
β : Type u_2
ι : Type u_3
x : ℝ
A : 0 < ↑⌊‖x‖⌋₊ + 1
B : ‖x‖ / (↑⌊‖x‖⌋₊ + 1) < 1
⊢ ∀ n ≥ ⌊‖x‖⌋₊, ‖x ^ (n + 1) / ↑(n + 1)!‖ ≤ ‖x‖ / (↑⌊‖x‖⌋₊ + 1) * ‖x ^ n / ↑n !‖

Next tactic:
exact summable_of_ratio_norm_eventually_le B (eventually_atTop.2 ⟨⌊‖x‖⌋₊, this⟩)
/-- The series `∑' n, x ^ n / n!` is summable of any `x : ℝ`. See also `exp_series_div_summable`
for a version that also works in `ℂ`, and `exp_series_summable'` for a version that works in
any normed algebra over `ℝ` or `ℂ`. -/
theorem Real.summable_pow_div_factorial (x : ℝ) : Summable (fun n ↦ x ^ n / n ! : ℕ → ℝ) := by
  -- We start with trivial estimates
  have A : (0 : ℝ) < ⌊‖x‖⌋₊ + 1 := zero_lt_one.trans_le (by simp)
  have B : ‖x‖ / (⌊‖x‖⌋₊ + 1) < 1 := (div_lt_one A).2 (Nat.lt_floor_add_one _)
  -- Then we apply the ratio test. The estimate works for `n ≥ ⌊‖x‖⌋₊`.
  suffices : ∀ n ≥ ⌊‖x‖⌋₊, ‖x ^ (n + 1) / (n + 1)!‖ ≤ ‖x‖ / (⌊‖x‖⌋₊ + 1) * ‖x ^ n / ↑n !‖
  exact summable_of_ratio_norm_eventually_le B (eventually_atTop.2 ⟨⌊‖x‖⌋₊, this⟩)
  -- Finally, we prove the upper estimate
  

Proof state:
case this
α : Type u_1
β : Type u_2
ι : Type u_3
x : ℝ
A : 0 < ↑⌊‖x‖⌋₊ + 1
B : ‖x‖ / (↑⌊‖x‖⌋₊ + 1) < 1
⊢ ∀ n ≥ ⌊‖x‖⌋₊, ‖x ^ (n + 1) / ↑(n + 1)!‖ ≤ ‖x‖ / (↑⌊‖x‖⌋₊ + 1) * ‖x ^ n / ↑n !‖

Next tactic:
intro n hn
/-- The series `∑' n, x ^ n / n!` is summable of any `x : ℝ`. See also `exp_series_div_summable`
for a version that also works in `ℂ`, and `exp_series_summable'` for a version that works in
any normed algebra over `ℝ` or `ℂ`. -/
theorem Real.summable_pow_div_factorial (x : ℝ) : Summable (fun n ↦ x ^ n / n ! : ℕ → ℝ) := by
  -- We start with trivial estimates
  have A : (0 : ℝ) < ⌊‖x‖⌋₊ + 1 := zero_lt_one.trans_le (by simp)
  have B : ‖x‖ / (⌊‖x‖⌋₊ + 1) < 1 := (div_lt_one A).2 (Nat.lt_floor_add_one _)
  -- Then we apply the ratio test. The estimate works for `n ≥ ⌊‖x‖⌋₊`.
  suffices : ∀ n ≥ ⌊‖x‖⌋₊, ‖x ^ (n + 1) / (n + 1)!‖ ≤ ‖x‖ / (⌊‖x‖⌋₊ + 1) * ‖x ^ n / ↑n !‖
  exact summable_of_ratio_norm_eventually_le B (eventually_atTop.2 ⟨⌊‖x‖⌋₊, this⟩)
  -- Finally, we prove the upper estimate
  intro n hn
  

Proof state:
case this
α : Type u_1
β : Type u_2
ι : Type u_3
x : ℝ
A : 0 < ↑⌊‖x‖⌋₊ + 1
B : ‖x‖ / (↑⌊‖x‖⌋₊ + 1) < 1
n : ℕ
hn : n ≥ ⌊‖x‖⌋₊
⊢ ‖x ^ (n + 1) / ↑(n + 1)!‖ ≤ ‖x‖ / (↑⌊‖x‖⌋₊ + 1) * ‖x ^ n / ↑n !‖

Next tactic:
calc
    ‖x ^ (n + 1) / (n + 1)!‖ = ‖x‖ / (n + 1) * ‖x ^ n / (n !)‖ := by
      rw [_root_.pow_succ, Nat.factorial_succ, Nat.cast_mul, ← _root_.div_mul_div_comm, norm_mul,
        norm_div, Real.norm_coe_nat, Nat.cast_succ]
    _ ≤ ‖x‖ / (⌊‖x‖⌋₊ + 1) * ‖x ^ n / (n !)‖ :=
      -- Porting note: this was `by mono* with 0 ≤ ‖x ^ n / (n !)‖, 0 ≤ ‖x‖ <;> apply norm_nonneg`
      -- but we can't wait on `mono`.
      mul_le_mul_of_nonneg_right
        (div_le_div (norm_nonneg x) (le_refl ‖x‖) A (add_le_add (mono_cast hn) (le_refl 1)))
        (norm_nonneg (x ^ n / n !))
/-- The series `∑' n, x ^ n / n!` is summable of any `x : ℝ`. See also `exp_series_div_summable`
for a version that also works in `ℂ`, and `exp_series_summable'` for a version that works in
any normed algebra over `ℝ` or `ℂ`. -/
theorem Real.summable_pow_div_factorial (x : ℝ) : Summable (fun n ↦ x ^ n / n ! : ℕ → ℝ) := by
  -- We start with trivial estimates
  have A : (0 : ℝ) < ⌊‖x‖⌋₊ + 1 := zero_lt_one.trans_le (by simp)
  have B : ‖x‖ / (⌊‖x‖⌋₊ + 1) < 1 := (div_lt_one A).2 (Nat.lt_floor_add_one _)
  -- Then we apply the ratio test. The estimate works for `n ≥ ⌊‖x‖⌋₊`.
  suffices : ∀ n ≥ ⌊‖x‖⌋₊, ‖x ^ (n + 1) / (n + 1)!‖ ≤ ‖x‖ / (⌊‖x‖⌋₊ + 1) * ‖x ^ n / ↑n !‖
  exact summable_of_ratio_norm_eventually_le B (eventually_atTop.2 ⟨⌊‖x‖⌋₊, this⟩)
  -- Finally, we prove the upper estimate
  intro n hn
  calc
    ‖x ^ (n + 1) / (n + 1)!‖ = ‖x‖ / (n + 1) * ‖x ^ n / (n !)‖ := by
      

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
x : ℝ
A : 0 < ↑⌊‖x‖⌋₊ + 1
B : ‖x‖ / (↑⌊‖x‖⌋₊ + 1) < 1
n : ℕ
hn : n ≥ ⌊‖x‖⌋₊
⊢ ‖x ^ (n + 1) / ↑(n + 1)!‖ = ‖x‖ / (↑n + 1) * ‖x ^ n / ↑n !‖

Next tactic:
rw [_root_.pow_succ, Nat.factorial_succ, Nat.cast_mul, ← _root_.div_mul_div_comm, norm_mul,
        norm_div, Real.norm_coe_nat, Nat.cast_succ]
/-- The free-forgetful adjunction for abelian groups.
-/
def adj : free ⊣ forget AddCommGroupCat.{u} :=
  Adjunction.mkOfHomEquiv
    { homEquiv := fun X G => FreeAbelianGroup.lift.symm
      -- Porting note: used to be just `by intros; ext; rfl`.
      homEquiv_naturality_left_symm := by
        

Proof state:
⊢ ∀ {X' X : Type u} {Y : AddCommGroupCat} (f : X' ⟶ X) (g : X ⟶ (forget AddCommGroupCat).obj Y),
    ((fun X G => FreeAbelianGroup.lift.symm) X' Y).symm (f ≫ g) =
      free.map f ≫ ((fun X G => FreeAbelianGroup.lift.symm) X Y).symm g

Next tactic:
intros
/-- The free-forgetful adjunction for abelian groups.
-/
def adj : free ⊣ forget AddCommGroupCat.{u} :=
  Adjunction.mkOfHomEquiv
    { homEquiv := fun X G => FreeAbelianGroup.lift.symm
      -- Porting note: used to be just `by intros; ext; rfl`.
      homEquiv_naturality_left_symm := by
        intros
        

Proof state:
X'✝ X✝ : Type u
Y✝ : AddCommGroupCat
f✝ : X'✝ ⟶ X✝
g✝ : X✝ ⟶ (forget AddCommGroupCat).obj Y✝
⊢ ((fun X G => FreeAbelianGroup.lift.symm) X'✝ Y✝).symm (f✝ ≫ g✝) =
    free.map f✝ ≫ ((fun X G => FreeAbelianGroup.lift.symm) X✝ Y✝).symm g✝

Next tactic:
ext
/-- The free-forgetful adjunction for abelian groups.
-/
def adj : free ⊣ forget AddCommGroupCat.{u} :=
  Adjunction.mkOfHomEquiv
    { homEquiv := fun X G => FreeAbelianGroup.lift.symm
      -- Porting note: used to be just `by intros; ext; rfl`.
      homEquiv_naturality_left_symm := by
        intros
        ext
        

Proof state:
case w
X'✝ X✝ : Type u
Y✝ : AddCommGroupCat
f✝ : X'✝ ⟶ X✝
g✝ : X✝ ⟶ (forget AddCommGroupCat).obj Y✝
x✝ : ↑(free.obj X'✝)
⊢ (((fun X G => FreeAbelianGroup.lift.symm) X'✝ Y✝).symm (f✝ ≫ g✝)) x✝ =
    (free.map f✝ ≫ ((fun X G => FreeAbelianGroup.lift.symm) X✝ Y✝).symm g✝) x✝

Next tactic:
simp only [Equiv.symm_symm]
/-- The free-forgetful adjunction for abelian groups.
-/
def adj : free ⊣ forget AddCommGroupCat.{u} :=
  Adjunction.mkOfHomEquiv
    { homEquiv := fun X G => FreeAbelianGroup.lift.symm
      -- Porting note: used to be just `by intros; ext; rfl`.
      homEquiv_naturality_left_symm := by
        intros
        ext
        simp only [Equiv.symm_symm]
        

Proof state:
case w
X'✝ X✝ : Type u
Y✝ : AddCommGroupCat
f✝ : X'✝ ⟶ X✝
g✝ : X✝ ⟶ (forget AddCommGroupCat).obj Y✝
x✝ : ↑(free.obj X'✝)
⊢ (FreeAbelianGroup.lift (f✝ ≫ g✝)) x✝ = (free.map f✝ ≫ FreeAbelianGroup.lift g✝) x✝

Next tactic:
apply FreeAbelianGroup.lift_comp
/-- The free functor `Type u ⥤ Group` sending a type `X` to the free group with generators `x : X`.
-/
def free : Type u ⥤ GroupCat where
  obj α := of (FreeGroup α)
  map := FreeGroup.map
  map_id := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    

Proof state:
⊢ ∀ (X : Type u),
    { obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.map (𝟙 X) =
      𝟙 ({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.obj X)

Next tactic:
intros
/-- The free functor `Type u ⥤ Group` sending a type `X` to the free group with generators `x : X`.
-/
def free : Type u ⥤ GroupCat where
  obj α := of (FreeGroup α)
  map := FreeGroup.map
  map_id := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; 

Proof state:
X✝ : Type u
⊢ { obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.map (𝟙 X✝) =
    𝟙 ({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.obj X✝)

Next tactic:
ext1
/-- The free functor `Type u ⥤ Group` sending a type `X` to the free group with generators `x : X`.
-/
def free : Type u ⥤ GroupCat where
  obj α := of (FreeGroup α)
  map := FreeGroup.map
  map_id := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; ext1; 

Proof state:
case w
X✝ : Type u
x✝ : ↑({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.obj X✝)
⊢ ({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.map (𝟙 X✝)) x✝ =
    (𝟙 ({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.obj X✝)) x✝

Next tactic:
erw [← FreeGroup.map.unique]
/-- The free functor `Type u ⥤ Group` sending a type `X` to the free group with generators `x : X`.
-/
def free : Type u ⥤ GroupCat where
  obj α := of (FreeGroup α)
  map := FreeGroup.map
  map_id := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; ext1; erw [← FreeGroup.map.unique] <;> 

Proof state:
case w
X✝ : Type u
x✝ : ↑({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.obj X✝)
⊢ ?w.g x✝ = (𝟙 ({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.obj X✝)) x✝

Next tactic:
intros
/-- The free functor `Type u ⥤ Group` sending a type `X` to the free group with generators `x : X`.
-/
def free : Type u ⥤ GroupCat where
  obj α := of (FreeGroup α)
  map := FreeGroup.map
  map_id := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; ext1; erw [← FreeGroup.map.unique] <;> 

Proof state:
case w.g
X✝ : Type u
x✝ : ↑({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.obj X✝)
⊢ FreeGroup X✝ →* FreeGroup X✝

Next tactic:
intros
/-- The free functor `Type u ⥤ Group` sending a type `X` to the free group with generators `x : X`.
-/
def free : Type u ⥤ GroupCat where
  obj α := of (FreeGroup α)
  map := FreeGroup.map
  map_id := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; ext1; erw [← FreeGroup.map.unique] <;> 

Proof state:
case w.hg
X✝ : Type u
x✝ : ↑({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.obj X✝)
⊢ ∀ (x : X✝), ?w.g (FreeGroup.of x) = FreeGroup.of (𝟙 X✝ x)

Next tactic:
intros
/-- The free functor `Type u ⥤ Group` sending a type `X` to the free group with generators `x : X`.
-/
def free : Type u ⥤ GroupCat where
  obj α := of (FreeGroup α)
  map := FreeGroup.map
  map_id := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; ext1; erw [← FreeGroup.map.unique] <;> intros <;> 

Proof state:
case w
X✝ : Type u
x✝ : ↑({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.obj X✝)
⊢ ?w.g x✝ = (𝟙 ({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.obj X✝)) x✝

Next tactic:
rfl
/-- The free functor `Type u ⥤ Group` sending a type `X` to the free group with generators `x : X`.
-/
def free : Type u ⥤ GroupCat where
  obj α := of (FreeGroup α)
  map := FreeGroup.map
  map_id := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; ext1; erw [← FreeGroup.map.unique] <;> intros <;> 

Proof state:
case w.hg
X✝ : Type u
x✝¹ : ↑({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.obj X✝)
x✝ : X✝
⊢ (𝟙 ({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.obj X✝)) (FreeGroup.of x✝) =
    FreeGroup.of (𝟙 X✝ x✝)

Next tactic:
rfl
/-- The free functor `Type u ⥤ Group` sending a type `X` to the free group with generators `x : X`.
-/
def free : Type u ⥤ GroupCat where
  obj α := of (FreeGroup α)
  map := FreeGroup.map
  map_id := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; ext1; erw [← FreeGroup.map.unique] <;> intros <;> rfl
  map_comp := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    

Proof state:
⊢ ∀ {X Y Z : Type u} (f : X ⟶ Y) (g : Y ⟶ Z),
    { obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.map (f ≫ g) =
      { obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.map f ≫
        { obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.map g

Next tactic:
intros
/-- The free functor `Type u ⥤ Group` sending a type `X` to the free group with generators `x : X`.
-/
def free : Type u ⥤ GroupCat where
  obj α := of (FreeGroup α)
  map := FreeGroup.map
  map_id := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; ext1; erw [← FreeGroup.map.unique] <;> intros <;> rfl
  map_comp := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; 

Proof state:
X✝ Y✝ Z✝ : Type u
f✝ : X✝ ⟶ Y✝
g✝ : Y✝ ⟶ Z✝
⊢ { obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.map (f✝ ≫ g✝) =
    { obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.map f✝ ≫
      { obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.map g✝

Next tactic:
ext1
/-- The free functor `Type u ⥤ Group` sending a type `X` to the free group with generators `x : X`.
-/
def free : Type u ⥤ GroupCat where
  obj α := of (FreeGroup α)
  map := FreeGroup.map
  map_id := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; ext1; erw [← FreeGroup.map.unique] <;> intros <;> rfl
  map_comp := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; ext1; 

Proof state:
case w
X✝ Y✝ Z✝ : Type u
f✝ : X✝ ⟶ Y✝
g✝ : Y✝ ⟶ Z✝
x✝ : ↑({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.obj X✝)
⊢ ({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.map (f✝ ≫ g✝)) x✝ =
    ({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.map f✝ ≫
        { obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.map g✝)
      x✝

Next tactic:
erw [← FreeGroup.map.unique]
/-- The free functor `Type u ⥤ Group` sending a type `X` to the free group with generators `x : X`.
-/
def free : Type u ⥤ GroupCat where
  obj α := of (FreeGroup α)
  map := FreeGroup.map
  map_id := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; ext1; erw [← FreeGroup.map.unique] <;> intros <;> rfl
  map_comp := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; ext1; erw [← FreeGroup.map.unique] <;> 

Proof state:
case w
X✝ Y✝ Z✝ : Type u
f✝ : X✝ ⟶ Y✝
g✝ : Y✝ ⟶ Z✝
x✝ : ↑({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.obj X✝)
⊢ ?w.g x✝ =
    ({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.map f✝ ≫
        { obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.map g✝)
      x✝

Next tactic:
intros
/-- The free functor `Type u ⥤ Group` sending a type `X` to the free group with generators `x : X`.
-/
def free : Type u ⥤ GroupCat where
  obj α := of (FreeGroup α)
  map := FreeGroup.map
  map_id := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; ext1; erw [← FreeGroup.map.unique] <;> intros <;> rfl
  map_comp := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; ext1; erw [← FreeGroup.map.unique] <;> 

Proof state:
case w.g
X✝ Y✝ Z✝ : Type u
f✝ : X✝ ⟶ Y✝
g✝ : Y✝ ⟶ Z✝
x✝ : ↑({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.obj X✝)
⊢ FreeGroup X✝ →* FreeGroup Z✝

Next tactic:
intros
/-- The free functor `Type u ⥤ Group` sending a type `X` to the free group with generators `x : X`.
-/
def free : Type u ⥤ GroupCat where
  obj α := of (FreeGroup α)
  map := FreeGroup.map
  map_id := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; ext1; erw [← FreeGroup.map.unique] <;> intros <;> rfl
  map_comp := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; ext1; erw [← FreeGroup.map.unique] <;> 

Proof state:
case w.hg
X✝ Y✝ Z✝ : Type u
f✝ : X✝ ⟶ Y✝
g✝ : Y✝ ⟶ Z✝
x✝ : ↑({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.obj X✝)
⊢ ∀ (x : X✝), ?w.g (FreeGroup.of x) = FreeGroup.of ((f✝ ≫ g✝) x)

Next tactic:
intros
/-- The free functor `Type u ⥤ Group` sending a type `X` to the free group with generators `x : X`.
-/
def free : Type u ⥤ GroupCat where
  obj α := of (FreeGroup α)
  map := FreeGroup.map
  map_id := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; ext1; erw [← FreeGroup.map.unique] <;> intros <;> rfl
  map_comp := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; ext1; erw [← FreeGroup.map.unique] <;> intros <;> 

Proof state:
case w
X✝ Y✝ Z✝ : Type u
f✝ : X✝ ⟶ Y✝
g✝ : Y✝ ⟶ Z✝
x✝ : ↑({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.obj X✝)
⊢ ?w.g x✝ =
    ({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.map f✝ ≫
        { obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.map g✝)
      x✝

Next tactic:
rfl
/-- The free functor `Type u ⥤ Group` sending a type `X` to the free group with generators `x : X`.
-/
def free : Type u ⥤ GroupCat where
  obj α := of (FreeGroup α)
  map := FreeGroup.map
  map_id := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; ext1; erw [← FreeGroup.map.unique] <;> intros <;> rfl
  map_comp := by
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    intros; ext1; erw [← FreeGroup.map.unique] <;> intros <;> 

Proof state:
case w.hg
X✝ Y✝ Z✝ : Type u
f✝ : X✝ ⟶ Y✝
g✝ : Y✝ ⟶ Z✝
x✝¹ : ↑({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.obj X✝)
x✝ : X✝
⊢ ({ obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.map f✝ ≫
        { obj := fun α => of (FreeGroup α), map := fun {X Y} => FreeGroup.map }.map g✝)
      (FreeGroup.of x✝) =
    FreeGroup.of ((f✝ ≫ g✝) x✝)

Next tactic:
rfl
/-- The free-forgetful adjunction for groups.
-/
def adj : free ⊣ forget GroupCat.{u} :=
  Adjunction.mkOfHomEquiv
    { homEquiv := fun X G => FreeGroup.lift.symm
      -- Porting note: used to be just `by intros; ext1; rfl`.
      homEquiv_naturality_left_symm := by
        

Proof state:
⊢ ∀ {X' X : Type u} {Y : GroupCat} (f : X' ⟶ X) (g : X ⟶ (forget GroupCat).obj Y),
    ((fun X G => FreeGroup.lift.symm) X' Y).symm (f ≫ g) = free.map f ≫ ((fun X G => FreeGroup.lift.symm) X Y).symm g

Next tactic:
intros
/-- The free-forgetful adjunction for groups.
-/
def adj : free ⊣ forget GroupCat.{u} :=
  Adjunction.mkOfHomEquiv
    { homEquiv := fun X G => FreeGroup.lift.symm
      -- Porting note: used to be just `by intros; ext1; rfl`.
      homEquiv_naturality_left_symm := by
        intros
        

Proof state:
X'✝ X✝ : Type u
Y✝ : GroupCat
f✝ : X'✝ ⟶ X✝
g✝ : X✝ ⟶ (forget GroupCat).obj Y✝
⊢ ((fun X G => FreeGroup.lift.symm) X'✝ Y✝).symm (f✝ ≫ g✝) =
    free.map f✝ ≫ ((fun X G => FreeGroup.lift.symm) X✝ Y✝).symm g✝

Next tactic:
ext1