[System] You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Tactic.NormNum.Prime).

[User]
Prove the following theorem. The retrieved context below may help.

```lean
theorem isNat_minFac_2 : {a a' : ℕ} → IsNat a a' → a' % 2 = 0 → IsNat a.minFac 2
  | a, _, ⟨rfl⟩, h => ⟨by rw [cast_ofNat, minFac_eq_two_iff, Nat.dvd_iff_mod_eq_zero, h]⟩
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Tactic.NormNum.Prime.not_prime_mul_of_ble (L37-L42)
theorem not_prime_mul_of_ble (a b n : ℕ) (h : a * b = n) (h₁ : a.ble 1 = false)
    (h₂ : b.ble 1 = false) : ¬ n.Prime :=
not_prime_of_mul_eq h (ble_eq_false.mp h₁).ne' (ble_eq_false.mp h₂).ne'

/-- Produce a proof that `n` is not prime from a factor `1 < d < n`. `en` should be the expression
  that is the natural number literal `n`. -/
```

-- snippet 2
```lean
-- Mathlib.Tactic.NormNum.Prime.deriveNotPrime (L43-L50)
def deriveNotPrime (n d : ℕ) (en : Q(ℕ)) : Q(¬ Nat.Prime $en) := Id.run do
let d' : ℕ := n / d
  let prf : Q($d * $d' = $en) := (q(Eq.refl $en) : Expr)
  let r : Q(Nat.ble $d 1 = false) := (q(Eq.refl false) : Expr)
  let r' : Q(Nat.ble $d' 1 = false) := (q(Eq.refl false) : Expr)
  return q(not_prime_mul_of_ble _ _ _ $prf $r $r')

/-- A predicate representing partial progress in a proof of `minFac`. -/
```

-- snippet 3
```lean
-- Mathlib.Tactic.NormNum.Prime.MinFacHelper (L51-L53)
def MinFacHelper (n k : ℕ) : Prop :=
2 < k ∧ k % 2 = 1 ∧ k ≤ minFac n
```

-- snippet 4
```lean
-- Mathlib.Tactic.NormNum.Prime.MinFacHelper (L54-L61)
theorem MinFacHelper.one_lt {n k : ℕ} (h : MinFacHelper n k) : 1 < n := by
have : 2 < minFac n := h.1.trans_le h.2.2
  obtain rfl | h := n.eq_zero_or_pos
  · contradiction
  rcases (succ_le_of_lt h).eq_or_lt with rfl | h
  · simp_all
  exact h
```

-- snippet 5
```lean
-- Mathlib.Tactic.NormNum.Prime.minFacHelper_0 (L62-L70)
theorem minFacHelper_0 (n : ℕ)
    (h1 : Nat.ble (nat_lit 2) n = true) (h2 : nat_lit 1 = n % (nat_lit 2)) :
    MinFacHelper n (nat_lit 3) := by
refine ⟨by simp, by simp, ?_⟩
  refine (le_minFac'.mpr fun p hp hpn ↦ ?_).resolve_left (Nat.ne_of_gt (Nat.le_of_ble_eq_true h1))
  rcases hp.eq_or_lt with rfl | h
  · simp [(Nat.dvd_iff_mod_eq_zero ..).1 hpn] at h2
  · exact h
```

-- snippet 6
```lean
-- Mathlib.Tactic.NormNum.Prime.minFacHelper_1 (L71-L87)
theorem minFacHelper_1 {n k k' : ℕ} (e : k + 2 = k') (h : MinFacHelper n k)
    (np : minFac n ≠ k) : MinFacHelper n k' := by
rw [← e]
  refine ⟨Nat.lt_add_right _ h.1, ?_, ?_⟩
  · rw [add_mod, mod_self, add_zero, mod_mod]
    exact h.2.1
  rcases h.2.2.eq_or_lt with rfl | h2
  · exact (np rfl).elim
  rcases (succ_le_of_lt h2).eq_or_lt with h2|h2
  · refine ((h.1.trans_le h.2.2).ne ?_).elim
    have h3 : 2 ∣ minFac n := by
      rw [Nat.dvd_iff_mod_eq_zero, ← h2, succ_eq_add_one, add_mod, h.2.1]
    rw [dvd_prime <| minFac_prime h.one_lt.ne'] at h3
    norm_num at h3
    exact h3
  exact h2
```

-- snippet 7
```lean
-- Mathlib.Tactic.NormNum.Prime.minFacHelper_2 (L88-L93)
theorem minFacHelper_2 {n k k' : ℕ} (e : k + 2 = k') (nk : ¬ Nat.Prime k)
    (h : MinFacHelper n k) : MinFacHelper n k' := by
refine minFacHelper_1 e h fun h2 ↦ ?_
  rw [← h2] at nk
  exact nk <| minFac_prime h.one_lt.ne'
```

-- snippet 8
```lean
-- Mathlib.Tactic.NormNum.Prime.minFacHelper_3 (L94-L100)
theorem minFacHelper_3 {n k k' : ℕ} (e : k + 2 = k') (nk : (n % k).beq 0 = false)
    (h : MinFacHelper n k) : MinFacHelper n k' := by
refine minFacHelper_1 e h fun h2 ↦ ?_
  have nk := Nat.ne_of_beq_eq_false nk
  rw [← Nat.dvd_iff_mod_eq_zero, ← h2] at nk
  exact nk <| minFac_dvd n
```

-- snippet 9
```lean
-- Mathlib.Tactic.NormNum.Prime.isNat_minFac_1 (L101-L103)
theorem isNat_minFac_1 : {a : ℕ} → IsNat a (nat_lit 1) → IsNat a.minFac 1
  | _, ⟨rfl⟩ => ⟨minFac_one⟩
```

-- snippet 10
```lean
-- Mathlib.Tactic.NormNum.Prime.isNat_minFac_3 (L107-L112)
theorem isNat_minFac_3 : {n n' : ℕ} → (k : ℕ) →
    IsNat n n' → MinFacHelper n' k → nat_lit 0 = n' % k → IsNat (minFac n) k
  | n, _, k, ⟨rfl⟩, h1, h2 => by
    rw [eq_comm, ← Nat.dvd_iff_mod_eq_zero] at h2
    exact ⟨le_antisymm (minFac_le_of_dvd h1.1.le h2) h1.2.2⟩
```

-- snippet 11
```lean
-- Mathlib.Tactic.NormNum.Prime.isNat_minFac_4 (L113-L125)
theorem isNat_minFac_4 : {n n' k : ℕ} →
    IsNat n n' → MinFacHelper n' k → (k * k).ble n' = false → IsNat (minFac n) n'
  | n, _, k, ⟨rfl⟩, h1, h2 => by
    refine ⟨(Nat.prime_def_minFac.mp ?_).2⟩
    rw [Nat.prime_def_le_sqrt]
    refine ⟨h1.one_lt, fun m hm hmn h2mn ↦ ?_⟩
    exact lt_irrefl m <| calc
      m ≤ sqrt n := hmn
_ < k        := sqrt_lt.mpr (ble_eq_false.mp h2)
      _ ≤ n.minFac := h1.2.2
      _ ≤ m        := Nat.minFac_le_of_dvd hm h2mn

/-- The `norm_num` extension which identifies expressions of the form `minFac n`. -/
```

-- snippet 12
```lean
-- Mathlib.Tactic.NormNum.Prime.isNat_prime_0 (L170-L172)
theorem isNat_prime_0 : {n : ℕ} → IsNat n (nat_lit 0) → ¬ n.Prime
  | _, ⟨rfl⟩ => not_prime_zero
```

-- snippet 13
```lean
-- Mathlib.Tactic.NormNum.Prime.isNat_prime_1 (L173-L175)
theorem isNat_prime_1 : {n : ℕ} → IsNat n (nat_lit 1) → ¬ n.Prime
  | _, ⟨rfl⟩ => not_prime_one
```

-- snippet 14
```lean
-- Mathlib.Tactic.NormNum.Prime.isNat_prime_2 (L176-L179)
theorem isNat_prime_2 : {n n' : ℕ} →
    IsNat n n' → Nat.ble 2 n' = true → IsNat (minFac n') n' → n.Prime
  | _, _, ⟨rfl⟩, h1, ⟨h2⟩ => prime_def_minFac.mpr ⟨ble_eq.mp h1, h2⟩
```

-- snippet 15
```lean
-- Mathlib.Tactic.NormNum.Prime.isNat_not_prime (L180-L182)
theorem isNat_not_prime {n n' : ℕ} (h : IsNat n n') : ¬n'.Prime → ¬n.Prime := isNat.natElim h
/-- The `norm_num` extension which identifies expressions of the form `Nat.Prime n`. -/
```

-- snippet 16
```lean
-- Mathlib.Tactic.NormNum.Basic.isInt_negOfNat (L101-L106)
theorem isInt_negOfNat (m n : ℕ) (h : IsNat m n) : IsInt (Int.negOfNat m) (.negOfNat n) :=
⟨congr_arg Int.negOfNat h.1⟩

/-- `norm_num` extension for `Int.negOfNat`.

It's useful for calling `derive` with the numerator of an `.isNegNNRat` branch. -/
```

-- snippet 17
```lean
-- Mathlib.Tactic.NormNum.Basic.isRat_mul (L464-L483)
theorem isRat_mul {α} [Ring α] {f : α → α → α} {a b : α} {na nb nc : ℤ} {da db dc k : ℕ} :
    f = HMul.hMul → IsRat a na da → IsRat b nb db →
    Int.mul na nb = Int.mul k nc →
    Nat.mul da db = Nat.mul k dc →
    IsRat (f a b) nc dc := by
rintro rfl ⟨_, rfl⟩ ⟨_, rfl⟩ (h₁ : na * nb = k * nc) (h₂ : da * db = k * dc)
  have : Invertible (↑(da * db) : α) := by simpa using invertibleMul (da:α) db
  have := invertibleOfMul' (α := α) h₂
  refine ⟨this, ?_⟩
  have H := (Nat.cast_commute (α := α) da db).invOf_left.invOf_right.right_comm
  have h₁ := congr_arg (Int.cast (R := α)) h₁
  simp only [Int.cast_mul, Int.cast_natCast] at h₁
  simp only [← mul_assoc, (Nat.cast_commute (α := α) da nb).invOf_left.right_comm, h₁]
  have h₂ := congr_arg (↑nc * ↑· * (⅟↑da * ⅟↑db * ⅟↑dc : α)) h₂
  simp only [Nat.cast_mul, ← mul_assoc] at h₂; rw [H] at h₂
  simp only [mul_invOf_cancel_right'] at h₂; rw [h₂, Nat.cast_commute]
  simp only [mul_invOf_cancel_right,
    (Nat.cast_commute (α := α) da dc).invOf_left.invOf_right.right_comm,
    (Nat.cast_commute (α := α) db dc).invOf_left.invOf_right.right_comm]
```

-- snippet 18
```lean
-- Mathlib.Tactic.NormNum.Abs.isNNRat_abs_nonneg (L36-L44)
theorem isNNRat_abs_nonneg {α : Type*} [DivisionRing α] [LinearOrder α]
    [IsStrictOrderedRing α] {a : α} {num den : ℕ} (ra : IsNNRat a num den) :
    IsNNRat |a| num den := by
obtain ⟨ha1, rfl⟩ := ra
  refine ⟨ha1, abs_of_nonneg ?_⟩
  apply mul_nonneg
  · exact Nat.cast_nonneg' num
  · simp only [invOf_eq_inv, inv_nonneg, Nat.cast_nonneg]
```

-- snippet 19
```lean
-- Mathlib.Tactic.NormNum.Basic.isNat_zero (L56-L59)
theorem isNat_zero (α) [AddMonoidWithOne α] : IsNat (Zero.zero : α) (nat_lit 0) :=
⟨Nat.cast_zero.symm⟩

/-- The `norm_num` extension which identifies the expression `Zero.zero`, returning `0`. -/
```

-- snippet 20
```lean
-- Mathlib.Tactic.NormNum.Basic.inferDivisionSemiring (L563-L566)
def inferDivisionSemiring {u : Level} (α : Q(Type u)) : MetaM Q(DivisionSemiring $α) :=
return ← synthInstanceQ q(DivisionSemiring $α) <|> throwError "not a division semiring"

/-- Helper function to synthesize a typed `DivisionRing α` expression. -/
```

-- snippet 21
```lean
-- Mathlib.Tactic.NormNum.Basic.evalNegOfNat (L108-L114)
def evalNegOfNat : NormNumExt where eval {u αZ} e := do
match u, αZ, e with
  | 0, ~q(ℤ), ~q(Int.negOfNat $a) =>
    let ⟨n, pn⟩ ← deriveNat (u := 0) a q(inferInstance)
    return .isNegNat q(inferInstance) n q(isInt_negOfNat $a $n $pn)
  | _ => failure
```

-- snippet 22
```lean
-- Mathlib.Tactic.NormNum.Basic.isNat_intCast (L147-L149)
theorem isNat_intCast {R} [Ring R] (n : ℤ) (m : ℕ) :
    IsNat n m → IsNat (n : R) m := by rintro ⟨⟨⟩⟩; exact ⟨by simp⟩
```

-- snippet 23
```lean
-- Mathlib.Tactic.NormNum.Basic.IsInt (L48-L55)
theorem IsInt.raw_refl (n : ℤ) : IsInt n n := ⟨rfl⟩
meta section

open Lean Meta Qq

/-! ### Constructors and constants -/
```

-- snippet 24
```lean
-- Mathlib.Tactic.NormNum.Abs.isNat_abs_neg (L30-L35)
theorem isNat_abs_neg {α : Type*} [Ring α] [Lattice α] [IsOrderedRing α]
    {a : α} {na : ℕ} (pa : IsInt a (.negOfNat na)) : IsNat |a| na := by
rw [pa.out]
  constructor
  simp
```

-- snippet 25
```lean
-- Mathlib.Tactic.NormNum.Basic.isNat_ofNat (L73-L76)
theorem isNat_ofNat (α : Type u) [AddMonoidWithOne α] {a : α} {n : ℕ}
    (h : n = a) : IsNat a n := ⟨h.symm⟩
/-- The `norm_num` extension which identifies an expression `OfNat.ofNat n`, returning `n`. -/
```

-- snippet 26
```lean
-- Mathlib.Tactic.NormNum.Basic.eq_of_true (L630-L630)
theorem eq_of_true {a b : Prop} (ha : a) (hb : b) : a = b := propext (iff_of_true ha hb)
```

-- snippet 27
```lean
-- Mathlib.Tactic.NormNum.Basic.isRat_add (L218-L238)
theorem isRat_add {α} [Ring α] {f : α → α → α} {a b : α} {na nb nc : ℤ} {da db dc k : ℕ} :
    f = HAdd.hAdd → IsRat a na da → IsRat b nb db →
    Int.add (Int.mul na db) (Int.mul nb da) = Int.mul k nc →
    Nat.mul da db = Nat.mul k dc →
    IsRat (f a b) nc dc := by
rintro rfl ⟨_, rfl⟩ ⟨_, rfl⟩ (h₁ : na * db + nb * da = k * nc) (h₂ : da * db = k * dc)
  have : Invertible (↑(da * db) : α) := by simpa using invertibleMul (da:α) db
  have := invertibleOfMul' (α := α) h₂
  use this
  have H := (Nat.cast_commute (α := α) da db).invOf_left.invOf_right.right_comm
  have h₁ := congr_arg (↑· * (⅟↑da * ⅟↑db : α)) h₁
  simp only [Int.cast_add, Int.cast_mul, Int.cast_natCast, ← mul_assoc,
    add_mul, mul_invOf_cancel_right] at h₁
  have h₂ := congr_arg (↑nc * ↑· * (⅟↑da * ⅟↑db * ⅟↑dc : α)) h₂
  simp only [H, mul_invOf_cancel_right', Nat.cast_mul, ← mul_assoc] at h₁ h₂
  rw [h₁, h₂, Nat.cast_commute]
  simp only [mul_invOf_cancel_right,
    (Nat.cast_commute (α := α) da dc).invOf_left.invOf_right.right_comm,
    (Nat.cast_commute (α := α) db dc).invOf_left.invOf_right.right_comm]

/-- Consider an `Option` as an object in the `MetaM` monad, by throwing an error on `none`. -/
```

-- snippet 28
```lean
-- Mathlib.Tactic.NormNum.Basic.isNat_one (L65-L67)
theorem isNat_one (α) [AddMonoidWithOne α] : IsNat (One.one : α) (nat_lit 1) := ⟨Nat.cast_one.symm⟩
/-- The `norm_num` extension which identifies the expression `One.one`, returning `1`. -/
```

-- snippet 29
```lean
-- Mathlib.Tactic.NormNum.Basic.isNNRat_mul (L444-L463)
theorem isNNRat_mul {α} [Semiring α] {f : α → α → α} {a b : α} {na nb nc : ℕ} {da db dc k : ℕ} :
    f = HMul.hMul → IsNNRat a na da → IsNNRat b nb db →
    Nat.mul na nb = Nat.mul k nc →
    Nat.mul da db = Nat.mul k dc →
    IsNNRat (f a b) nc dc := by
rintro rfl ⟨_, rfl⟩ ⟨_, rfl⟩ (h₁ : na * nb = k * nc) (h₂ : da * db = k * dc)
  have : Invertible (↑(da * db) : α) := by simpa using invertibleMul (da:α) db
  have := invertibleOfMul' (α := α) h₂
  refine ⟨this, ?_⟩
  have H := (Nat.cast_commute (α := α) da db).invOf_left.invOf_right.right_comm
  have h₁ := congr_arg (Nat.cast (R := α)) h₁
  simp only [Nat.cast_mul] at h₁
  simp only [← mul_assoc, (Nat.cast_commute (α := α) da nb).invOf_left.right_comm, h₁]
  have h₂ := congr_arg (↑nc * ↑· * (⅟↑da * ⅟↑db * ⅟↑dc : α)) h₂
  simp only [Nat.cast_mul, ← mul_assoc] at h₂; rw [H] at h₂
  simp only [mul_invOf_cancel_right'] at h₂; rw [h₂, Nat.cast_commute]
  simp only [mul_invOf_cancel_right',
    (Nat.cast_commute (α := α) da dc).invOf_left.invOf_right.right_comm,
    (Nat.cast_commute (α := α) db dc).invOf_left.invOf_right.right_comm]
```

-- snippet 30
```lean
-- Mathlib.Tactic.NormNum.Basic.isNNRat_add (L196-L217)
theorem isNNRat_add {α} [Semiring α] {f : α → α → α} {a b : α} {na nb nc : ℕ} {da db dc k : ℕ} :
    f = HAdd.hAdd → IsNNRat a na da → IsNNRat b nb db →
    Nat.add (Nat.mul na db) (Nat.mul nb da) = Nat.mul k nc →
    Nat.mul da db = Nat.mul k dc →
    IsNNRat (f a b) nc dc := by
rintro rfl ⟨_, rfl⟩ ⟨_, rfl⟩ (h₁ : na * db + nb * da = k * nc) (h₂ : da * db = k * dc)
  have : Invertible (↑(da * db) : α) := by simpa using invertibleMul (da:α) db
  have := invertibleOfMul' (α := α) h₂
  use this
  have H := (Nat.cast_commute (α := α) da db).invOf_left.invOf_right.right_comm
  have h₁ := congr_arg (↑· * (⅟↑da * ⅟↑db : α)) h₁
  simp only [Nat.cast_add, Nat.cast_mul, ← mul_assoc,
    add_mul, mul_invOf_cancel_right] at h₁
  have h₂ := congr_arg (↑nc * ↑· * (⅟↑da * ⅟↑db * ⅟↑dc : α)) h₂
  simp only [H, mul_invOf_cancel_right', Nat.cast_mul, ← mul_assoc] at h₁ h₂
  rw [h₁, h₂, Nat.cast_commute]
  simp only [mul_invOf_cancel_right,
    (Nat.cast_commute (α := α) da dc).invOf_left.invOf_right.right_comm,
    (Nat.cast_commute (α := α) db dc).invOf_left.invOf_right.right_comm]

-- TODO: clean up and move it somewhere in mathlib? It's a bit much for this file
-- see note [norm_num lemma function equality]
```

-- snippet 31
```lean
-- Mathlib.Tactic.NormNum.Basic.ne_of_false_of_true (L631-L631)
theorem ne_of_false_of_true {a b : Prop} (ha : ¬a) (hb : b) : a ≠ b := mt (· ▸ hb) ha
```

-- snippet 32
```lean
-- Mathlib.Tactic.NormNum.Basic.isRat_sub (L377-L385)
theorem isRat_sub {α} [Ring α] {f : α → α → α} {a b : α} {na nb nc : ℤ} {da db dc k : ℕ}
    (hf : f = HSub.hSub) (ra : IsRat a na da) (rb : IsRat b nb db)
    (h₁ : Int.sub (Int.mul na db) (Int.mul nb da) = Int.mul k nc)
    (h₂ : Nat.mul da db = Nat.mul k dc) :
    IsRat (f a b) nc dc := by
rw [hf, sub_eq_add_neg]
  refine isRat_add rfl ra (isRat_neg (n' := -nb) rfl rb rfl) (k := k) (nc := nc) ?_ h₂
  rw [show Int.mul (-nb) _ = _ from neg_mul ..]; exact h₁
```

-- snippet 33
```lean
-- Mathlib.Tactic.NormNum.Abs.isNNRat_abs_neg (L45-L55)
theorem isNNRat_abs_neg {α : Type*} [DivisionRing α] [LinearOrder α] [IsStrictOrderedRing α]
    {a : α} {num den : ℕ} (ra : IsRat a (.negOfNat num) den) : IsNNRat |a| num den := by
obtain ⟨ha1, rfl⟩ := ra
  simp only [Int.cast_negOfNat, neg_mul, abs_neg]
  refine ⟨ha1, abs_of_nonneg ?_⟩
  apply mul_nonneg
  · exact Nat.cast_nonneg' num
  · simp only [invOf_eq_inv, inv_nonneg, Nat.cast_nonneg]

/-- The `norm_num` extension which identifies expressions of the form `|a|`,
such that `norm_num` successfully recognises `a`. -/
```

-- snippet 34
```lean
-- Mathlib.Tactic.NormNum.Basic.isNat_natCast (L135-L138)
theorem isNat_natCast {R} [AddMonoidWithOne R] (n m : ℕ) :
    IsNat n m → IsNat (n : R) m := by rintro ⟨⟨⟩⟩; exact ⟨rfl⟩
/-- The `norm_num` extension which identifies an expression `Nat.cast n`, returning `n`. -/
```

-- snippet 35
```lean
-- Mathlib.Tactic.NormNum.Basic.inferDivisionRing (L567-L569)
def inferDivisionRing {u : Level} (α : Q(Type u)) : MetaM Q(DivisionRing $α) :=
return ← synthInstanceQ q(DivisionRing $α) <|> throwError "not a division ring"
```

-- snippet 36
```lean
-- Mathlib.Tactic.NormNum.Abs.isNat_abs_nonneg (L24-L29)
theorem isNat_abs_nonneg {α : Type*} [Ring α] [Lattice α] [IsOrderedRing α]
    {a : α} {na : ℕ} (pa : IsNat a na) : IsNat |a| na := by
rw [pa.out, Nat.abs_cast]
  constructor
  rfl
```

-- snippet 37
```lean
-- Mathlib.Tactic.NormNum.Basic.Result (L247-L304)
def Result.add {u : Level} {α : Q(Type u)} {a b : Q($α)} (ra : Result q($a)) (rb : Result q($b))
    (inst : Q(Add $α) := by exact q(delta% inferInstance)) :
MetaM (Result q($a + $b)) := do
  let rec intArm (rα : Q(Ring $α)) := do
    assumeInstancesCommute
    let ⟨za, na, pa⟩ ← ra.toInt _; let ⟨zb, nb, pb⟩ ← rb.toInt _
    let zc := za + zb
    have c := mkRawIntLit zc
    haveI' : Int.add $na $nb =Q $c := ⟨⟩
    return .isInt rα c zc q(isInt_add (.refl _) $pa $pb (.refl $c))
  let rec nnratArm (dsα : Q(DivisionSemiring $α)) : MetaM (Result _) := do
    assumeInstancesCommute
    let ⟨qa, na, da, pa⟩ ← ra.toNNRat' dsα; let ⟨qb, nb, db, pb⟩ ← rb.toNNRat' dsα
    let qc := qa + qb
    let dd := qa.den * qb.den
    let k := dd / qc.den
    have t1 : Q(ℕ) := mkRawNatLit (k * qc.num.toNat)
    have t2 : Q(ℕ) := mkRawNatLit dd
    have nc : Q(ℕ) := mkRawNatLit qc.num.toNat
    have dc : Q(ℕ) := mkRawNatLit qc.den
    have k : Q(ℕ) := mkRawNatLit k
    let r1 : Q(Nat.add (Nat.mul $na $db) (Nat.mul $nb $da) = Nat.mul $k $nc) :=
      (q(Eq.refl $t1) : Expr)
    let r2 : Q(Nat.mul $da $db = Nat.mul $k $dc) := (q(Eq.refl $t2) : Expr)
    return .isNNRat' dsα qc nc dc q(isNNRat_add (.refl _) $pa $pb $r1 $r2)
  let rec ratArm (dα : Q(DivisionRing $α)) : MetaM (Result _) := do
    assumeInstancesCommute
    let ⟨qa, na, da, pa⟩ ← ra.toRat' dα; let ⟨qb, nb, db, pb⟩ ← rb.toRat' dα
    let qc := qa + qb
    let dd := qa.den * qb.den
    let k := dd / qc.den
    have t1 : Q(ℤ) := mkRawIntLit (k * qc.num)
    have t2 : Q(ℕ) := mkRawNatLit dd
    have nc : Q(ℤ) := mkRawIntLit qc.num
    have dc : Q(ℕ) := mkRawNatLit qc.den
    have k : Q(ℕ) := mkRawNatLit k
    let r1 : Q(Int.add (Int.mul $na $db) (Int.mul $nb $da) = Int.mul $k $nc) :=
      (q(Eq.refl $t1) : Expr)
    let r2 : Q(Nat.mul $da $db = Nat.mul $k $dc) := (q(Eq.refl $t2) : Expr)
    return .isRat dα qc nc dc q(isRat_add (.refl _) $pa $pb $r1 $r2)
  match ra, rb with
  | .isBool .., _ | _, .isBool .. => failure
  | .isNegNNRat dα .., _ | _, .isNegNNRat dα .. => ratArm dα
  -- mixing positive rationals and negative naturals means we need to use the full rat handler
  | .isNNRat _dsα .., .isNegNat _rα .. | .isNegNat _rα .., .isNNRat _dsα .. =>
    -- could alternatively try to combine `rα` and `dsα` here, but we'd have to do a defeq check
    -- so would still need to be in `MetaM`.
    let dα ← synthInstanceQ q(DivisionRing $α)
    assumeInstancesCommute
    ratArm q($dα)
  | .isNNRat dsα .., _ | _, .isNNRat dsα .. => nnratArm dsα
  | .isNegNat rα .., _ | _, .isNegNat rα .. => intArm rα
  | .isNat _ na pa, .isNat sα nb pb =>
    assumeInstancesCommute
    have c : Q(ℕ) := mkRawNatLit (na.natLit! + nb.natLit!)
    haveI' : Nat.add $na $nb =Q $c := ⟨⟩
    return .isNat sα c q(isNat_add (.refl _) $pa $pb (.refl $c))
```

-- snippet 38
```lean
-- Mathlib.Tactic.NormNum.Basic.ble_eq_false (L616-L618)
theorem ble_eq_false {x y : ℕ} : x.ble y = false ↔ y < x := by
rw [← Nat.not_le, ← Bool.not_eq_true, Nat.ble_eq]
```

-- snippet 39
```lean
-- Mathlib.Tactic.NormNum.Basic.invertibleOfMul' (L45-L47)
def invertibleOfMul' {α} [Semiring α] {a k b : ℕ} [Invertible (a : α)]
    (h : a = k * b) : Invertible (b : α) := invertibleOfMul k (b:α) ↑a (by simp [h])
```

-- snippet 40
```lean
-- Mathlib.Tactic.NormNum.Basic.isintCast (L150-L153)
theorem isintCast {R} [Ring R] (n m : ℤ) :
    IsInt n m → IsInt (n : R) m := by rintro ⟨⟨⟩⟩; exact ⟨rfl⟩
/-- The `norm_num` extension which identifies an expression `Int.cast n`, returning `n`. -/
```

<s>[SYSTEM_PROMPT]You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Tactic.NormNum.Prime).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]Prove the following theorem. The retrieved context below may help.

```lean
theorem isNat_minFac_2 : {a a' : ℕ} → IsNat a a' → a' % 2 = 0 → IsNat a.minFac 2
  | a, _, ⟨rfl⟩, h => ⟨by rw [cast_ofNat, minFac_eq_two_iff, Nat.dvd_iff_mod_eq_zero, h]⟩
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Tactic.NormNum.Prime.not_prime_mul_of_ble (L37-L42)
theorem not_prime_mul_of_ble (a b n : ℕ) (h : a * b = n) (h₁ : a.ble 1 = false)
    (h₂ : b.ble 1 = false) : ¬ n.Prime :=
not_prime_of_mul_eq h (ble_eq_false.mp h₁).ne' (ble_eq_false.mp h₂).ne'

/-- Produce a proof that `n` is not prime from a factor `1 < d < n`. `en` should be the expression
  that is the natural number literal `n`. -/
```

-- snippet 2
```lean
-- Mathlib.Tactic.NormNum.Prime.deriveNotPrime (L43-L50)
def deriveNotPrime (n d : ℕ) (en : Q(ℕ)) : Q(¬ Nat.Prime $en) := Id.run do
let d' : ℕ := n / d
  let prf : Q($d * $d' = $en) := (q(Eq.refl $en) : Expr)
  let r : Q(Nat.ble $d 1 = false) := (q(Eq.refl false) : Expr)
  let r' : Q(Nat.ble $d' 1 = false) := (q(Eq.refl false) : Expr)
  return q(not_prime_mul_of_ble _ _ _ $prf $r $r')

/-- A predicate representing partial progress in a proof of `minFac`. -/
```

-- snippet 3
```lean
-- Mathlib.Tactic.NormNum.Prime.MinFacHelper (L51-L53)
def MinFacHelper (n k : ℕ) : Prop :=
2 < k ∧ k % 2 = 1 ∧ k ≤ minFac n
```

-- snippet 4
```lean
-- Mathlib.Tactic.NormNum.Prime.MinFacHelper (L54-L61)
theorem MinFacHelper.one_lt {n k : ℕ} (h : MinFacHelper n k) : 1 < n := by
have : 2 < minFac n := h.1.trans_le h.2.2
  obtain rfl | h := n.eq_zero_or_pos
  · contradiction
  rcases (succ_le_of_lt h).eq_or_lt with rfl | h
  · simp_all
  exact h
```

-- snippet 5
```lean
-- Mathlib.Tactic.NormNum.Prime.minFacHelper_0 (L62-L70)
theorem minFacHelper_0 (n : ℕ)
    (h1 : Nat.ble (nat_lit 2) n = true) (h2 : nat_lit 1 = n % (nat_lit 2)) :
    MinFacHelper n (nat_lit 3) := by
refine ⟨by simp, by simp, ?_⟩
  refine (le_minFac'.mpr fun p hp hpn ↦ ?_).resolve_left (Nat.ne_of_gt (Nat.le_of_ble_eq_true h1))
  rcases hp.eq_or_lt with rfl | h
  · simp [(Nat.dvd_iff_mod_eq_zero ..).1 hpn] at h2
  · exact h
```

-- snippet 6
```lean
-- Mathlib.Tactic.NormNum.Prime.minFacHelper_1 (L71-L87)
theorem minFacHelper_1 {n k k' : ℕ} (e : k + 2 = k') (h : MinFacHelper n k)
    (np : minFac n ≠ k) : MinFacHelper n k' := by
rw [← e]
  refine ⟨Nat.lt_add_right _ h.1, ?_, ?_⟩
  · rw [add_mod, mod_self, add_zero, mod_mod]
    exact h.2.1
  rcases h.2.2.eq_or_lt with rfl | h2
  · exact (np rfl).elim
  rcases (succ_le_of_lt h2).eq_or_lt with h2|h2
  · refine ((h.1.trans_le h.2.2).ne ?_).elim
    have h3 : 2 ∣ minFac n := by
      rw [Nat.dvd_iff_mod_eq_zero, ← h2, succ_eq_add_one, add_mod, h.2.1]
    rw [dvd_prime <| minFac_prime h.one_lt.ne'] at h3
    norm_num at h3
    exact h3
  exact h2
```

-- snippet 7
```lean
-- Mathlib.Tactic.NormNum.Prime.minFacHelper_2 (L88-L93)
theorem minFacHelper_2 {n k k' : ℕ} (e : k + 2 = k') (nk : ¬ Nat.Prime k)
    (h : MinFacHelper n k) : MinFacHelper n k' := by
refine minFacHelper_1 e h fun h2 ↦ ?_
  rw [← h2] at nk
  exact nk <| minFac_prime h.one_lt.ne'
```

-- snippet 8
```lean
-- Mathlib.Tactic.NormNum.Prime.minFacHelper_3 (L94-L100)
theorem minFacHelper_3 {n k k' : ℕ} (e : k + 2 = k') (nk : (n % k).beq 0 = false)
    (h : MinFacHelper n k) : MinFacHelper n k' := by
refine minFacHelper_1 e h fun h2 ↦ ?_
  have nk := Nat.ne_of_beq_eq_false nk
  rw [← Nat.dvd_iff_mod_eq_zero, ← h2] at nk
  exact nk <| minFac_dvd n
```

-- snippet 9
```lean
-- Mathlib.Tactic.NormNum.Prime.isNat_minFac_1 (L101-L103)
theorem isNat_minFac_1 : {a : ℕ} → IsNat a (nat_lit 1) → IsNat a.minFac 1
  | _, ⟨rfl⟩ => ⟨minFac_one⟩
```

-- snippet 10
```lean
-- Mathlib.Tactic.NormNum.Prime.isNat_minFac_3 (L107-L112)
theorem isNat_minFac_3 : {n n' : ℕ} → (k : ℕ) →
    IsNat n n' → MinFacHelper n' k → nat_lit 0 = n' % k → IsNat (minFac n) k
  | n, _, k, ⟨rfl⟩, h1, h2 => by
    rw [eq_comm, ← Nat.dvd_iff_mod_eq_zero] at h2
    exact ⟨le_antisymm (minFac_le_of_dvd h1.1.le h2) h1.2.2⟩
```

-- snippet 11
```lean
-- Mathlib.Tactic.NormNum.Prime.isNat_minFac_4 (L113-L125)
theorem isNat_minFac_4 : {n n' k : ℕ} →
    IsNat n n' → MinFacHelper n' k → (k * k).ble n' = false → IsNat (minFac n) n'
  | n, _, k, ⟨rfl⟩, h1, h2 => by
    refine ⟨(Nat.prime_def_minFac.mp ?_).2⟩
    rw [Nat.prime_def_le_sqrt]
    refine ⟨h1.one_lt, fun m hm hmn h2mn ↦ ?_⟩
    exact lt_irrefl m <| calc
      m ≤ sqrt n := hmn
_ < k        := sqrt_lt.mpr (ble_eq_false.mp h2)
      _ ≤ n.minFac := h1.2.2
      _ ≤ m        := Nat.minFac_le_of_dvd hm h2mn

/-- The `norm_num` extension which identifies expressions of the form `minFac n`. -/
```

-- snippet 12
```lean
-- Mathlib.Tactic.NormNum.Prime.isNat_prime_0 (L170-L172)
theorem isNat_prime_0 : {n : ℕ} → IsNat n (nat_lit 0) → ¬ n.Prime
  | _, ⟨rfl⟩ => not_prime_zero
```

-- snippet 13
```lean
-- Mathlib.Tactic.NormNum.Prime.isNat_prime_1 (L173-L175)
theorem isNat_prime_1 : {n : ℕ} → IsNat n (nat_lit 1) → ¬ n.Prime
  | _, ⟨rfl⟩ => not_prime_one
```

-- snippet 14
```lean
-- Mathlib.Tactic.NormNum.Prime.isNat_prime_2 (L176-L179)
theorem isNat_prime_2 : {n n' : ℕ} →
    IsNat n n' → Nat.ble 2 n' = true → IsNat (minFac n') n' → n.Prime
  | _, _, ⟨rfl⟩, h1, ⟨h2⟩ => prime_def_minFac.mpr ⟨ble_eq.mp h1, h2⟩
```

-- snippet 15
```lean
-- Mathlib.Tactic.NormNum.Prime.isNat_not_prime (L180-L182)
theorem isNat_not_prime {n n' : ℕ} (h : IsNat n n') : ¬n'.Prime → ¬n.Prime := isNat.natElim h
/-- The `norm_num` extension which identifies expressions of the form `Nat.Prime n`. -/
```

-- snippet 16
```lean
-- Mathlib.Tactic.NormNum.Basic.isInt_negOfNat (L101-L106)
theorem isInt_negOfNat (m n : ℕ) (h : IsNat m n) : IsInt (Int.negOfNat m) (.negOfNat n) :=
⟨congr_arg Int.negOfNat h.1⟩

/-- `norm_num` extension for `Int.negOfNat`.

It's useful for calling `derive` with the numerator of an `.isNegNNRat` branch. -/
```

-- snippet 17
```lean
-- Mathlib.Tactic.NormNum.Basic.isRat_mul (L464-L483)
theorem isRat_mul {α} [Ring α] {f : α → α → α} {a b : α} {na nb nc : ℤ} {da db dc k : ℕ} :
    f = HMul.hMul → IsRat a na da → IsRat b nb db →
    Int.mul na nb = Int.mul k nc →
    Nat.mul da db = Nat.mul k dc →
    IsRat (f a b) nc dc := by
rintro rfl ⟨_, rfl⟩ ⟨_, rfl⟩ (h₁ : na * nb = k * nc) (h₂ : da * db = k * dc)
  have : Invertible (↑(da * db) : α) := by simpa using invertibleMul (da:α) db
  have := invertibleOfMul' (α := α) h₂
  refine ⟨this, ?_⟩
  have H := (Nat.cast_commute (α := α) da db).invOf_left.invOf_right.right_comm
  have h₁ := congr_arg (Int.cast (R := α)) h₁
  simp only [Int.cast_mul, Int.cast_natCast] at h₁
  simp only [← mul_assoc, (Nat.cast_commute (α := α) da nb).invOf_left.right_comm, h₁]
  have h₂ := congr_arg (↑nc * ↑· * (⅟↑da * ⅟↑db * ⅟↑dc : α)) h₂
  simp only [Nat.cast_mul, ← mul_assoc] at h₂; rw [H] at h₂
  simp only [mul_invOf_cancel_right'] at h₂; rw [h₂, Nat.cast_commute]
  simp only [mul_invOf_cancel_right,
    (Nat.cast_commute (α := α) da dc).invOf_left.invOf_right.right_comm,
    (Nat.cast_commute (α := α) db dc).invOf_left.invOf_right.right_comm]
```

-- snippet 18
```lean
-- Mathlib.Tactic.NormNum.Abs.isNNRat_abs_nonneg (L36-L44)
theorem isNNRat_abs_nonneg {α : Type*} [DivisionRing α] [LinearOrder α]
    [IsStrictOrderedRing α] {a : α} {num den : ℕ} (ra : IsNNRat a num den) :
    IsNNRat |a| num den := by
obtain ⟨ha1, rfl⟩ := ra
  refine ⟨ha1, abs_of_nonneg ?_⟩
  apply mul_nonneg
  · exact Nat.cast_nonneg' num
  · simp only [invOf_eq_inv, inv_nonneg, Nat.cast_nonneg]
```

-- snippet 19
```lean
-- Mathlib.Tactic.NormNum.Basic.isNat_zero (L56-L59)
theorem isNat_zero (α) [AddMonoidWithOne α] : IsNat (Zero.zero : α) (nat_lit 0) :=
⟨Nat.cast_zero.symm⟩

/-- The `norm_num` extension which identifies the expression `Zero.zero`, returning `0`. -/
```

-- snippet 20
```lean
-- Mathlib.Tactic.NormNum.Basic.inferDivisionSemiring (L563-L566)
def inferDivisionSemiring {u : Level} (α : Q(Type u)) : MetaM Q(DivisionSemiring $α) :=
return ← synthInstanceQ q(DivisionSemiring $α) <|> throwError "not a division semiring"

/-- Helper function to synthesize a typed `DivisionRing α` expression. -/
```

-- snippet 21
```lean
-- Mathlib.Tactic.NormNum.Basic.evalNegOfNat (L108-L114)
def evalNegOfNat : NormNumExt where eval {u αZ} e := do
match u, αZ, e with
  | 0, ~q(ℤ), ~q(Int.negOfNat $a) =>
    let ⟨n, pn⟩ ← deriveNat (u := 0) a q(inferInstance)
    return .isNegNat q(inferInstance) n q(isInt_negOfNat $a $n $pn)
  | _ => failure
```

-- snippet 22
```lean
-- Mathlib.Tactic.NormNum.Basic.isNat_intCast (L147-L149)
theorem isNat_intCast {R} [Ring R] (n : ℤ) (m : ℕ) :
    IsNat n m → IsNat (n : R) m := by rintro ⟨⟨⟩⟩; exact ⟨by simp⟩
```

-- snippet 23
```lean
-- Mathlib.Tactic.NormNum.Basic.IsInt (L48-L55)
theorem IsInt.raw_refl (n : ℤ) : IsInt n n := ⟨rfl⟩
meta section

open Lean Meta Qq

/-! ### Constructors and constants -/
```

-- snippet 24
```lean
-- Mathlib.Tactic.NormNum.Abs.isNat_abs_neg (L30-L35)
theorem isNat_abs_neg {α : Type*} [Ring α] [Lattice α] [IsOrderedRing α]
    {a : α} {na : ℕ} (pa : IsInt a (.negOfNat na)) : IsNat |a| na := by
rw [pa.out]
  constructor
  simp
```

-- snippet 25
```lean
-- Mathlib.Tactic.NormNum.Basic.isNat_ofNat (L73-L76)
theorem isNat_ofNat (α : Type u) [AddMonoidWithOne α] {a : α} {n : ℕ}
    (h : n = a) : IsNat a n := ⟨h.symm⟩
/-- The `norm_num` extension which identifies an expression `OfNat.ofNat n`, returning `n`. -/
```

-- snippet 26
```lean
-- Mathlib.Tactic.NormNum.Basic.eq_of_true (L630-L630)
theorem eq_of_true {a b : Prop} (ha : a) (hb : b) : a = b := propext (iff_of_true ha hb)
```

-- snippet 27
```lean
-- Mathlib.Tactic.NormNum.Basic.isRat_add (L218-L238)
theorem isRat_add {α} [Ring α] {f : α → α → α} {a b : α} {na nb nc : ℤ} {da db dc k : ℕ} :
    f = HAdd.hAdd → IsRat a na da → IsRat b nb db →
    Int.add (Int.mul na db) (Int.mul nb da) = Int.mul k nc →
    Nat.mul da db = Nat.mul k dc →
    IsRat (f a b) nc dc := by
rintro rfl ⟨_, rfl⟩ ⟨_, rfl⟩ (h₁ : na * db + nb * da = k * nc) (h₂ : da * db = k * dc)
  have : Invertible (↑(da * db) : α) := by simpa using invertibleMul (da:α) db
  have := invertibleOfMul' (α := α) h₂
  use this
  have H := (Nat.cast_commute (α := α) da db).invOf_left.invOf_right.right_comm
  have h₁ := congr_arg (↑· * (⅟↑da * ⅟↑db : α)) h₁
  simp only [Int.cast_add, Int.cast_mul, Int.cast_natCast, ← mul_assoc,
    add_mul, mul_invOf_cancel_right] at h₁
  have h₂ := congr_arg (↑nc * ↑· * (⅟↑da * ⅟↑db * ⅟↑dc : α)) h₂
  simp only [H, mul_invOf_cancel_right', Nat.cast_mul, ← mul_assoc] at h₁ h₂
  rw [h₁, h₂, Nat.cast_commute]
  simp only [mul_invOf_cancel_right,
    (Nat.cast_commute (α := α) da dc).invOf_left.invOf_right.right_comm,
    (Nat.cast_commute (α := α) db dc).invOf_left.invOf_right.right_comm]

/-- Consider an `Option` as an object in the `MetaM` monad, by throwing an error on `none`. -/
```

-- snippet 28
```lean
-- Mathlib.Tactic.NormNum.Basic.isNat_one (L65-L67)
theorem isNat_one (α) [AddMonoidWithOne α] : IsNat (One.one : α) (nat_lit 1) := ⟨Nat.cast_one.symm⟩
/-- The `norm_num` extension which identifies the expression `One.one`, returning `1`. -/
```

-- snippet 29
```lean
-- Mathlib.Tactic.NormNum.Basic.isNNRat_mul (L444-L463)
theorem isNNRat_mul {α} [Semiring α] {f : α → α → α} {a b : α} {na nb nc : ℕ} {da db dc k : ℕ} :
    f = HMul.hMul → IsNNRat a na da → IsNNRat b nb db →
    Nat.mul na nb = Nat.mul k nc →
    Nat.mul da db = Nat.mul k dc →
    IsNNRat (f a b) nc dc := by
rintro rfl ⟨_, rfl⟩ ⟨_, rfl⟩ (h₁ : na * nb = k * nc) (h₂ : da * db = k * dc)
  have : Invertible (↑(da * db) : α) := by simpa using invertibleMul (da:α) db
  have := invertibleOfMul' (α := α) h₂
  refine ⟨this, ?_⟩
  have H := (Nat.cast_commute (α := α) da db).invOf_left.invOf_right.right_comm
  have h₁ := congr_arg (Nat.cast (R := α)) h₁
  simp only [Nat.cast_mul] at h₁
  simp only [← mul_assoc, (Nat.cast_commute (α := α) da nb).invOf_left.right_comm, h₁]
  have h₂ := congr_arg (↑nc * ↑· * (⅟↑da * ⅟↑db * ⅟↑dc : α)) h₂
  simp only [Nat.cast_mul, ← mul_assoc] at h₂; rw [H] at h₂
  simp only [mul_invOf_cancel_right'] at h₂; rw [h₂, Nat.cast_commute]
  simp only [mul_invOf_cancel_right',
    (Nat.cast_commute (α := α) da dc).invOf_left.invOf_right.right_comm,
    (Nat.cast_commute (α := α) db dc).invOf_left.invOf_right.right_comm]
```

-- snippet 30
```lean
-- Mathlib.Tactic.NormNum.Basic.isNNRat_add (L196-L217)
theorem isNNRat_add {α} [Semiring α] {f : α → α → α} {a b : α} {na nb nc : ℕ} {da db dc k : ℕ} :
    f = HAdd.hAdd → IsNNRat a na da → IsNNRat b nb db →
    Nat.add (Nat.mul na db) (Nat.mul nb da) = Nat.mul k nc →
    Nat.mul da db = Nat.mul k dc →
    IsNNRat (f a b) nc dc := by
rintro rfl ⟨_, rfl⟩ ⟨_, rfl⟩ (h₁ : na * db + nb * da = k * nc) (h₂ : da * db = k * dc)
  have : Invertible (↑(da * db) : α) := by simpa using invertibleMul (da:α) db
  have := invertibleOfMul' (α := α) h₂
  use this
  have H := (Nat.cast_commute (α := α) da db).invOf_left.invOf_right.right_comm
  have h₁ := congr_arg (↑· * (⅟↑da * ⅟↑db : α)) h₁
  simp only [Nat.cast_add, Nat.cast_mul, ← mul_assoc,
    add_mul, mul_invOf_cancel_right] at h₁
  have h₂ := congr_arg (↑nc * ↑· * (⅟↑da * ⅟↑db * ⅟↑dc : α)) h₂
  simp only [H, mul_invOf_cancel_right', Nat.cast_mul, ← mul_assoc] at h₁ h₂
  rw [h₁, h₂, Nat.cast_commute]
  simp only [mul_invOf_cancel_right,
    (Nat.cast_commute (α := α) da dc).invOf_left.invOf_right.right_comm,
    (Nat.cast_commute (α := α) db dc).invOf_left.invOf_right.right_comm]

-- TODO: clean up and move it somewhere in mathlib? It's a bit much for this file
-- see note [norm_num lemma function equality]
```

-- snippet 31
```lean
-- Mathlib.Tactic.NormNum.Basic.ne_of_false_of_true (L631-L631)
theorem ne_of_false_of_true {a b : Prop} (ha : ¬a) (hb : b) : a ≠ b := mt (· ▸ hb) ha
```

-- snippet 32
```lean
-- Mathlib.Tactic.NormNum.Basic.isRat_sub (L377-L385)
theorem isRat_sub {α} [Ring α] {f : α → α → α} {a b : α} {na nb nc : ℤ} {da db dc k : ℕ}
    (hf : f = HSub.hSub) (ra : IsRat a na da) (rb : IsRat b nb db)
    (h₁ : Int.sub (Int.mul na db) (Int.mul nb da) = Int.mul k nc)
    (h₂ : Nat.mul da db = Nat.mul k dc) :
    IsRat (f a b) nc dc := by
rw [hf, sub_eq_add_neg]
  refine isRat_add rfl ra (isRat_neg (n' := -nb) rfl rb rfl) (k := k) (nc := nc) ?_ h₂
  rw [show Int.mul (-nb) _ = _ from neg_mul ..]; exact h₁
```

-- snippet 33
```lean
-- Mathlib.Tactic.NormNum.Abs.isNNRat_abs_neg (L45-L55)
theorem isNNRat_abs_neg {α : Type*} [DivisionRing α] [LinearOrder α] [IsStrictOrderedRing α]
    {a : α} {num den : ℕ} (ra : IsRat a (.negOfNat num) den) : IsNNRat |a| num den := by
obtain ⟨ha1, rfl⟩ := ra
  simp only [Int.cast_negOfNat, neg_mul, abs_neg]
  refine ⟨ha1, abs_of_nonneg ?_⟩
  apply mul_nonneg
  · exact Nat.cast_nonneg' num
  · simp only [invOf_eq_inv, inv_nonneg, Nat.cast_nonneg]

/-- The `norm_num` extension which identifies expressions of the form `|a|`,
such that `norm_num` successfully recognises `a`. -/
```

-- snippet 34
```lean
-- Mathlib.Tactic.NormNum.Basic.isNat_natCast (L135-L138)
theorem isNat_natCast {R} [AddMonoidWithOne R] (n m : ℕ) :
    IsNat n m → IsNat (n : R) m := by rintro ⟨⟨⟩⟩; exact ⟨rfl⟩
/-- The `norm_num` extension which identifies an expression `Nat.cast n`, returning `n`. -/
```

-- snippet 35
```lean
-- Mathlib.Tactic.NormNum.Basic.inferDivisionRing (L567-L569)
def inferDivisionRing {u : Level} (α : Q(Type u)) : MetaM Q(DivisionRing $α) :=
return ← synthInstanceQ q(DivisionRing $α) <|> throwError "not a division ring"
```

-- snippet 36
```lean
-- Mathlib.Tactic.NormNum.Abs.isNat_abs_nonneg (L24-L29)
theorem isNat_abs_nonneg {α : Type*} [Ring α] [Lattice α] [IsOrderedRing α]
    {a : α} {na : ℕ} (pa : IsNat a na) : IsNat |a| na := by
rw [pa.out, Nat.abs_cast]
  constructor
  rfl
```

-- snippet 37
```lean
-- Mathlib.Tactic.NormNum.Basic.Result (L247-L304)
def Result.add {u : Level} {α : Q(Type u)} {a b : Q($α)} (ra : Result q($a)) (rb : Result q($b))
    (inst : Q(Add $α) := by exact q(delta% inferInstance)) :
MetaM (Result q($a + $b)) := do
  let rec intArm (rα : Q(Ring $α)) := do
    assumeInstancesCommute
    let ⟨za, na, pa⟩ ← ra.toInt _; let ⟨zb, nb, pb⟩ ← rb.toInt _
    let zc := za + zb
    have c := mkRawIntLit zc
    haveI' : Int.add $na $nb =Q $c := ⟨⟩
    return .isInt rα c zc q(isInt_add (.refl _) $pa $pb (.refl $c))
  let rec nnratArm (dsα : Q(DivisionSemiring $α)) : MetaM (Result _) := do
    assumeInstancesCommute
    let ⟨qa, na, da, pa⟩ ← ra.toNNRat' dsα; let ⟨qb, nb, db, pb⟩ ← rb.toNNRat' dsα
    let qc := qa + qb
    let dd := qa.den * qb.den
    let k := dd / qc.den
    have t1 : Q(ℕ) := mkRawNatLit (k * qc.num.toNat)
    have t2 : Q(ℕ) := mkRawNatLit dd
    have nc : Q(ℕ) := mkRawNatLit qc.num.toNat
    have dc : Q(ℕ) := mkRawNatLit qc.den
    have k : Q(ℕ) := mkRawNatLit k
    let r1 : Q(Nat.add (Nat.mul $na $db) (Nat.mul $nb $da) = Nat.mul $k $nc) :=
      (q(Eq.refl $t1) : Expr)
    let r2 : Q(Nat.mul $da $db = Nat.mul $k $dc) := (q(Eq.refl $t2) : Expr)
    return .isNNRat' dsα qc nc dc q(isNNRat_add (.refl _) $pa $pb $r1 $r2)
  let rec ratArm (dα : Q(DivisionRing $α)) : MetaM (Result _) := do
    assumeInstancesCommute
    let ⟨qa, na, da, pa⟩ ← ra.toRat' dα; let ⟨qb, nb, db, pb⟩ ← rb.toRat' dα
    let qc := qa + qb
    let dd := qa.den * qb.den
    let k := dd / qc.den
    have t1 : Q(ℤ) := mkRawIntLit (k * qc.num)
    have t2 : Q(ℕ) := mkRawNatLit dd
    have nc : Q(ℤ) := mkRawIntLit qc.num
    have dc : Q(ℕ) := mkRawNatLit qc.den
    have k : Q(ℕ) := mkRawNatLit k
    let r1 : Q(Int.add (Int.mul $na $db) (Int.mul $nb $da) = Int.mul $k $nc) :=
      (q(Eq.refl $t1) : Expr)
    let r2 : Q(Nat.mul $da $db = Nat.mul $k $dc) := (q(Eq.refl $t2) : Expr)
    return .isRat dα qc nc dc q(isRat_add (.refl _) $pa $pb $r1 $r2)
  match ra, rb with
  | .isBool .., _ | _, .isBool .. => failure
  | .isNegNNRat dα .., _ | _, .isNegNNRat dα .. => ratArm dα
  -- mixing positive rationals and negative naturals means we need to use the full rat handler
  | .isNNRat _dsα .., .isNegNat _rα .. | .isNegNat _rα .., .isNNRat _dsα .. =>
    -- could alternatively try to combine `rα` and `dsα` here, but we'd have to do a defeq check
    -- so would still need to be in `MetaM`.
    let dα ← synthInstanceQ q(DivisionRing $α)
    assumeInstancesCommute
    ratArm q($dα)
  | .isNNRat dsα .., _ | _, .isNNRat dsα .. => nnratArm dsα
  | .isNegNat rα .., _ | _, .isNegNat rα .. => intArm rα
  | .isNat _ na pa, .isNat sα nb pb =>
    assumeInstancesCommute
    have c : Q(ℕ) := mkRawNatLit (na.natLit! + nb.natLit!)
    haveI' : Nat.add $na $nb =Q $c := ⟨⟩
    return .isNat sα c q(isNat_add (.refl _) $pa $pb (.refl $c))
```

-- snippet 38
```lean
-- Mathlib.Tactic.NormNum.Basic.ble_eq_false (L616-L618)
theorem ble_eq_false {x y : ℕ} : x.ble y = false ↔ y < x := by
rw [← Nat.not_le, ← Bool.not_eq_true, Nat.ble_eq]
```

-- snippet 39
```lean
-- Mathlib.Tactic.NormNum.Basic.invertibleOfMul' (L45-L47)
def invertibleOfMul' {α} [Semiring α] {a k b : ℕ} [Invertible (a : α)]
    (h : a = k * b) : Invertible (b : α) := invertibleOfMul k (b:α) ↑a (by simp [h])
```

-- snippet 40
```lean
-- Mathlib.Tactic.NormNum.Basic.isintCast (L150-L153)
theorem isintCast {R} [Ring R] (n m : ℤ) :
    IsInt n m → IsInt (n : R) m := by rintro ⟨⟨⟩⟩; exact ⟨rfl⟩
/-- The `norm_num` extension which identifies an expression `Int.cast n`, returning `n`. -/
```
[/INST]


Instruction: Edit `isEquivalent_deriv_rpow_p_mul_one_add_smoothingFn` so it still compiles and the proof is simplified where possible. Return the full updated `isEquivalent_deriv_rpow_p_mul_one_add_smoothingFn` block.

[System] You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Computability.AkraBazzi.AkraBazzi).

[User]
You are editing a file in `Mathlib/Computability/AkraBazzi/AkraBazzi.lean` (mathlib commit 5e932f97dd25535344f80f9dd8da3aab83df0fe6).

## Current excerpt (around `Mathlib.Computability.AkraBazzi.AkraBazzi.isEquivalent_deriv_rpow_p_mul_one_add_smoothingFn`, L139-L161)
## Imports
```lean
import Mathlib.Analysis.SpecialFunctions.Pow.Deriv
```

Open namespaces: Finset, Real, Filter, Asymptotics, scoped, Topology

## Surrounding context in Mathlib/Computability/AkraBazzi/AkraBazzi.lean
```lean
-- Mathlib.Computability.AkraBazzi.AkraBazzi.of (L21-L60)
instance of the problem of size `n`, into `k` smaller instances, where the `i`-th instance is of
size roughly `b_i n`, and calling itself recursively on those smaller instances. `T(n)` then
represents the running time of the algorithm, and `g(n)` represents the running time required to
divide the instance and process the answers produced by the recursive calls. Since virtually all
such algorithms produce instances that are only approximately of size `b_i n` (they must round up
or down, at the very least), we allow the instance sizes to be given by a function `r_i(n)` that
approximates `b_i n`.

The Akra-Bazzi theorem gives the asymptotic order of such a recurrence: it states that
`T(n) ∈ Θ(n^p (1 + ∑_{u=0}^{n-1} g(n) / u^{p+1}))`,

-- Mathlib.Computability.AkraBazzi.AkraBazzi.eventually_deriv_rpow_p_mul_one_sub_smoothingFn (L82-L98)
lemma eventually_deriv_rpow_p_mul_one_sub_smoothingFn (p : ℝ) :
    deriv (fun z => z ^ p * (1 - ε z))
      =ᶠ[atTop] fun z => p * z ^ (p - 1) * (1 - ε z) + z ^ (p - 1) / (log z ^ 2)

-- Mathlib.Computability.AkraBazzi.AkraBazzi.eventually_deriv_rpow_p_mul_one_add_smoothingFn (L99-L115)
lemma eventually_deriv_rpow_p_mul_one_add_smoothingFn (p : ℝ) :
    deriv (fun z => z ^ p * (1 + ε z))
      =ᶠ[atTop] fun z => p * z ^ (p - 1) * (1 + ε z) - z ^ (p - 1) / (log z ^ 2)
```

Relevant lemmas available in scope: `Tendsto.comp`

```lean
lemma isEquivalent_deriv_rpow_p_mul_one_add_smoothingFn {p : ℝ} (hp : p ≠ 0) :
    deriv (fun z => z ^ p * (1 + ε z)) ~[atTop] fun z => p * z ^ (p - 1) := calc deriv (fun z => z ^ p * (1 + ε z))
    _ =ᶠ[atTop] fun z => p * z ^ (p - 1) * (1 + ε z) - z ^ (p - 1) / (log z ^ 2) :=
      eventually_deriv_rpow_p_mul_one_add_smoothingFn p
    _ ~[atTop] fun z => p * z ^ (p - 1) := by
      refine IsEquivalent.add_isLittleO ?one ?two
      case one => calc
        (fun z => p * z ^ (p - 1) * (1 + ε z)) ~[atTop] fun z => p * z ^ (p - 1) * 1 :=
              IsEquivalent.mul IsEquivalent.refl isEquivalent_one_add_smoothingFn_one
        _ = fun z => p * z ^ (p - 1) := by ext; ring
      case two => calc
        (fun z => -(z ^ (p - 1) / (log z ^ 2))) =o[atTop] fun z => z ^ (p - 1) / 1 := by
            simp_rw [isLittleO_neg_left, div_eq_mul_inv]
            refine IsBigO.mul_isLittleO (isBigO_refl _ _)
              (IsLittleO.inv_rev ?_ (by simp))
            rw [isLittleO_const_left]
            refine Or.inr <| Tendsto.comp tendsto_norm_atTop_atTop ?_
            exact Tendsto.comp (g := fun z => z ^ 2)
              (tendsto_pow_atTop (by norm_num)) tendsto_log_atTop
        _ = fun z => z ^ (p - 1) := by ext; simp
        _ =Θ[atTop] fun z => p * z ^ (p - 1) := IsTheta.const_mul_right hp <| isTheta_refl _ _
```

## Edit instruction
Edit `isEquivalent_deriv_rpow_p_mul_one_add_smoothingFn` so it still compiles and the proof is simplified where possible. Return the full updated `isEquivalent_deriv_rpow_p_mul_one_add_smoothingFn` block.

You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Computability.AkraBazzi.AkraBazzi).

You are editing a file in `Mathlib/Computability/AkraBazzi/AkraBazzi.lean` (mathlib commit 5e932f97dd25535344f80f9dd8da3aab83df0fe6).

## Current excerpt (around `Mathlib.Computability.AkraBazzi.AkraBazzi.isEquivalent_deriv_rpow_p_mul_one_add_smoothingFn`, L139-L161)
## Imports
```lean
import Mathlib.Analysis.SpecialFunctions.Pow.Deriv
```

Open namespaces: Finset, Real, Filter, Asymptotics, scoped, Topology

## Surrounding context in Mathlib/Computability/AkraBazzi/AkraBazzi.lean
```lean
-- Mathlib.Computability.AkraBazzi.AkraBazzi.of (L21-L60)
instance of the problem of size `n`, into `k` smaller instances, where the `i`-th instance is of
size roughly `b_i n`, and calling itself recursively on those smaller instances. `T(n)` then
represents the running time of the algorithm, and `g(n)` represents the running time required to
divide the instance and process the answers produced by the recursive calls. Since virtually all
such algorithms produce instances that are only approximately of size `b_i n` (they must round up
or down, at the very least), we allow the instance sizes to be given by a function `r_i(n)` that
approximates `b_i n`.

The Akra-Bazzi theorem gives the asymptotic order of such a recurrence: it states that
`T(n) ∈ Θ(n^p (1 + ∑_{u=0}^{n-1} g(n) / u^{p+1}))`,

-- Mathlib.Computability.AkraBazzi.AkraBazzi.eventually_deriv_rpow_p_mul_one_sub_smoothingFn (L82-L98)
lemma eventually_deriv_rpow_p_mul_one_sub_smoothingFn (p : ℝ) :
    deriv (fun z => z ^ p * (1 - ε z))
      =ᶠ[atTop] fun z => p * z ^ (p - 1) * (1 - ε z) + z ^ (p - 1) / (log z ^ 2)

-- Mathlib.Computability.AkraBazzi.AkraBazzi.eventually_deriv_rpow_p_mul_one_add_smoothingFn (L99-L115)
lemma eventually_deriv_rpow_p_mul_one_add_smoothingFn (p : ℝ) :
    deriv (fun z => z ^ p * (1 + ε z))
      =ᶠ[atTop] fun z => p * z ^ (p - 1) * (1 + ε z) - z ^ (p - 1) / (log z ^ 2)
```

Relevant lemmas available in scope: `Tendsto.comp`

```lean
lemma isEquivalent_deriv_rpow_p_mul_one_add_smoothingFn {p : ℝ} (hp : p ≠ 0) :
    deriv (fun z => z ^ p * (1 + ε z)) ~[atTop] fun z => p * z ^ (p - 1) := calc deriv (fun z => z ^ p * (1 + ε z))
    _ =ᶠ[atTop] fun z => p * z ^ (p - 1) * (1 + ε z) - z ^ (p - 1) / (log z ^ 2) :=
      eventually_deriv_rpow_p_mul_one_add_smoothingFn p
    _ ~[atTop] fun z => p * z ^ (p - 1) := by
      refine IsEquivalent.add_isLittleO ?one ?two
      case one => calc
        (fun z => p * z ^ (p - 1) * (1 + ε z)) ~[atTop] fun z => p * z ^ (p - 1) * 1 :=
              IsEquivalent.mul IsEquivalent.refl isEquivalent_one_add_smoothingFn_one
        _ = fun z => p * z ^ (p - 1) := by ext; ring
      case two => calc
        (fun z => -(z ^ (p - 1) / (log z ^ 2))) =o[atTop] fun z => z ^ (p - 1) / 1 := by
            simp_rw [isLittleO_neg_left, div_eq_mul_inv]
            refine IsBigO.mul_isLittleO (isBigO_refl _ _)
              (IsLittleO.inv_rev ?_ (by simp))
            rw [isLittleO_const_left]
            refine Or.inr <| Tendsto.comp tendsto_norm_atTop_atTop ?_
            exact Tendsto.comp (g := fun z => z ^ 2)
              (tendsto_pow_atTop (by norm_num)) tendsto_log_atTop
        _ = fun z => z ^ (p - 1) := by ext; simp
        _ =Θ[atTop] fun z => p * z ^ (p - 1) := IsTheta.const_mul_right hp <| isTheta_refl _ _
```

## Edit instruction
Edit `isEquivalent_deriv_rpow_p_mul_one_add_smoothingFn` so it still compiles and the proof is simplified where possible. Return the full updated `isEquivalent_deriv_rpow_p_mul_one_add_smoothingFn` block.


[System] You are Leanstral, a Lean 4 proof assistant. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Tactic.CategoryTheory.Coherence.Datatypes).

[User]
Complete the following proof.

Open namespaces: Lean, Meta, MonadMor₁

## Surrounding context in Mathlib/Tactic/CategoryTheory/Coherence/Datatypes.lean
```lean
-- Mathlib.Tactic.CategoryTheory.Coherence.Datatypes.Obj (L55-L88)
def Obj.e (a : Obj) : Expr

-- Mathlib.Tactic.CategoryTheory.Coherence.Datatypes.Mor₁ (L89-L94)
def Mor₁.e : Mor₁ → Expr
  | .id e _ => e
  | .comp e _ _ => e
  | .of a => a.e

/-- The domain of a 1-morphism. -/

-- Mathlib.Tactic.CategoryTheory.Coherence.Datatypes.Mor₁ (L95-L100)
def Mor₁.src : Mor₁ → Obj
  | .id _ a => a
  | .comp _ f _ => f.src
  | .of f => f.src

/-- The codomain of a 1-morphism. -/
```

```lean
def Mor₂Iso.tgtM {m : Type → Type} [Monad m] [MonadMor₁ m] : Mor₂Iso → m Mor₁
  | .structuralAtom α => α.tgtM
  | .comp _ _ _ h .. => return h
  | .whiskerLeft _ f _ h _ => do comp₁M f h
  | .whiskerRight _ _ g _ h => do comp₁M g h
  | .horizontalComp _ _ g₁ _ g₂ _ _ => do comp₁M g₁ g₂
  | .inv _ f _ _ => return f
  | .coherenceComp _ _ _ _ i .. => return i
  | .of η => return η.tgt

/-- A monad equipped with the ability to construct `Mor₂Iso` terms. -/
class MonadMor₂Iso (m : Type → Type) where
  /-- The expression for the associator `α_ f g h`. -/
  associatorM (f g h : Mor₁) : m StructuralAtom
  /-- The expression for the left unitor `λ_ f`. -/
  leftUnitorM (f : Mor₁) : m StructuralAtom
  /-- The expression for the right unitor `ρ_ f`. -/
  rightUnitorM (f : Mor₁) : m StructuralAtom
  /-- The expression for the identity `Iso.refl f`. -/
  id₂M (f : Mor₁) : m StructuralAtom
  /-- The expression for the coherence isomorphism `⊗𝟙 : f ⟶ g`. -/
  coherenceHomM (f g : Mor₁) (inst : Expr) : m CoherenceHom
  /-- The expression for the composition `η ≪≫ θ`. -/
  comp₂M (η θ : Mor₂Iso) : m Mor₂Iso
  /-- The expression for the left whiskering `whiskerLeftIso f η`. -/
  whiskerLeftM (f : Mor₁) (η : Mor₂Iso) : m Mor₂Iso
  /-- The expression for the right whiskering `whiskerRightIso η h`. -/
  whiskerRightM (η : Mor₂Iso) (h : Mor₁) : m Mor₂Iso
  /-- The expression for the horizontal composition `η ◫ θ`. -/
  horizontalCompM (η θ : Mor₂Iso) : m Mor₂Iso
  /-- The expression for the inverse `Iso.symm η`. -/
  symmM (η : Mor₂Iso) : m Mor₂Iso
  /-- The expression for the coherence composition `η ≪⊗≫ θ
```

Provide a complete Lean proof for the statement above. Do not include the statement in your answer.

You are Leanstral, a Lean 4 proof assistant. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Tactic.CategoryTheory.Coherence.Datatypes).

Complete the following proof.

Open namespaces: Lean, Meta, MonadMor₁

## Surrounding context in Mathlib/Tactic/CategoryTheory/Coherence/Datatypes.lean
```lean
-- Mathlib.Tactic.CategoryTheory.Coherence.Datatypes.Obj (L55-L88)
def Obj.e (a : Obj) : Expr

-- Mathlib.Tactic.CategoryTheory.Coherence.Datatypes.Mor₁ (L89-L94)
def Mor₁.e : Mor₁ → Expr
  | .id e _ => e
  | .comp e _ _ => e
  | .of a => a.e

/-- The domain of a 1-morphism. -/

-- Mathlib.Tactic.CategoryTheory.Coherence.Datatypes.Mor₁ (L95-L100)
def Mor₁.src : Mor₁ → Obj
  | .id _ a => a
  | .comp _ f _ => f.src
  | .of f => f.src

/-- The codomain of a 1-morphism. -/
```

```lean
def Mor₂Iso.tgtM {m : Type → Type} [Monad m] [MonadMor₁ m] : Mor₂Iso → m Mor₁
  | .structuralAtom α => α.tgtM
  | .comp _ _ _ h .. => return h
  | .whiskerLeft _ f _ h _ => do comp₁M f h
  | .whiskerRight _ _ g _ h => do comp₁M g h
  | .horizontalComp _ _ g₁ _ g₂ _ _ => do comp₁M g₁ g₂
  | .inv _ f _ _ => return f
  | .coherenceComp _ _ _ _ i .. => return i
  | .of η => return η.tgt

/-- A monad equipped with the ability to construct `Mor₂Iso` terms. -/
class MonadMor₂Iso (m : Type → Type) where
  /-- The expression for the associator `α_ f g h`. -/
  associatorM (f g h : Mor₁) : m StructuralAtom
  /-- The expression for the left unitor `λ_ f`. -/
  leftUnitorM (f : Mor₁) : m StructuralAtom
  /-- The expression for the right unitor `ρ_ f`. -/
  rightUnitorM (f : Mor₁) : m StructuralAtom
  /-- The expression for the identity `Iso.refl f`. -/
  id₂M (f : Mor₁) : m StructuralAtom
  /-- The expression for the coherence isomorphism `⊗𝟙 : f ⟶ g`. -/
  coherenceHomM (f g : Mor₁) (inst : Expr) : m CoherenceHom
  /-- The expression for the composition `η ≪≫ θ`. -/
  comp₂M (η θ : Mor₂Iso) : m Mor₂Iso
  /-- The expression for the left whiskering `whiskerLeftIso f η`. -/
  whiskerLeftM (f : Mor₁) (η : Mor₂Iso) : m Mor₂Iso
  /-- The expression for the right whiskering `whiskerRightIso η h`. -/
  whiskerRightM (η : Mor₂Iso) (h : Mor₁) : m Mor₂Iso
  /-- The expression for the horizontal composition `η ◫ θ`. -/
  horizontalCompM (η θ : Mor₂Iso) : m Mor₂Iso
  /-- The expression for the inverse `Iso.symm η`. -/
  symmM (η : Mor₂Iso) : m Mor₂Iso
  /-- The expression for the coherence composition `η ≪⊗≫ θ
```

Provide a complete Lean proof for the statement above. Do not include the statement in your answer.


[System] You are Leanstral, a Lean 4 proof assistant. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Dynamics.Ergodic.Ergodic).

[User]
Complete the following proof.

Open namespaces: Set, Function, Filter, MeasureTheory, MeasureTheory.Measure, ENNReal

## Surrounding context in Mathlib/Dynamics/Ergodic/Ergodic.lean
```lean
-- Mathlib.Dynamics.Ergodic.Ergodic.ae_empty_or_univ (L62-L65)
theorem ae_empty_or_univ (hf : PreErgodic f μ) (hs : MeasurableSet s) (hfs : f ⁻¹' s = s) :
    s =ᵐ[μ] (∅ : Set α) ∨ s =ᵐ[μ] univ

-- Mathlib.Dynamics.Ergodic.Ergodic.measure_self_or_compl_eq_zero (L66-L69)
theorem measure_self_or_compl_eq_zero (hf : PreErgodic f μ) (hs : MeasurableSet s)
    (hs' : f ⁻¹' s = s) : μ s = 0 ∨ μ sᶜ = 0

-- Mathlib.Dynamics.Ergodic.Ergodic.ae_mem_or_ae_notMem (L70-L74)
theorem ae_mem_or_ae_notMem (hf : PreErgodic f μ) (hsm : MeasurableSet s) (hs : f ⁻¹' s = s) :
    (∀ᵐ x ∂μ, x ∈ s) ∨ ∀ᵐ x ∂μ, x ∉ s
```

```lean
theorem preErgodic_conjugate_iff {e : α ≃ᵐ β} (h : MeasurePreserving e μ μ') :
    PreErgodic (e ∘ f ∘ e.symm) μ' ↔ PreErgodic f μ
```

Provide a complete Lean proof for the statement above. Do not include the statement in your answer.

You are Leanstral, a Lean 4 proof assistant. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Dynamics.Ergodic.Ergodic).

Complete the following proof.

Open namespaces: Set, Function, Filter, MeasureTheory, MeasureTheory.Measure, ENNReal

## Surrounding context in Mathlib/Dynamics/Ergodic/Ergodic.lean
```lean
-- Mathlib.Dynamics.Ergodic.Ergodic.ae_empty_or_univ (L62-L65)
theorem ae_empty_or_univ (hf : PreErgodic f μ) (hs : MeasurableSet s) (hfs : f ⁻¹' s = s) :
    s =ᵐ[μ] (∅ : Set α) ∨ s =ᵐ[μ] univ

-- Mathlib.Dynamics.Ergodic.Ergodic.measure_self_or_compl_eq_zero (L66-L69)
theorem measure_self_or_compl_eq_zero (hf : PreErgodic f μ) (hs : MeasurableSet s)
    (hs' : f ⁻¹' s = s) : μ s = 0 ∨ μ sᶜ = 0

-- Mathlib.Dynamics.Ergodic.Ergodic.ae_mem_or_ae_notMem (L70-L74)
theorem ae_mem_or_ae_notMem (hf : PreErgodic f μ) (hsm : MeasurableSet s) (hs : f ⁻¹' s = s) :
    (∀ᵐ x ∂μ, x ∈ s) ∨ ∀ᵐ x ∂μ, x ∉ s
```

```lean
theorem preErgodic_conjugate_iff {e : α ≃ᵐ β} (h : MeasurePreserving e μ μ') :
    PreErgodic (e ∘ f ∘ e.symm) μ' ↔ PreErgodic f μ
```

Provide a complete Lean proof for the statement above. Do not include the statement in your answer.


[System] You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Computability.ContextFreeGrammar).

[User]
Prove the following theorem. The retrieved context below may help.

```lean
lemma mem_language_iff (g : ContextFreeGrammar T) (w : List T) :
    w ∈ g.language ↔ g.Derives [Symbol.nonterminal g.initial] (w.map Symbol.terminal)
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Computability.ContextFreeGrammar.Rewrites (L68-L79)
lemma Rewrites.exists_parts (hr : r.Rewrites u v) :
    ∃ p q : List (Symbol T N),
      u = p ++ [Symbol.nonterminal r.input] ++ q ∧ v = p ++ r.output ++ q := by
induction hr with
  | head s =>
    use [], s
    simp
  | cons x _ ih =>
    rcases ih with ⟨p', q', rfl, rfl⟩
    use x :: p', q'
    simp
```

-- snippet 2
```lean
-- Mathlib.Computability.ContextFreeGrammar.Rewrites (L80-L82)
lemma Rewrites.input_output : r.Rewrites [.nonterminal r.input] r.output := by
simpa using head []
```

-- snippet 3
```lean
-- Mathlib.Computability.ContextFreeGrammar.rewrites_of_exists_parts (L83-L91)
lemma rewrites_of_exists_parts (r : ContextFreeRule T N) (p q : List (Symbol T N)) :
    r.Rewrites (p ++ [Symbol.nonterminal r.input] ++ q) (p ++ r.output ++ q) := by
induction p with
  | nil => exact Rewrites.head q
  | cons d l ih => exact Rewrites.cons d ih

/-- Rule `r` rewrites string `u` is to string `v` iff they share both a prefix `p` and postfix `q`
such that the remaining middle part of `u` is the input of `r` and the remaining middle part
of `u` is the output of `r`. -/
```

-- snippet 4
```lean
-- Mathlib.Computability.ContextFreeGrammar.rewrites_iff (L92-L96)
theorem rewrites_iff :
    r.Rewrites u v ↔ ∃ p q : List (Symbol T N),
      u = p ++ [Symbol.nonterminal r.input] ++ q ∧ v = p ++ r.output ++ q :=
⟨Rewrites.exists_parts, by rintro ⟨p, q, rfl, rfl⟩; apply rewrites_of_exists_parts⟩
```

-- snippet 5
```lean
-- Mathlib.Computability.ContextFreeGrammar.Rewrites (L97-L100)
lemma Rewrites.nonterminal_input_mem : r.Rewrites u v → .nonterminal r.input ∈ u := by
simp +contextual [rewrites_iff, List.append_assoc]

/-- Add extra prefix to context-free rewriting. -/
```

-- snippet 6
```lean
-- Mathlib.Computability.ContextFreeGrammar.Rewrites (L101-L108)
lemma Rewrites.append_left (hvw : r.Rewrites u v) (p : List (Symbol T N)) :
    r.Rewrites (p ++ u) (p ++ v) := by
rw [rewrites_iff] at *
  rcases hvw with ⟨x, y, hxy⟩
  use p ++ x, y
  simp_all

/-- Add extra postfix to context-free rewriting. -/
```

-- snippet 7
```lean
-- Mathlib.Computability.ContextFreeGrammar.Rewrites (L109-L122)
lemma Rewrites.append_right (hvw : r.Rewrites u v) (p : List (Symbol T N)) :
    r.Rewrites (u ++ p) (v ++ p) := by
rw [rewrites_iff] at *
  rcases hvw with ⟨x, y, hxy⟩
  use x, y ++ p
  simp_all

end ContextFreeRule

namespace ContextFreeGrammar

/-- Given a context-free grammar `g` and strings `u` and `v`
`g.Produces u v` means that one step of a context-free transformation by a rule from `g` sends
`u` to `v`. -/
```

-- snippet 8
```lean
-- Mathlib.Computability.ContextFreeGrammar.Produces (L123-L127)
def Produces (g : ContextFreeGrammar T) (u v : List (Symbol T g.NT)) : Prop :=
∃ r ∈ g.rules, r.Rewrites u v

/-- Given a context-free grammar `g` and strings `u` and `v`
`g.Derives u v` means that `g` can transform `u` to `v` in some number of rewriting steps. -/
```

-- snippet 9
```lean
-- Mathlib.Computability.ContextFreeGrammar.Derives (L128-L134)
abbrev Derives (g : ContextFreeGrammar T) :
    List (Symbol T g.NT) → List (Symbol T g.NT) → Prop :=
Relation.ReflTransGen g.Produces

/-- Given a context-free grammar `g` and a string `s`
`g.Generates s` means that `g` can transform its initial nonterminal to `s` in some number of
rewriting steps. -/
```

-- snippet 10
```lean
-- Mathlib.Computability.ContextFreeGrammar.Generates (L135-L138)
def Generates (g : ContextFreeGrammar T) (s : List (Symbol T g.NT)) : Prop :=
g.Derives [Symbol.nonterminal g.initial] s

/-- The language (set of words) that can be generated by a given context-free grammar `g`. -/
```

-- snippet 11
```lean
-- Mathlib.Computability.ContextFreeGrammar.language (L139-L144)
def language (g : ContextFreeGrammar T) : Language T :=
{ w : List T | g.Generates (w.map Symbol.terminal) }

/-- A given word `w` belongs to the language generated by a given context-free grammar `g` iff
`g` can derive the word `w` (wrapped as a string) from the initial nonterminal of `g` in some
number of steps. -/
```

-- snippet 12
```lean
-- Mathlib.Computability.ContextFreeGrammar.Derives (L153-L155)
lemma Derives.refl (w : List (Symbol T g.NT)) : g.Derives w w :=
Relation.ReflTransGen.refl
```

-- snippet 13
```lean
-- Mathlib.Computability.ContextFreeGrammar.Produces (L156-L158)
lemma Produces.single {v w : List (Symbol T g.NT)} (hvw : g.Produces v w) : g.Derives v w :=
Relation.ReflTransGen.single hvw
```

-- snippet 14
```lean
-- Mathlib.Computability.ContextFreeGrammar.Derives (L160-L163)
lemma Derives.trans {u v w : List (Symbol T g.NT)} (huv : g.Derives u v) (hvw : g.Derives v w) :
    g.Derives u w :=
Relation.ReflTransGen.trans huv hvw
```

-- snippet 15
```lean
-- Mathlib.Computability.ContextFreeGrammar.Derives (L164-L168)
lemma Derives.trans_produces {u v w : List (Symbol T g.NT)}
    (huv : g.Derives u v) (hvw : g.Produces v w) :
    g.Derives u w :=
huv.trans hvw.single
```

<s>[SYSTEM_PROMPT]You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Computability.ContextFreeGrammar).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]Prove the following theorem. The retrieved context below may help.

```lean
lemma mem_language_iff (g : ContextFreeGrammar T) (w : List T) :
    w ∈ g.language ↔ g.Derives [Symbol.nonterminal g.initial] (w.map Symbol.terminal)
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Computability.ContextFreeGrammar.Rewrites (L68-L79)
lemma Rewrites.exists_parts (hr : r.Rewrites u v) :
    ∃ p q : List (Symbol T N),
      u = p ++ [Symbol.nonterminal r.input] ++ q ∧ v = p ++ r.output ++ q := by
induction hr with
  | head s =>
    use [], s
    simp
  | cons x _ ih =>
    rcases ih with ⟨p', q', rfl, rfl⟩
    use x :: p', q'
    simp
```

-- snippet 2
```lean
-- Mathlib.Computability.ContextFreeGrammar.Rewrites (L80-L82)
lemma Rewrites.input_output : r.Rewrites [.nonterminal r.input] r.output := by
simpa using head []
```

-- snippet 3
```lean
-- Mathlib.Computability.ContextFreeGrammar.rewrites_of_exists_parts (L83-L91)
lemma rewrites_of_exists_parts (r : ContextFreeRule T N) (p q : List (Symbol T N)) :
    r.Rewrites (p ++ [Symbol.nonterminal r.input] ++ q) (p ++ r.output ++ q) := by
induction p with
  | nil => exact Rewrites.head q
  | cons d l ih => exact Rewrites.cons d ih

/-- Rule `r` rewrites string `u` is to string `v` iff they share both a prefix `p` and postfix `q`
such that the remaining middle part of `u` is the input of `r` and the remaining middle part
of `u` is the output of `r`. -/
```

-- snippet 4
```lean
-- Mathlib.Computability.ContextFreeGrammar.rewrites_iff (L92-L96)
theorem rewrites_iff :
    r.Rewrites u v ↔ ∃ p q : List (Symbol T N),
      u = p ++ [Symbol.nonterminal r.input] ++ q ∧ v = p ++ r.output ++ q :=
⟨Rewrites.exists_parts, by rintro ⟨p, q, rfl, rfl⟩; apply rewrites_of_exists_parts⟩
```

-- snippet 5
```lean
-- Mathlib.Computability.ContextFreeGrammar.Rewrites (L97-L100)
lemma Rewrites.nonterminal_input_mem : r.Rewrites u v → .nonterminal r.input ∈ u := by
simp +contextual [rewrites_iff, List.append_assoc]

/-- Add extra prefix to context-free rewriting. -/
```

-- snippet 6
```lean
-- Mathlib.Computability.ContextFreeGrammar.Rewrites (L101-L108)
lemma Rewrites.append_left (hvw : r.Rewrites u v) (p : List (Symbol T N)) :
    r.Rewrites (p ++ u) (p ++ v) := by
rw [rewrites_iff] at *
  rcases hvw with ⟨x, y, hxy⟩
  use p ++ x, y
  simp_all

/-- Add extra postfix to context-free rewriting. -/
```

-- snippet 7
```lean
-- Mathlib.Computability.ContextFreeGrammar.Rewrites (L109-L122)
lemma Rewrites.append_right (hvw : r.Rewrites u v) (p : List (Symbol T N)) :
    r.Rewrites (u ++ p) (v ++ p) := by
rw [rewrites_iff] at *
  rcases hvw with ⟨x, y, hxy⟩
  use x, y ++ p
  simp_all

end ContextFreeRule

namespace ContextFreeGrammar

/-- Given a context-free grammar `g` and strings `u` and `v`
`g.Produces u v` means that one step of a context-free transformation by a rule from `g` sends
`u` to `v`. -/
```

-- snippet 8
```lean
-- Mathlib.Computability.ContextFreeGrammar.Produces (L123-L127)
def Produces (g : ContextFreeGrammar T) (u v : List (Symbol T g.NT)) : Prop :=
∃ r ∈ g.rules, r.Rewrites u v

/-- Given a context-free grammar `g` and strings `u` and `v`
`g.Derives u v` means that `g` can transform `u` to `v` in some number of rewriting steps. -/
```

-- snippet 9
```lean
-- Mathlib.Computability.ContextFreeGrammar.Derives (L128-L134)
abbrev Derives (g : ContextFreeGrammar T) :
    List (Symbol T g.NT) → List (Symbol T g.NT) → Prop :=
Relation.ReflTransGen g.Produces

/-- Given a context-free grammar `g` and a string `s`
`g.Generates s` means that `g` can transform its initial nonterminal to `s` in some number of
rewriting steps. -/
```

-- snippet 10
```lean
-- Mathlib.Computability.ContextFreeGrammar.Generates (L135-L138)
def Generates (g : ContextFreeGrammar T) (s : List (Symbol T g.NT)) : Prop :=
g.Derives [Symbol.nonterminal g.initial] s

/-- The language (set of words) that can be generated by a given context-free grammar `g`. -/
```

-- snippet 11
```lean
-- Mathlib.Computability.ContextFreeGrammar.language (L139-L144)
def language (g : ContextFreeGrammar T) : Language T :=
{ w : List T | g.Generates (w.map Symbol.terminal) }

/-- A given word `w` belongs to the language generated by a given context-free grammar `g` iff
`g` can derive the word `w` (wrapped as a string) from the initial nonterminal of `g` in some
number of steps. -/
```

-- snippet 12
```lean
-- Mathlib.Computability.ContextFreeGrammar.Derives (L153-L155)
lemma Derives.refl (w : List (Symbol T g.NT)) : g.Derives w w :=
Relation.ReflTransGen.refl
```

-- snippet 13
```lean
-- Mathlib.Computability.ContextFreeGrammar.Produces (L156-L158)
lemma Produces.single {v w : List (Symbol T g.NT)} (hvw : g.Produces v w) : g.Derives v w :=
Relation.ReflTransGen.single hvw
```

-- snippet 14
```lean
-- Mathlib.Computability.ContextFreeGrammar.Derives (L160-L163)
lemma Derives.trans {u v w : List (Symbol T g.NT)} (huv : g.Derives u v) (hvw : g.Derives v w) :
    g.Derives u w :=
Relation.ReflTransGen.trans huv hvw
```

-- snippet 15
```lean
-- Mathlib.Computability.ContextFreeGrammar.Derives (L164-L168)
lemma Derives.trans_produces {u v w : List (Symbol T g.NT)}
    (huv : g.Derives u v) (hvw : g.Produces v w) :
    g.Derives u w :=
huv.trans hvw.single
```
[/INST]


[System] You are Leanstral, a Lean 4 proof assistant. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.AlgebraicTopology.SimplicialSet.HomotopyCat).

[User]
Complete the following proof.

Open namespaces: CategoryTheory, Category, Limits, Functor, Opposite, Simplicial, Nerve, SimplexCategory.Truncated

## Surrounding context in Mathlib/AlgebraicTopology/SimplicialSet/HomotopyCat.lean
```lean
-- Mathlib.AlgebraicTopology.SimplicialSet.HomotopyCat.OneTruncation₂ (L51-L52)
def OneTruncation₂ (S : SSet.Truncated 2)

-- Mathlib.AlgebraicTopology.SimplicialSet.HomotopyCat.reflQuiver (L59-L62)
instance reflQuiver (S : SSet.Truncated 2) : ReflQuiver (OneTruncation₂ S) where
  Hom

-- Mathlib.AlgebraicTopology.SimplicialSet.HomotopyCat.hom_ext (L64-L68)
lemma hom_ext
    {S : SSet.Truncated 2} {x y : OneTruncation₂ S} {f g : x ⟶ y}
    (h : f.edge = g.edge) : f = g
```

```lean
def quotientFunctor :
    Cat.FreeRefl (OneTruncation₂ V) ⥤ V.HomotopyCategory
```

Provide a complete Lean proof for the statement above. Do not include the statement in your answer.

You are Leanstral, a Lean 4 proof assistant. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.AlgebraicTopology.SimplicialSet.HomotopyCat).

Complete the following proof.

Open namespaces: CategoryTheory, Category, Limits, Functor, Opposite, Simplicial, Nerve, SimplexCategory.Truncated

## Surrounding context in Mathlib/AlgebraicTopology/SimplicialSet/HomotopyCat.lean
```lean
-- Mathlib.AlgebraicTopology.SimplicialSet.HomotopyCat.OneTruncation₂ (L51-L52)
def OneTruncation₂ (S : SSet.Truncated 2)

-- Mathlib.AlgebraicTopology.SimplicialSet.HomotopyCat.reflQuiver (L59-L62)
instance reflQuiver (S : SSet.Truncated 2) : ReflQuiver (OneTruncation₂ S) where
  Hom

-- Mathlib.AlgebraicTopology.SimplicialSet.HomotopyCat.hom_ext (L64-L68)
lemma hom_ext
    {S : SSet.Truncated 2} {x y : OneTruncation₂ S} {f g : x ⟶ y}
    (h : f.edge = g.edge) : f = g
```

```lean
def quotientFunctor :
    Cat.FreeRefl (OneTruncation₂ V) ⥤ V.HomotopyCategory
```

Provide a complete Lean proof for the statement above. Do not include the statement in your answer.