l3lab/ntp-mathlib huggingface dataset:
theorem findGreatest_eq_iff :
    Nat.findGreatest P k = m ↔ m ≤ k ∧ (m ≠ 0 → P m) ∧ ∀ ⦃n⦄, m < n → n ≤ k → ¬P n := by
  induction' k with k ihk generalizing m
  · rw [eq_comm, Iff.comm]
    simp only [zero_eq, nonpos_iff_eq_zero, ne_eq, findGreatest_zero, and_iff_left_iff_imp]
    rintro rfl
    exact ⟨fun h => (h rfl).elim, fun n hlt heq => (hlt.ne heq.symm).elim⟩
  · by_cases hk : P (k + 1)
    · rw [findGreatest_eq hk]
      constructor
      · rintro rfl
        exact ⟨le_rfl, fun _ => hk, fun n hlt hle => (hlt.not_le hle).elim⟩
      · rintro ⟨hle, h0, hm⟩
        rcases Decidable.eq_or_lt_of_le hle with (rfl | hlt)
        exacts [rfl, (hm hlt le_rfl hk).elim]
    · rw [findGreatest_of_not hk, ihk]
      constructor
      · rintro ⟨hle, hP, hm⟩
        refine ⟨hle.trans k.le_succ, hP, fun n hlt hle => ?_⟩
        rcases Decidable.eq_or_lt_of_le hle with (rfl | hlt')
        exacts [hk, hm hlt <| lt_succ_iff.1 hlt']
      · rintro ⟨hle, hP, hm⟩
        

Proof state:
case neg.mpr.intro.intro
n l : ℕ
P Q : ℕ → Prop
inst✝ : DecidablePred P
k : ℕ
ihk : ∀ {m : ℕ}, Nat.findGreatest P k = m ↔ m ≤ k ∧ (m ≠ 0 → P m) ∧ ∀ ⦃n : ℕ⦄, m < n → n ≤ k → ¬P n
m : ℕ
hk : ¬P (k + 1)
hle : m ≤ succ k
hP : m ≠ 0 → P m
hm : ∀ ⦃n : ℕ⦄, m < n → n ≤ succ k → ¬P n
⊢ m ≤ k ∧ (m ≠ 0 → P m) ∧ ∀ ⦃n : ℕ⦄, m < n → n ≤ k → ¬P n

Next tactic:
refine ⟨lt_succ_iff.1 (hle.lt_of_ne ?_), hP, fun n hlt hle => hm hlt (hle.trans k.le_succ)⟩
theorem findGreatest_eq_iff :
    Nat.findGreatest P k = m ↔ m ≤ k ∧ (m ≠ 0 → P m) ∧ ∀ ⦃n⦄, m < n → n ≤ k → ¬P n := by
  induction' k with k ihk generalizing m
  · rw [eq_comm, Iff.comm]
    simp only [zero_eq, nonpos_iff_eq_zero, ne_eq, findGreatest_zero, and_iff_left_iff_imp]
    rintro rfl
    exact ⟨fun h => (h rfl).elim, fun n hlt heq => (hlt.ne heq.symm).elim⟩
  · by_cases hk : P (k + 1)
    · rw [findGreatest_eq hk]
      constructor
      · rintro rfl
        exact ⟨le_rfl, fun _ => hk, fun n hlt hle => (hlt.not_le hle).elim⟩
      · rintro ⟨hle, h0, hm⟩
        rcases Decidable.eq_or_lt_of_le hle with (rfl | hlt)
        exacts [rfl, (hm hlt le_rfl hk).elim]
    · rw [findGreatest_of_not hk, ihk]
      constructor
      · rintro ⟨hle, hP, hm⟩
        refine ⟨hle.trans k.le_succ, hP, fun n hlt hle => ?_⟩
        rcases Decidable.eq_or_lt_of_le hle with (rfl | hlt')
        exacts [hk, hm hlt <| lt_succ_iff.1 hlt']
      · rintro ⟨hle, hP, hm⟩
        refine ⟨lt_succ_iff.1 (hle.lt_of_ne ?_), hP, fun n hlt hle => hm hlt (hle.trans k.le_succ)⟩
        

Proof state:
case neg.mpr.intro.intro
n l : ℕ
P Q : ℕ → Prop
inst✝ : DecidablePred P
k : ℕ
ihk : ∀ {m : ℕ}, Nat.findGreatest P k = m ↔ m ≤ k ∧ (m ≠ 0 → P m) ∧ ∀ ⦃n : ℕ⦄, m < n → n ≤ k → ¬P n
m : ℕ
hk : ¬P (k + 1)
hle : m ≤ succ k
hP : m ≠ 0 → P m
hm : ∀ ⦃n : ℕ⦄, m < n → n ≤ succ k → ¬P n
⊢ m ≠ succ k

Next tactic:
rintro rfl
theorem findGreatest_eq_iff :
    Nat.findGreatest P k = m ↔ m ≤ k ∧ (m ≠ 0 → P m) ∧ ∀ ⦃n⦄, m < n → n ≤ k → ¬P n := by
  induction' k with k ihk generalizing m
  · rw [eq_comm, Iff.comm]
    simp only [zero_eq, nonpos_iff_eq_zero, ne_eq, findGreatest_zero, and_iff_left_iff_imp]
    rintro rfl
    exact ⟨fun h => (h rfl).elim, fun n hlt heq => (hlt.ne heq.symm).elim⟩
  · by_cases hk : P (k + 1)
    · rw [findGreatest_eq hk]
      constructor
      · rintro rfl
        exact ⟨le_rfl, fun _ => hk, fun n hlt hle => (hlt.not_le hle).elim⟩
      · rintro ⟨hle, h0, hm⟩
        rcases Decidable.eq_or_lt_of_le hle with (rfl | hlt)
        exacts [rfl, (hm hlt le_rfl hk).elim]
    · rw [findGreatest_of_not hk, ihk]
      constructor
      · rintro ⟨hle, hP, hm⟩
        refine ⟨hle.trans k.le_succ, hP, fun n hlt hle => ?_⟩
        rcases Decidable.eq_or_lt_of_le hle with (rfl | hlt')
        exacts [hk, hm hlt <| lt_succ_iff.1 hlt']
      · rintro ⟨hle, hP, hm⟩
        refine ⟨lt_succ_iff.1 (hle.lt_of_ne ?_), hP, fun n hlt hle => hm hlt (hle.trans k.le_succ)⟩
        rintro rfl
        

Proof state:
case neg.mpr.intro.intro
n l : ℕ
P Q : ℕ → Prop
inst✝ : DecidablePred P
k : ℕ
ihk : ∀ {m : ℕ}, Nat.findGreatest P k = m ↔ m ≤ k ∧ (m ≠ 0 → P m) ∧ ∀ ⦃n : ℕ⦄, m < n → n ≤ k → ¬P n
hk : ¬P (k + 1)
hle : succ k ≤ succ k
hP : succ k ≠ 0 → P (succ k)
hm : ∀ ⦃n : ℕ⦄, succ k < n → n ≤ succ k → ¬P n
⊢ False

Next tactic:
exact hk (hP k.succ_ne_zero)
theorem findGreatest_eq_zero_iff : Nat.findGreatest P k = 0 ↔ ∀ ⦃n⦄, 0 < n → n ≤ k → ¬P n := by
  

Proof state:
m n k l : ℕ
P Q : ℕ → Prop
inst✝ : DecidablePred P
⊢ Nat.findGreatest P k = 0 ↔ ∀ ⦃n : ℕ⦄, 0 < n → n ≤ k → ¬P n

Next tactic:
simp [findGreatest_eq_iff]
@[simp] lemma findGreatest_pos : 0 < Nat.findGreatest P k ↔ ∃ n, 0 < n ∧ n ≤ k ∧ P n := by
  

Proof state:
m n k l : ℕ
P Q : ℕ → Prop
inst✝ : DecidablePred P
⊢ 0 < Nat.findGreatest P k ↔ ∃ n, 0 < n ∧ n ≤ k ∧ P n

Next tactic:
rw [pos_iff_ne_zero, Ne.def, findGreatest_eq_zero_iff]
@[simp] lemma findGreatest_pos : 0 < Nat.findGreatest P k ↔ ∃ n, 0 < n ∧ n ≤ k ∧ P n := by
  rw [pos_iff_ne_zero, Ne.def, findGreatest_eq_zero_iff]; 

Proof state:
m n k l : ℕ
P Q : ℕ → Prop
inst✝ : DecidablePred P
⊢ (¬∀ ⦃n : ℕ⦄, 0 < n → n ≤ k → ¬P n) ↔ ∃ n, 0 < n ∧ n ≤ k ∧ P n

Next tactic:
push_neg
@[simp] lemma findGreatest_pos : 0 < Nat.findGreatest P k ↔ ∃ n, 0 < n ∧ n ≤ k ∧ P n := by
  rw [pos_iff_ne_zero, Ne.def, findGreatest_eq_zero_iff]; push_neg; 

Proof state:
m n k l : ℕ
P Q : ℕ → Prop
inst✝ : DecidablePred P
⊢ (Exists fun ⦃n⦄ => 0 < n ∧ n ≤ k ∧ P n) ↔ ∃ n, 0 < n ∧ n ≤ k ∧ P n

Next tactic:
rfl
theorem findGreatest_spec (hmb : m ≤ n) (hm : P m) : P (Nat.findGreatest P n) := by
  

Proof state:
m n k l : ℕ
P Q : ℕ → Prop
inst✝ : DecidablePred P
hmb : m ≤ n
hm : P m
⊢ P (Nat.findGreatest P n)

Next tactic:
by_cases h : Nat.findGreatest P n = 0
theorem findGreatest_spec (hmb : m ≤ n) (hm : P m) : P (Nat.findGreatest P n) := by
  by_cases h : Nat.findGreatest P n = 0
  · 

Proof state:
case pos
m n k l : ℕ
P Q : ℕ → Prop
inst✝ : DecidablePred P
hmb : m ≤ n
hm : P m
h : Nat.findGreatest P n = 0
⊢ P (Nat.findGreatest P n)

Next tactic:
cases m
theorem findGreatest_spec (hmb : m ≤ n) (hm : P m) : P (Nat.findGreatest P n) := by
  by_cases h : Nat.findGreatest P n = 0
  · cases m
    · 

Proof state:
case pos.zero
n k l : ℕ
P Q : ℕ → Prop
inst✝ : DecidablePred P
h : Nat.findGreatest P n = 0
hmb : zero ≤ n
hm : P zero
⊢ P (Nat.findGreatest P n)

Next tactic:
rwa [h]
theorem findGreatest_spec (hmb : m ≤ n) (hm : P m) : P (Nat.findGreatest P n) := by
  by_cases h : Nat.findGreatest P n = 0
  · cases m
    · rwa [h]
    

Proof state:
case pos.succ
n k l : ℕ
P Q : ℕ → Prop
inst✝ : DecidablePred P
h : Nat.findGreatest P n = 0
n✝ : ℕ
hmb : succ n✝ ≤ n
hm : P (succ n✝)
⊢ P (Nat.findGreatest P n)

Next tactic:
exact ((findGreatest_eq_zero_iff.1 h) (zero_lt_succ _) hmb hm).elim
theorem findGreatest_spec (hmb : m ≤ n) (hm : P m) : P (Nat.findGreatest P n) := by
  by_cases h : Nat.findGreatest P n = 0
  · cases m
    · rwa [h]
    exact ((findGreatest_eq_zero_iff.1 h) (zero_lt_succ _) hmb hm).elim
  · 

Proof state:
case neg
m n k l : ℕ
P Q : ℕ → Prop
inst✝ : DecidablePred P
hmb : m ≤ n
hm : P m
h : ¬Nat.findGreatest P n = 0
⊢ P (Nat.findGreatest P n)

Next tactic:
exact (findGreatest_eq_iff.1 rfl).2.1 h
theorem findGreatest_mono_right (P : ℕ → Prop) [DecidablePred P] :
    Monotone (Nat.findGreatest P) := by
  

Proof state:
m n k l : ℕ
P✝ Q : ℕ → Prop
inst✝¹ : DecidablePred P✝
P : ℕ → Prop
inst✝ : DecidablePred P
⊢ Monotone (Nat.findGreatest P)

Next tactic:
refine monotone_nat_of_le_succ fun n => ?_
theorem findGreatest_mono_right (P : ℕ → Prop) [DecidablePred P] :
    Monotone (Nat.findGreatest P) := by
  refine monotone_nat_of_le_succ fun n => ?_
  

Proof state:
m n✝ k l : ℕ
P✝ Q : ℕ → Prop
inst✝¹ : DecidablePred P✝
P : ℕ → Prop
inst✝ : DecidablePred P
n : ℕ
⊢ Nat.findGreatest P n ≤ Nat.findGreatest P (n + 1)

Next tactic:
rw [findGreatest_succ]
theorem findGreatest_mono_right (P : ℕ → Prop) [DecidablePred P] :
    Monotone (Nat.findGreatest P) := by
  refine monotone_nat_of_le_succ fun n => ?_
  rw [findGreatest_succ]
  

Proof state:
m n✝ k l : ℕ
P✝ Q : ℕ → Prop
inst✝¹ : DecidablePred P✝
P : ℕ → Prop
inst✝ : DecidablePred P
n : ℕ
⊢ Nat.findGreatest P n ≤ if P (n + 1) then n + 1 else Nat.findGreatest P n

Next tactic:
split_ifs
theorem findGreatest_mono_right (P : ℕ → Prop) [DecidablePred P] :
    Monotone (Nat.findGreatest P) := by
  refine monotone_nat_of_le_succ fun n => ?_
  rw [findGreatest_succ]
  split_ifs
  · 

Proof state:
case pos
m n✝ k l : ℕ
P✝ Q : ℕ → Prop
inst✝¹ : DecidablePred P✝
P : ℕ → Prop
inst✝ : DecidablePred P
n : ℕ
h✝ : P (n + 1)
⊢ Nat.findGreatest P n ≤ n + 1

Next tactic:
exact (findGreatest_le n).trans (le_succ _)
theorem findGreatest_mono_right (P : ℕ → Prop) [DecidablePred P] :
    Monotone (Nat.findGreatest P) := by
  refine monotone_nat_of_le_succ fun n => ?_
  rw [findGreatest_succ]
  split_ifs
  · exact (findGreatest_le n).trans (le_succ _)
  · 

Proof state:
case neg
m n✝ k l : ℕ
P✝ Q : ℕ → Prop
inst✝¹ : DecidablePred P✝
P : ℕ → Prop
inst✝ : DecidablePred P
n : ℕ
h✝ : ¬P (n + 1)
⊢ Nat.findGreatest P n ≤ Nat.findGreatest P n

Next tactic:
rfl
theorem findGreatest_mono_left [DecidablePred Q] (hPQ : P ≤ Q) :
    Nat.findGreatest P ≤ Nat.findGreatest Q := by
  

Proof state:
m n k l : ℕ
P Q : ℕ → Prop
inst✝¹ : DecidablePred P
inst✝ : DecidablePred Q
hPQ : P ≤ Q
⊢ Nat.findGreatest P ≤ Nat.findGreatest Q

Next tactic:
intro n
theorem findGreatest_mono_left [DecidablePred Q] (hPQ : P ≤ Q) :
    Nat.findGreatest P ≤ Nat.findGreatest Q := by
  intro n
  

Proof state:
m n✝ k l : ℕ
P Q : ℕ → Prop
inst✝¹ : DecidablePred P
inst✝ : DecidablePred Q
hPQ : P ≤ Q
n : ℕ
⊢ Nat.findGreatest P n ≤ Nat.findGreatest Q n

Next tactic:
induction' n with n hn
theorem findGreatest_mono_left [DecidablePred Q] (hPQ : P ≤ Q) :
    Nat.findGreatest P ≤ Nat.findGreatest Q := by
  intro n
  induction' n with n hn
  · 

Proof state:
case zero
m n k l : ℕ
P Q : ℕ → Prop
inst✝¹ : DecidablePred P
inst✝ : DecidablePred Q
hPQ : P ≤ Q
⊢ Nat.findGreatest P zero ≤ Nat.findGreatest Q zero

Next tactic:
rfl
theorem findGreatest_mono_left [DecidablePred Q] (hPQ : P ≤ Q) :
    Nat.findGreatest P ≤ Nat.findGreatest Q := by
  intro n
  induction' n with n hn
  · rfl
  

Proof state:
case succ
m n✝ k l : ℕ
P Q : ℕ → Prop
inst✝¹ : DecidablePred P
inst✝ : DecidablePred Q
hPQ : P ≤ Q
n : ℕ
hn : Nat.findGreatest P n ≤ Nat.findGreatest Q n
⊢ Nat.findGreatest P (succ n) ≤ Nat.findGreatest Q (succ n)

Next tactic:
by_cases h : P (n + 1)
theorem findGreatest_mono_left [DecidablePred Q] (hPQ : P ≤ Q) :
    Nat.findGreatest P ≤ Nat.findGreatest Q := by
  intro n
  induction' n with n hn
  · rfl
  by_cases h : P (n + 1)
  · 

Proof state:
case pos
m n✝ k l : ℕ
P Q : ℕ → Prop
inst✝¹ : DecidablePred P
inst✝ : DecidablePred Q
hPQ : P ≤ Q
n : ℕ
hn : Nat.findGreatest P n ≤ Nat.findGreatest Q n
h : P (n + 1)
⊢ Nat.findGreatest P (succ n) ≤ Nat.findGreatest Q (succ n)

Next tactic:
rw [findGreatest_eq h, findGreatest_eq (hPQ _ h)]
theorem findGreatest_mono_left [DecidablePred Q] (hPQ : P ≤ Q) :
    Nat.findGreatest P ≤ Nat.findGreatest Q := by
  intro n
  induction' n with n hn
  · rfl
  by_cases h : P (n + 1)
  · rw [findGreatest_eq h, findGreatest_eq (hPQ _ h)]
  · 

Proof state:
case neg
m n✝ k l : ℕ
P Q : ℕ → Prop
inst✝¹ : DecidablePred P
inst✝ : DecidablePred Q
hPQ : P ≤ Q
n : ℕ
hn : Nat.findGreatest P n ≤ Nat.findGreatest Q n
h : ¬P (n + 1)
⊢ Nat.findGreatest P (succ n) ≤ Nat.findGreatest Q (succ n)

Next tactic:
rw [findGreatest_of_not h]
theorem findGreatest_mono_left [DecidablePred Q] (hPQ : P ≤ Q) :
    Nat.findGreatest P ≤ Nat.findGreatest Q := by
  intro n
  induction' n with n hn
  · rfl
  by_cases h : P (n + 1)
  · rw [findGreatest_eq h, findGreatest_eq (hPQ _ h)]
  · rw [findGreatest_of_not h]
    

Proof state:
case neg
m n✝ k l : ℕ
P Q : ℕ → Prop
inst✝¹ : DecidablePred P
inst✝ : DecidablePred Q
hPQ : P ≤ Q
n : ℕ
hn : Nat.findGreatest P n ≤ Nat.findGreatest Q n
h : ¬P (n + 1)
⊢ Nat.findGreatest P n ≤ Nat.findGreatest Q (succ n)

Next tactic:
exact hn.trans (Nat.findGreatest_mono_right _ <| le_succ _)
@[simp]
theorem bit0_le_bit1_iff : bit0 m ≤ bit1 n ↔ m ≤ n :=
  ⟨fun h => by
    

Proof state:
m n k l : ℕ
h : bit0 m ≤ bit1 n
⊢ m ≤ n

Next tactic:
rwa [← Nat.lt_succ_iff, n.bit1_eq_succ_bit0,
    ← n.bit0_succ_eq, bit0_lt_bit0, Nat.lt_succ_iff] at h
@[simp]
theorem bit1_le_bit0_iff : bit1 m ≤ bit0 n ↔ m < n :=
  ⟨fun h => by 

Proof state:
m n k l : ℕ
h : bit1 m ≤ bit0 n
⊢ m < n

Next tactic:
rwa [m.bit1_eq_succ_bit0, succ_le_iff, bit0_lt_bit0] at h
instance decidableLoHi (lo hi : ℕ) (P : ℕ → Prop) [H : DecidablePred P] :
    Decidable (∀ x, lo ≤ x → x < hi → P x) :=
  decidable_of_iff (∀ x < hi - lo, P (lo + x))
    ⟨fun al x hl hh => by
      

Proof state:
m n k l lo hi : ℕ
P : ℕ → Prop
H : DecidablePred P
al : ∀ (x : ℕ), x < hi - lo → P (lo + x)
x : ℕ
hl : lo ≤ x
hh : x < hi
⊢ P x

Next tactic:
have := al (x - lo) ((tsub_lt_tsub_iff_right hl).mpr hh)
instance decidableLoHi (lo hi : ℕ) (P : ℕ → Prop) [H : DecidablePred P] :
    Decidable (∀ x, lo ≤ x → x < hi → P x) :=
  decidable_of_iff (∀ x < hi - lo, P (lo + x))
    ⟨fun al x hl hh => by
      have := al (x - lo) ((tsub_lt_tsub_iff_right hl).mpr hh)
      

Proof state:
m n k l lo hi : ℕ
P : ℕ → Prop
H : DecidablePred P
al : ∀ (x : ℕ), x < hi - lo → P (lo + x)
x : ℕ
hl : lo ≤ x
hh : x < hi
this : P (lo + (x - lo))
⊢ P x

Next tactic:
rwa [add_tsub_cancel_of_le hl] at this
theorem gcd_def (x y : ℕ) : gcd x y = if x = 0 then y else gcd (y % x) x := by
  

Proof state:
x y : ℕ
⊢ gcd x y = if x = 0 then y else gcd (y % x) x

Next tactic:
cases x
theorem gcd_def (x y : ℕ) : gcd x y = if x = 0 then y else gcd (y % x) x := by
  cases x <;> 

Proof state:
case zero
y : ℕ
⊢ gcd zero y = if zero = 0 then y else gcd (y % zero) zero

Next tactic:
simp [Nat.gcd_succ]
theorem gcd_def (x y : ℕ) : gcd x y = if x = 0 then y else gcd (y % x) x := by
  cases x <;> 

Proof state:
case succ
y n✝ : ℕ
⊢ gcd (succ n✝) y = if succ n✝ = 0 then y else gcd (y % succ n✝) (succ n✝)

Next tactic:
simp [Nat.gcd_succ]
@[to_additive]
instance concreteCategory : ConcreteCategory GroupCat := by
  

Proof state:
⊢ ConcreteCategory GroupCat

Next tactic:
dsimp only [GroupCat]
@[to_additive]
instance concreteCategory : ConcreteCategory GroupCat := by
  dsimp only [GroupCat]
  

Proof state:
⊢ ConcreteCategory (Bundled Group)

Next tactic:
infer_instance
@[to_additive]
example {R S : GroupCat} (i : R ⟶ S) (r : R) (h : r = 1) : i r = 1 := by 

Proof state:
R S : GroupCat
i : R ⟶ S
r : ↑R
h : r = 1
⊢ i r = 1

Next tactic:
simp [h]
@[to_additive]
instance concreteCategory : ConcreteCategory CommGroupCat := by
  

Proof state:
⊢ ConcreteCategory CommGroupCat

Next tactic:
dsimp only [CommGroupCat]
@[to_additive]
instance concreteCategory : ConcreteCategory CommGroupCat := by
  dsimp only [CommGroupCat]
  

Proof state:
⊢ ConcreteCategory (Bundled CommGroup)

Next tactic:
infer_instance
@[to_additive]
example {R S : CommGroupCat} (i : R ⟶ S) (r : R) (h : r = 1) : i r = 1 := by 

Proof state:
R S : CommGroupCat
i : R ⟶ S
r : ↑R
h : r = 1
⊢ i r = 1

Next tactic:
simp [h]
theorem asHom_injective {G : AddCommGroupCat.{0}} : Function.Injective (@asHom G) := fun h k w => by
  

Proof state:
G : AddCommGroupCat
h k : ↑G
w : asHom h = asHom k
⊢ h = k

Next tactic:
convert congr_arg (fun k : AddCommGroupCat.of ℤ ⟶ G => (k : ℤ → G) (1 : ℤ)) w
theorem asHom_injective {G : AddCommGroupCat.{0}} : Function.Injective (@asHom G) := fun h k w => by
  convert congr_arg (fun k : AddCommGroupCat.of ℤ ⟶ G => (k : ℤ → G) (1 : ℤ)) w <;> 

Proof state:
case h.e'_2
G : AddCommGroupCat
h k : ↑G
w : asHom h = asHom k
⊢ h = (asHom h) 1

Next tactic:
simp
theorem asHom_injective {G : AddCommGroupCat.{0}} : Function.Injective (@asHom G) := fun h k w => by
  convert congr_arg (fun k : AddCommGroupCat.of ℤ ⟶ G => (k : ℤ → G) (1 : ℤ)) w <;> 

Proof state:
case h.e'_3
G : AddCommGroupCat
h k : ↑G
w : asHom h = asHom k
⊢ k = (asHom k) 1

Next tactic:
simp
theorem injective_of_mono {G H : AddCommGroupCat.{0}} (f : G ⟶ H) [Mono f] : Function.Injective f :=
  fun g₁ g₂ h => by
  

Proof state:
G H : AddCommGroupCat
f : G ⟶ H
inst✝ : Mono f
g₁ g₂ : ↑G
h : f g₁ = f g₂
⊢ g₁ = g₂

Next tactic:
have t0 : asHom g₁ ≫ f = asHom g₂ ≫ f := by aesop_cat
theorem injective_of_mono {G H : AddCommGroupCat.{0}} (f : G ⟶ H) [Mono f] : Function.Injective f :=
  fun g₁ g₂ h => by
  have t0 : asHom g₁ ≫ f = asHom g₂ ≫ f := by 

Proof state:
G H : AddCommGroupCat
f : G ⟶ H
inst✝ : Mono f
g₁ g₂ : ↑G
h : f g₁ = f g₂
⊢ asHom g₁ ≫ f = asHom g₂ ≫ f

Next tactic:
aesop_cat
theorem injective_of_mono {G H : AddCommGroupCat.{0}} (f : G ⟶ H) [Mono f] : Function.Injective f :=
  fun g₁ g₂ h => by
  have t0 : asHom g₁ ≫ f = asHom g₂ ≫ f := by aesop_cat
  

Proof state:
G H : AddCommGroupCat
f : G ⟶ H
inst✝ : Mono f
g₁ g₂ : ↑G
h : f g₁ = f g₂
t0 : asHom g₁ ≫ f = asHom g₂ ≫ f
⊢ g₁ = g₂

Next tactic:
have t1 : asHom g₁ = asHom g₂ := (cancel_mono _).1 t0
theorem injective_of_mono {G H : AddCommGroupCat.{0}} (f : G ⟶ H) [Mono f] : Function.Injective f :=
  fun g₁ g₂ h => by
  have t0 : asHom g₁ ≫ f = asHom g₂ ≫ f := by aesop_cat
  have t1 : asHom g₁ = asHom g₂ := (cancel_mono _).1 t0
  

Proof state:
G H : AddCommGroupCat
f : G ⟶ H
inst✝ : Mono f
g₁ g₂ : ↑G
h : f g₁ = f g₂
t0 : asHom g₁ ≫ f = asHom g₂ ≫ f
t1 : asHom g₁ = asHom g₂
⊢ g₁ = g₂

Next tactic:
apply asHom_injective t1
/-- The (bundled) group of automorphisms of a type is isomorphic to the (bundled) group
of permutations. -/
def isoPerm {α : Type u} : GroupCat.of (Aut α) ≅ GroupCat.of (Equiv.Perm α) where
  hom :=
    { toFun := fun g => g.toEquiv
      map_one' := by 

Proof state:
α : Type u
⊢ (fun g => g.toEquiv) 1 = 1

Next tactic:
aesop
/-- The (bundled) group of automorphisms of a type is isomorphic to the (bundled) group
of permutations. -/
def isoPerm {α : Type u} : GroupCat.of (Aut α) ≅ GroupCat.of (Equiv.Perm α) where
  hom :=
    { toFun := fun g => g.toEquiv
      map_one' := by aesop
      map_mul' := by 

Proof state:
α : Type u
⊢ ∀ (x y : ↑(GroupCat.of (Aut α))),
    OneHom.toFun { toFun := fun g => g.toEquiv, map_one' := (_ : (fun g => g.toEquiv) 1 = 1) } (x * y) =
      OneHom.toFun { toFun := fun g => g.toEquiv, map_one' := (_ : (fun g => g.toEquiv) 1 = 1) } x *
        OneHom.toFun { toFun := fun g => g.toEquiv, map_one' := (_ : (fun g => g.toEquiv) 1 = 1) } y

Next tactic:
aesop
/-- The (bundled) group of automorphisms of a type is isomorphic to the (bundled) group
of permutations. -/
def isoPerm {α : Type u} : GroupCat.of (Aut α) ≅ GroupCat.of (Equiv.Perm α) where
  hom :=
    { toFun := fun g => g.toEquiv
      map_one' := by aesop
      map_mul' := by aesop }
  inv :=
    { toFun := fun g => g.toIso
      map_one' := by 

Proof state:
α : Type u
⊢ (fun g => Equiv.toIso g) 1 = 1

Next tactic:
aesop
/-- The (bundled) group of automorphisms of a type is isomorphic to the (bundled) group
of permutations. -/
def isoPerm {α : Type u} : GroupCat.of (Aut α) ≅ GroupCat.of (Equiv.Perm α) where
  hom :=
    { toFun := fun g => g.toEquiv
      map_one' := by aesop
      map_mul' := by aesop }
  inv :=
    { toFun := fun g => g.toIso
      map_one' := by aesop
      map_mul' := by 

Proof state:
α : Type u
⊢ ∀ (x y : ↑(GroupCat.of (Equiv.Perm α))),
    OneHom.toFun { toFun := fun g => Equiv.toIso g, map_one' := (_ : (fun g => Equiv.toIso g) 1 = 1) } (x * y) =
      OneHom.toFun { toFun := fun g => Equiv.toIso g, map_one' := (_ : (fun g => Equiv.toIso g) 1 = 1) } x *
        OneHom.toFun { toFun := fun g => Equiv.toIso g, map_one' := (_ : (fun g => Equiv.toIso g) 1 = 1) } y

Next tactic:
aesop
@[to_additive]
instance GroupCat.forget_reflects_isos : ReflectsIsomorphisms (forget GroupCat.{u}) where
  reflects {X Y} f _ := by
    

Proof state:
X Y : GroupCat
f : X ⟶ Y
x✝ : IsIso ((forget GroupCat).map f)
⊢ IsIso f

Next tactic:
let i := asIso ((forget GroupCat).map f)
@[to_additive]
instance GroupCat.forget_reflects_isos : ReflectsIsomorphisms (forget GroupCat.{u}) where
  reflects {X Y} f _ := by
    let i := asIso ((forget GroupCat).map f)
    

Proof state:
X Y : GroupCat
f : X ⟶ Y
x✝ : IsIso ((forget GroupCat).map f)
i : (forget GroupCat).obj X ≅ (forget GroupCat).obj Y := asIso ((forget GroupCat).map f)
⊢ IsIso f

Next tactic:
let e : X ≃* Y := { i.toEquiv with map_mul' := by aesop }
@[to_additive]
instance GroupCat.forget_reflects_isos : ReflectsIsomorphisms (forget GroupCat.{u}) where
  reflects {X Y} f _ := by
    let i := asIso ((forget GroupCat).map f)
    let e : X ≃* Y := { i.toEquiv with map_mul' := by 

Proof state:
X Y : GroupCat
f : X ⟶ Y
x✝ : IsIso ((forget GroupCat).map f)
i : (forget GroupCat).obj X ≅ (forget GroupCat).obj Y := asIso ((forget GroupCat).map f)
src✝ : (forget GroupCat).obj X ≃ (forget GroupCat).obj Y := i.toEquiv
⊢ ∀ (x y : ↑X),
    Equiv.toFun
        { toFun := src✝.toFun, invFun := src✝.invFun, left_inv := (_ : Function.LeftInverse src✝.invFun src✝.toFun),
          right_inv := (_ : Function.RightInverse src✝.invFun src✝.toFun) }
        (x * y) =
      Equiv.toFun
          { toFun := src✝.toFun, invFun := src✝.invFun, left_inv := (_ : Function.LeftInverse src✝.invFun src✝.toFun),
            right_inv := (_ : Function.RightInverse src✝.invFun src✝.toFun) }
          x *
        Equiv.toFun
          { toFun := src✝.toFun, invFun := src✝.invFun, left_inv := (_ : Function.LeftInverse src✝.invFun src✝.toFun),
            right_inv := (_ : Function.RightInverse src✝.invFun src✝.toFun) }
          y

Next tactic:
aesop
@[to_additive]
instance GroupCat.forget_reflects_isos : ReflectsIsomorphisms (forget GroupCat.{u}) where
  reflects {X Y} f _ := by
    let i := asIso ((forget GroupCat).map f)
    let e : X ≃* Y := { i.toEquiv with map_mul' := by aesop }
    

Proof state:
X Y : GroupCat
f : X ⟶ Y
x✝ : IsIso ((forget GroupCat).map f)
i : (forget GroupCat).obj X ≅ (forget GroupCat).obj Y := asIso ((forget GroupCat).map f)
e : ↑X ≃* ↑Y :=
  let src := i.toEquiv;
  {
    toEquiv :=
      { toFun := src.toFun, invFun := src.invFun, left_inv := (_ : Function.LeftInverse src.invFun src.toFun),
        right_inv := (_ : Function.RightInverse src.invFun src.toFun) },
    map_mul' := (_ : ∀ (x_1 y : ↑X), f (x_1 * y) = f x_1 * f y) }
⊢ IsIso f

Next tactic:
exact IsIso.of_iso e.toGroupCatIso
@[to_additive]
instance CommGroupCat.forget_reflects_isos : ReflectsIsomorphisms (forget CommGroupCat.{u}) where
  reflects {X Y} f _ := by
    

Proof state:
X Y : CommGroupCat
f : X ⟶ Y
x✝ : IsIso ((forget CommGroupCat).map f)
⊢ IsIso f

Next tactic:
let i := asIso ((forget CommGroupCat).map f)
@[to_additive]
instance CommGroupCat.forget_reflects_isos : ReflectsIsomorphisms (forget CommGroupCat.{u}) where
  reflects {X Y} f _ := by
    let i := asIso ((forget CommGroupCat).map f)
    

Proof state:
X Y : CommGroupCat
f : X ⟶ Y
x✝ : IsIso ((forget CommGroupCat).map f)
i : (forget CommGroupCat).obj X ≅ (forget CommGroupCat).obj Y := asIso ((forget CommGroupCat).map f)
⊢ IsIso f

Next tactic:
let e : X ≃* Y := { i.toEquiv with map_mul' := by aesop }
@[to_additive]
instance CommGroupCat.forget_reflects_isos : ReflectsIsomorphisms (forget CommGroupCat.{u}) where
  reflects {X Y} f _ := by
    let i := asIso ((forget CommGroupCat).map f)
    let e : X ≃* Y := { i.toEquiv with map_mul' := by 

Proof state:
X Y : CommGroupCat
f : X ⟶ Y
x✝ : IsIso ((forget CommGroupCat).map f)
i : (forget CommGroupCat).obj X ≅ (forget CommGroupCat).obj Y := asIso ((forget CommGroupCat).map f)
src✝ : (forget CommGroupCat).obj X ≃ (forget CommGroupCat).obj Y := i.toEquiv
⊢ ∀ (x y : ↑X),
    Equiv.toFun
        { toFun := src✝.toFun, invFun := src✝.invFun, left_inv := (_ : Function.LeftInverse src✝.invFun src✝.toFun),
          right_inv := (_ : Function.RightInverse src✝.invFun src✝.toFun) }
        (x * y) =
      Equiv.toFun
          { toFun := src✝.toFun, invFun := src✝.invFun, left_inv := (_ : Function.LeftInverse src✝.invFun src✝.toFun),
            right_inv := (_ : Function.RightInverse src✝.invFun src✝.toFun) }
          x *
        Equiv.toFun
          { toFun := src✝.toFun, invFun := src✝.invFun, left_inv := (_ : Function.LeftInverse src✝.invFun src✝.toFun),
            right_inv := (_ : Function.RightInverse src✝.invFun src✝.toFun) }
          y

Next tactic:
aesop