[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.Algebra.MvPolynomial.CommRing).

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

```lean
theorem totalDegree_neg (a : MvPolynomial σ R) : (-a).totalDegree = a.totalDegree
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.C_sub (L60-L62)
theorem C_sub : (C (a - a') : MvPolynomial σ R) = C a - C a' :=
map_sub _ _ _
```

-- snippet 2
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.C_neg (L64-L66)
theorem C_neg : (C (-a) : MvPolynomial σ R) = -C a :=
map_neg _ _
```

-- snippet 3
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.coeff_neg (L68-L70)
theorem coeff_neg (m : σ →₀ ℕ) (p : MvPolynomial σ R) : coeff m (-p) = -coeff m p :=
Finsupp.neg_apply _ _
```

-- snippet 4
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.coeff_sub (L72-L74)
theorem coeff_sub (m : σ →₀ ℕ) (p q : MvPolynomial σ R) : coeff m (p - q) = coeff m p - coeff m q :=
Finsupp.sub_apply _ _ _
```

-- snippet 5
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.support_neg (L76-L78)
theorem support_neg : (-p).support = p.support :=
Finsupp.support_neg p
```

-- snippet 6
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.support_sub (L79-L86)
theorem support_sub [DecidableEq σ] (p q : MvPolynomial σ R) :
    (p - q).support ⊆ p.support ∪ q.support :=
Finsupp.support_sub

variable {σ} (p)

section Degrees
```

-- snippet 7
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.degrees_neg (L88-L90)
theorem degrees_neg (p : MvPolynomial σ R) : (-p).degrees = p.degrees := by
rw [degrees, support_neg]; rfl
```

-- snippet 8
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.degrees_sub_le (L91-L98)
theorem degrees_sub_le [DecidableEq σ] {p q : MvPolynomial σ R} :
    (p - q).degrees ≤ p.degrees ∪ q.degrees := by
simpa [degrees_def] using AddMonoidAlgebra.supDegree_sub_le

end Degrees

section Degrees
```

-- snippet 9
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.degreeOf_neg (L100-L102)
theorem degreeOf_neg (i : σ) (p : MvPolynomial σ R) : degreeOf i (-p) = degreeOf i p := by
rw [degreeOf, degreeOf, degrees_neg]
```

-- snippet 10
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.degreeOf_sub_le (L103-L110)
theorem degreeOf_sub_le (i : σ) (p q : MvPolynomial σ R) :
    degreeOf i (p - q) ≤ max (degreeOf i p) (degreeOf i q) := by
simpa only [sub_eq_add_neg, degreeOf_neg] using degreeOf_add_le i p (-q)

end Degrees

section Vars
```

-- snippet 11
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.vars_neg (L112-L113)
theorem vars_neg : (-p).vars = p.vars := by simp [vars, degrees_neg]
```

-- snippet 12
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.vars_sub_subset (L114-L116)
theorem vars_sub_subset [DecidableEq σ] : (p - q).vars ⊆ p.vars ∪ q.vars := by
convert vars_add_subset p (-q) using 2 <;> simp [sub_eq_add_neg]
```

-- snippet 13
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.vars_sub_of_disjoint (L118-L129)
theorem vars_sub_of_disjoint [DecidableEq σ] (hpq : Disjoint p.vars q.vars) :
    (p - q).vars = p.vars ∪ q.vars := by
rw [← vars_neg q] at hpq
  convert vars_add_of_disjoint hpq using 2 <;> simp [sub_eq_add_neg]

end Vars

section Eval

variable [CommRing S]
variable (f : R →+* S) (g : σ → S)
```

-- snippet 14
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.eval₂_sub (L131-L133)
theorem eval₂_sub : (p - q).eval₂ f g = p.eval₂ f g - q.eval₂ f g :=
(eval₂Hom f g).map_sub _ _
```

-- snippet 15
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.eval_sub (L134-L136)
theorem eval_sub (f : σ → R) : eval f (p - q) = eval f p - eval f q :=
eval₂_sub _ _ _
```

-- snippet 16
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_inj (L172-L175)
theorem C_inj {σ : Type*} (R : Type*) [CommSemiring R] (r s : R) :
    (C r : MvPolynomial σ R) = C s ↔ r = s :=
(C_injective σ R).eq_iff
```

-- snippet 17
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_add (L149-L151)
theorem C_add : (C (a + a') : MvPolynomial σ R) = C a + C a' :=
Finsupp.single_add _ _ _
```

-- snippet 18
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.monomial_left_injective (L124-L127)
theorem monomial_left_injective {r : R} (hr : r ≠ 0) :
    Function.Injective fun s : σ →₀ ℕ => monomial s r :=
Finsupp.single_left_injective hr
```

-- snippet 19
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.one_def (L95-L96)
theorem one_def : (1 : MvPolynomial σ R) = monomial 0 1 := rfl
```

-- snippet 20
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.single_eq_monomial (L97-L99)
theorem single_eq_monomial (s : σ →₀ ℕ) (a : R) : Finsupp.single s a = monomial s a :=
rfl
```

-- snippet 21
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.X (L121-L123)
def X (n : σ) : MvPolynomial σ R :=
monomial (Finsupp.single n 1) 1
```

-- snippet 22
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.infinite_of_infinite (L185-L188)
instance infinite_of_infinite (σ : Type*) (R : Type*) [CommSemiring R] [Infinite R] :
    Infinite (MvPolynomial σ R) :=
Infinite.of_injective C (C_injective _ _)
```

-- snippet 23
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.monomial_left_inj (L129-L132)
theorem monomial_left_inj {s t : σ →₀ ℕ} {r : R} (hr : r ≠ 0) :
    monomial s r = monomial t r ↔ s = t :=
Finsupp.single_left_inj hr
```

-- snippet 24
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.MvPolynomial (L81-L91)
abbrev MvPolynomial (σ : Type*) (R : Type*) [CommSemiring R] :=
AddMonoidAlgebra R (σ →₀ ℕ)

namespace MvPolynomial

variable {σ : Type*} {a a' a₁ a₂ : R} {e : ℕ} {n m : σ} {s : σ →₀ ℕ}

section CommSemiring
variable [CommSemiring R] [CommSemiring S₁] {p q : MvPolynomial σ R}

/-- `monomial s a` is the monomial with coefficient `a` and exponents given by `s` -/
```

-- snippet 25
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_apply (L133-L135)
theorem C_apply : (C a : MvPolynomial σ R) = monomial 0 a :=
rfl
```

-- snippet 26
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.algebraMap_apply (L116-L120)
theorem algebraMap_apply [Algebra R S₁] (r : R) :
    algebraMap R (MvPolynomial σ S₁) r = C (algebraMap R S₁ r) :=
rfl

/-- `X n` is the degree `1` monomial $X_n$. -/
```

-- snippet 27
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_1 (L140-L142)
theorem C_1 : C 1 = (1 : MvPolynomial σ R) :=
rfl
```

-- snippet 28
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_surjective (L164-L170)
theorem C_surjective {R : Type*} [CommSemiring R] (σ : Type*) [IsEmpty σ] :
    Function.Surjective (C : R → MvPolynomial σ R) := by
refine fun p => ⟨p.toFun 0, Finsupp.ext fun a => ?_⟩
  simp only [C_apply, ← single_eq_monomial, (Finsupp.ext isEmptyElim (α := σ) : a = 0),
    single_eq_same]
  rfl
```

-- snippet 29
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_pow (L157-L159)
theorem C_pow (a : R) (n : ℕ) : (C (a ^ n) : MvPolynomial σ R) = C a ^ n :=
map_pow _ _ _
```

-- snippet 30
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.mul_def (L100-L103)
theorem mul_def : p * q = p.sum fun m a => q.sum fun n b => monomial (m + n) (a * b) :=
AddMonoidAlgebra.mul_def ..

/-- `C a` is the constant polynomial with value `a` -/
```

-- snippet 31
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_ne_zero (L178-L180)
lemma C_ne_zero : (C a : MvPolynomial σ R) ≠ 0 ↔ a ≠ 0 :=
C_eq_zero.ne
```

-- snippet 32
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.nontrivial_of_nontrivial (L181-L184)
instance nontrivial_of_nontrivial (σ : Type*) (R : Type*) [CommSemiring R] [Nontrivial R] :
    Nontrivial (MvPolynomial σ R) :=
inferInstanceAs (Nontrivial <| AddMonoidAlgebra R (σ →₀ ℕ))
```

-- snippet 33
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C (L104-L108)
def C : R →+* MvPolynomial σ R :=
{ singleZeroRingHom with toFun := monomial 0 }

variable (R σ)
```

-- snippet 34
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_mul (L153-L155)
theorem C_mul : (C (a * a') : MvPolynomial σ R) = C a * C a' :=
C_mul_monomial.symm
```

-- snippet 35
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.algebraMap_eq (L110-L114)
theorem algebraMap_eq : algebraMap R (MvPolynomial σ R) = C :=
rfl

variable {R σ}
```

-- snippet 36
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_injective (L160-L163)
theorem C_injective (σ : Type*) (R : Type*) [CommSemiring R] :
    Function.Injective (C : R → MvPolynomial σ R) :=
Finsupp.single_injective _
```

-- snippet 37
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.monomial (L92-L94)
def monomial (s : σ →₀ ℕ) : R →ₗ[R] MvPolynomial σ R :=
AddMonoidAlgebra.lsingle s
```

-- snippet 38
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_mul_monomial (L143-L147)
theorem C_mul_monomial : C a * monomial s a' = monomial s (a * a') := by
have := single_mul_single 0 s a a'
  rw [zero_add] at this
  exact this
```

-- snippet 39
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_0 (L137-L138)
theorem C_0 : C 0 = (0 : MvPolynomial σ R) := map_zero _
```

-- snippet 40
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.infinite_of_nonempty (L189-L193)
instance infinite_of_nonempty (σ : Type*) (R : Type*) [Nonempty σ] [CommSemiring R]
    [Nontrivial R] : Infinite (MvPolynomial σ R) :=
Infinite.of_injective ((fun s : σ →₀ ℕ => monomial s 1) ∘ Finsupp.single (Classical.arbitrary σ))
    <| (monomial_left_injective one_ne_zero).comp (Finsupp.single_injective _)
```

<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.Algebra.MvPolynomial.CommRing).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]Prove the following theorem. The retrieved context below may help.

```lean
theorem totalDegree_neg (a : MvPolynomial σ R) : (-a).totalDegree = a.totalDegree
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.C_sub (L60-L62)
theorem C_sub : (C (a - a') : MvPolynomial σ R) = C a - C a' :=
map_sub _ _ _
```

-- snippet 2
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.C_neg (L64-L66)
theorem C_neg : (C (-a) : MvPolynomial σ R) = -C a :=
map_neg _ _
```

-- snippet 3
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.coeff_neg (L68-L70)
theorem coeff_neg (m : σ →₀ ℕ) (p : MvPolynomial σ R) : coeff m (-p) = -coeff m p :=
Finsupp.neg_apply _ _
```

-- snippet 4
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.coeff_sub (L72-L74)
theorem coeff_sub (m : σ →₀ ℕ) (p q : MvPolynomial σ R) : coeff m (p - q) = coeff m p - coeff m q :=
Finsupp.sub_apply _ _ _
```

-- snippet 5
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.support_neg (L76-L78)
theorem support_neg : (-p).support = p.support :=
Finsupp.support_neg p
```

-- snippet 6
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.support_sub (L79-L86)
theorem support_sub [DecidableEq σ] (p q : MvPolynomial σ R) :
    (p - q).support ⊆ p.support ∪ q.support :=
Finsupp.support_sub

variable {σ} (p)

section Degrees
```

-- snippet 7
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.degrees_neg (L88-L90)
theorem degrees_neg (p : MvPolynomial σ R) : (-p).degrees = p.degrees := by
rw [degrees, support_neg]; rfl
```

-- snippet 8
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.degrees_sub_le (L91-L98)
theorem degrees_sub_le [DecidableEq σ] {p q : MvPolynomial σ R} :
    (p - q).degrees ≤ p.degrees ∪ q.degrees := by
simpa [degrees_def] using AddMonoidAlgebra.supDegree_sub_le

end Degrees

section Degrees
```

-- snippet 9
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.degreeOf_neg (L100-L102)
theorem degreeOf_neg (i : σ) (p : MvPolynomial σ R) : degreeOf i (-p) = degreeOf i p := by
rw [degreeOf, degreeOf, degrees_neg]
```

-- snippet 10
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.degreeOf_sub_le (L103-L110)
theorem degreeOf_sub_le (i : σ) (p q : MvPolynomial σ R) :
    degreeOf i (p - q) ≤ max (degreeOf i p) (degreeOf i q) := by
simpa only [sub_eq_add_neg, degreeOf_neg] using degreeOf_add_le i p (-q)

end Degrees

section Vars
```

-- snippet 11
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.vars_neg (L112-L113)
theorem vars_neg : (-p).vars = p.vars := by simp [vars, degrees_neg]
```

-- snippet 12
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.vars_sub_subset (L114-L116)
theorem vars_sub_subset [DecidableEq σ] : (p - q).vars ⊆ p.vars ∪ q.vars := by
convert vars_add_subset p (-q) using 2 <;> simp [sub_eq_add_neg]
```

-- snippet 13
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.vars_sub_of_disjoint (L118-L129)
theorem vars_sub_of_disjoint [DecidableEq σ] (hpq : Disjoint p.vars q.vars) :
    (p - q).vars = p.vars ∪ q.vars := by
rw [← vars_neg q] at hpq
  convert vars_add_of_disjoint hpq using 2 <;> simp [sub_eq_add_neg]

end Vars

section Eval

variable [CommRing S]
variable (f : R →+* S) (g : σ → S)
```

-- snippet 14
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.eval₂_sub (L131-L133)
theorem eval₂_sub : (p - q).eval₂ f g = p.eval₂ f g - q.eval₂ f g :=
(eval₂Hom f g).map_sub _ _
```

-- snippet 15
```lean
-- Mathlib.Algebra.MvPolynomial.CommRing.eval_sub (L134-L136)
theorem eval_sub (f : σ → R) : eval f (p - q) = eval f p - eval f q :=
eval₂_sub _ _ _
```

-- snippet 16
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_inj (L172-L175)
theorem C_inj {σ : Type*} (R : Type*) [CommSemiring R] (r s : R) :
    (C r : MvPolynomial σ R) = C s ↔ r = s :=
(C_injective σ R).eq_iff
```

-- snippet 17
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_add (L149-L151)
theorem C_add : (C (a + a') : MvPolynomial σ R) = C a + C a' :=
Finsupp.single_add _ _ _
```

-- snippet 18
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.monomial_left_injective (L124-L127)
theorem monomial_left_injective {r : R} (hr : r ≠ 0) :
    Function.Injective fun s : σ →₀ ℕ => monomial s r :=
Finsupp.single_left_injective hr
```

-- snippet 19
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.one_def (L95-L96)
theorem one_def : (1 : MvPolynomial σ R) = monomial 0 1 := rfl
```

-- snippet 20
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.single_eq_monomial (L97-L99)
theorem single_eq_monomial (s : σ →₀ ℕ) (a : R) : Finsupp.single s a = monomial s a :=
rfl
```

-- snippet 21
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.X (L121-L123)
def X (n : σ) : MvPolynomial σ R :=
monomial (Finsupp.single n 1) 1
```

-- snippet 22
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.infinite_of_infinite (L185-L188)
instance infinite_of_infinite (σ : Type*) (R : Type*) [CommSemiring R] [Infinite R] :
    Infinite (MvPolynomial σ R) :=
Infinite.of_injective C (C_injective _ _)
```

-- snippet 23
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.monomial_left_inj (L129-L132)
theorem monomial_left_inj {s t : σ →₀ ℕ} {r : R} (hr : r ≠ 0) :
    monomial s r = monomial t r ↔ s = t :=
Finsupp.single_left_inj hr
```

-- snippet 24
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.MvPolynomial (L81-L91)
abbrev MvPolynomial (σ : Type*) (R : Type*) [CommSemiring R] :=
AddMonoidAlgebra R (σ →₀ ℕ)

namespace MvPolynomial

variable {σ : Type*} {a a' a₁ a₂ : R} {e : ℕ} {n m : σ} {s : σ →₀ ℕ}

section CommSemiring
variable [CommSemiring R] [CommSemiring S₁] {p q : MvPolynomial σ R}

/-- `monomial s a` is the monomial with coefficient `a` and exponents given by `s` -/
```

-- snippet 25
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_apply (L133-L135)
theorem C_apply : (C a : MvPolynomial σ R) = monomial 0 a :=
rfl
```

-- snippet 26
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.algebraMap_apply (L116-L120)
theorem algebraMap_apply [Algebra R S₁] (r : R) :
    algebraMap R (MvPolynomial σ S₁) r = C (algebraMap R S₁ r) :=
rfl

/-- `X n` is the degree `1` monomial $X_n$. -/
```

-- snippet 27
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_1 (L140-L142)
theorem C_1 : C 1 = (1 : MvPolynomial σ R) :=
rfl
```

-- snippet 28
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_surjective (L164-L170)
theorem C_surjective {R : Type*} [CommSemiring R] (σ : Type*) [IsEmpty σ] :
    Function.Surjective (C : R → MvPolynomial σ R) := by
refine fun p => ⟨p.toFun 0, Finsupp.ext fun a => ?_⟩
  simp only [C_apply, ← single_eq_monomial, (Finsupp.ext isEmptyElim (α := σ) : a = 0),
    single_eq_same]
  rfl
```

-- snippet 29
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_pow (L157-L159)
theorem C_pow (a : R) (n : ℕ) : (C (a ^ n) : MvPolynomial σ R) = C a ^ n :=
map_pow _ _ _
```

-- snippet 30
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.mul_def (L100-L103)
theorem mul_def : p * q = p.sum fun m a => q.sum fun n b => monomial (m + n) (a * b) :=
AddMonoidAlgebra.mul_def ..

/-- `C a` is the constant polynomial with value `a` -/
```

-- snippet 31
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_ne_zero (L178-L180)
lemma C_ne_zero : (C a : MvPolynomial σ R) ≠ 0 ↔ a ≠ 0 :=
C_eq_zero.ne
```

-- snippet 32
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.nontrivial_of_nontrivial (L181-L184)
instance nontrivial_of_nontrivial (σ : Type*) (R : Type*) [CommSemiring R] [Nontrivial R] :
    Nontrivial (MvPolynomial σ R) :=
inferInstanceAs (Nontrivial <| AddMonoidAlgebra R (σ →₀ ℕ))
```

-- snippet 33
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C (L104-L108)
def C : R →+* MvPolynomial σ R :=
{ singleZeroRingHom with toFun := monomial 0 }

variable (R σ)
```

-- snippet 34
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_mul (L153-L155)
theorem C_mul : (C (a * a') : MvPolynomial σ R) = C a * C a' :=
C_mul_monomial.symm
```

-- snippet 35
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.algebraMap_eq (L110-L114)
theorem algebraMap_eq : algebraMap R (MvPolynomial σ R) = C :=
rfl

variable {R σ}
```

-- snippet 36
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_injective (L160-L163)
theorem C_injective (σ : Type*) (R : Type*) [CommSemiring R] :
    Function.Injective (C : R → MvPolynomial σ R) :=
Finsupp.single_injective _
```

-- snippet 37
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.monomial (L92-L94)
def monomial (s : σ →₀ ℕ) : R →ₗ[R] MvPolynomial σ R :=
AddMonoidAlgebra.lsingle s
```

-- snippet 38
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_mul_monomial (L143-L147)
theorem C_mul_monomial : C a * monomial s a' = monomial s (a * a') := by
have := single_mul_single 0 s a a'
  rw [zero_add] at this
  exact this
```

-- snippet 39
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.C_0 (L137-L138)
theorem C_0 : C 0 = (0 : MvPolynomial σ R) := map_zero _
```

-- snippet 40
```lean
-- Mathlib.Algebra.MvPolynomial.Basic.infinite_of_nonempty (L189-L193)
instance infinite_of_nonempty (σ : Type*) (R : Type*) [Nonempty σ] [CommSemiring R]
    [Nontrivial R] : Infinite (MvPolynomial σ R) :=
Infinite.of_injective ((fun s : σ →₀ ℕ => monomial s 1) ∘ Finsupp.single (Classical.arbitrary σ))
    <| (monomial_left_injective one_ne_zero).comp (Finsupp.single_injective _)
```
[/INST]


[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.Analysis.Normed.Group.Int).

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

```lean
theorem norm_zpow_le_mul_norm (n : ℤ) (a : α) : ‖a ^ n‖ ≤ ‖n‖ * ‖a‖
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Analysis.Normed.Group.Int.instNormedAddCommGroup (L20-L25)
instance instNormedAddCommGroup : NormedAddCommGroup ℤ where
  norm n := ‖(n : ℝ)‖
dist_eq m n := by
    simp only [dist_eq, norm, cast_add, cast_neg]
    rw [abs_sub_comm, neg_add_eq_sub]
```

-- snippet 2
```lean
-- Mathlib.Analysis.Normed.Group.Int.norm_cast_real (L27-L29)
theorem norm_cast_real (m : ℤ) : ‖(m : ℝ)‖ = ‖m‖ :=
rfl
```

-- snippet 3
```lean
-- Mathlib.Analysis.Normed.Group.Int.norm_eq_abs (L30-L32)
theorem norm_eq_abs (n : ℤ) : ‖n‖ = |(n : ℝ)| :=
rfl
```

-- snippet 4
```lean
-- Mathlib.Analysis.Normed.Group.Int.norm_natCast (L33-L34)
theorem norm_natCast (n : ℕ) : ‖(n : ℤ)‖ = n := by simp [Int.norm_eq_abs]
```

-- snippet 5
```lean
-- Mathlib.Analysis.Normed.Group.Int.abs_le_floor_nnreal_iff (L42-L48)
theorem abs_le_floor_nnreal_iff (z : ℤ) (c : ℝ≥0) : |z| ≤ ⌊c⌋₊ ↔ ‖z‖₊ ≤ c := by
rw [Int.abs_eq_natAbs, Int.ofNat_le, Nat.le_floor_iff (zero_le c), NNReal.natCast_natAbs z]

end Int

-- Now that we've installed the norm on `ℤ`,
-- we can state some lemmas about `zsmul`.
```

-- snippet 6
```lean
-- Mathlib.Analysis.Normed.Group.Int.nnnorm_zpow_le_mul_norm (L58-L60)
theorem nnnorm_zpow_le_mul_norm (n : ℤ) (a : α) : ‖a ^ n‖₊ ≤ ‖n‖₊ * ‖a‖₊ := by
simpa only [← NNReal.coe_le_coe, NNReal.coe_mul] using norm_zpow_le_mul_norm n a
```

-- snippet 7
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_lineMap_lineMap (L67-L70)
theorem nndist_lineMap_lineMap (p₁ p₂ : P) (c₁ c₂ : 𝕜) :
    nndist (lineMap p₁ p₂ c₁) (lineMap p₁ p₂ c₂) = nndist c₁ c₂ * nndist p₁ p₂ :=
NNReal.eq <| dist_lineMap_lineMap _ _ _ _
```

-- snippet 8
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_midpoint_right (L159-L162)
theorem nndist_midpoint_right (p₁ p₂ : P) :
    nndist (midpoint 𝕜 p₁ p₂) p₂ = ‖(2 : 𝕜)‖₊⁻¹ * nndist p₁ p₂ :=
NNReal.eq <| dist_midpoint_right _ _
```

-- snippet 9
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_right_lineMap (L104-L106)
theorem dist_right_lineMap (p₁ p₂ : P) (c : 𝕜) : dist p₂ (lineMap p₁ p₂ c) = ‖1 - c‖ * dist p₁ p₂ :=
(dist_comm _ _).trans (dist_lineMap_right _ _ _)
```

-- snippet 10
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_center_homothety (L41-L44)
theorem dist_center_homothety (p₁ p₂ : P) (c : 𝕜) :
    dist p₁ (homothety p₁ c p₂) = ‖c‖ * dist p₁ p₂ := by
simp [homothety_def, norm_smul, ← dist_eq_norm_vsub, dist_comm]
```

-- snippet 11
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_lineMap_lineMap (L60-L65)
theorem dist_lineMap_lineMap (p₁ p₂ : P) (c₁ c₂ : 𝕜) :
    dist (lineMap p₁ p₂ c₁) (lineMap p₁ p₂ c₂) = dist c₁ c₂ * dist p₁ p₂ := by
rw [dist_comm p₁ p₂]
  simp only [lineMap_apply, dist_eq_norm_vsub, vadd_vsub_vadd_cancel_right,
    ← sub_smul, norm_smul, vsub_eq_sub]
```

-- snippet 12
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_lineMap_right (L99-L102)
theorem nndist_lineMap_right (p₁ p₂ : P) (c : 𝕜) :
    nndist (lineMap p₁ p₂ c) p₂ = ‖1 - c‖₊ * nndist p₁ p₂ :=
NNReal.eq <| dist_lineMap_right _ _ _
```

-- snippet 13
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_homothety_center (L55-L58)
theorem nndist_homothety_center (p₁ p₂ : P) (c : 𝕜) :
    nndist (homothety p₁ c p₂) p₁ = ‖c‖₊ * nndist p₁ p₂ :=
NNReal.eq <| dist_homothety_center _ _ _
```

-- snippet 14
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_homothety_self (L113-L116)
theorem dist_homothety_self (p₁ p₂ : P) (c : 𝕜) :
    dist (homothety p₁ c p₂) p₂ = ‖1 - c‖ * dist p₁ p₂ := by
rw [homothety_eq_lineMap, dist_lineMap_right]
```

-- snippet 15
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_lineMap_left (L80-L83)
theorem nndist_lineMap_left (p₁ p₂ : P) (c : 𝕜) :
    nndist (lineMap p₁ p₂ c) p₁ = ‖c‖₊ * nndist p₁ p₂ :=
NNReal.eq <| dist_lineMap_left _ _ _
```

-- snippet 16
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_self_homothety (L123-L125)
theorem dist_self_homothety (p₁ p₂ : P) (c : 𝕜) :
    dist p₂ (homothety p₁ c p₂) = ‖1 - c‖ * dist p₁ p₂ := by rw [dist_comm, dist_homothety_self]
```

-- snippet 17
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_lineMap_left (L76-L78)
theorem dist_lineMap_left (p₁ p₂ : P) (c : 𝕜) : dist (lineMap p₁ p₂ c) p₁ = ‖c‖ * dist p₁ p₂ := by
simpa only [lineMap_apply_zero, dist_zero_right] using dist_lineMap_lineMap p₁ p₂ c 0
```

-- snippet 18
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_lineMap_right (L94-L97)
theorem dist_lineMap_right (p₁ p₂ : P) (c : 𝕜) :
    dist (lineMap p₁ p₂ c) p₂ = ‖1 - c‖ * dist p₁ p₂ := by
simpa only [lineMap_apply_one, dist_eq_norm'] using dist_lineMap_lineMap p₁ p₂ c 1
```

-- snippet 19
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_midpoint_right (L154-L157)
theorem dist_midpoint_right (p₁ p₂ : P) :
    dist (midpoint 𝕜 p₁ p₂) p₂ = ‖(2 : 𝕜)‖⁻¹ * dist p₁ p₂ := by
rw [midpoint_comm, dist_midpoint_left, dist_comm]
```

-- snippet 20
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_left_lineMap (L89-L92)
theorem nndist_left_lineMap (p₁ p₂ : P) (c : 𝕜) :
    nndist p₁ (lineMap p₁ p₂ c) = ‖c‖₊ * nndist p₁ p₂ :=
NNReal.eq <| dist_left_lineMap _ _ _
```

-- snippet 21
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_left_lineMap (L85-L87)
theorem dist_left_lineMap (p₁ p₂ : P) (c : 𝕜) : dist p₁ (lineMap p₁ p₂ c) = ‖c‖ * dist p₁ p₂ :=
(dist_comm _ _).trans (dist_lineMap_left _ _ _)
```

-- snippet 22
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_left_midpoint (L140-L143)
theorem nndist_left_midpoint (p₁ p₂ : P) :
    nndist p₁ (midpoint 𝕜 p₁ p₂) = ‖(2 : 𝕜)‖₊⁻¹ * nndist p₁ p₂ :=
NNReal.eq <| dist_left_midpoint _ _
```

-- snippet 23
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_center_homothety (L46-L49)
theorem nndist_center_homothety (p₁ p₂ : P) (c : 𝕜) :
    nndist p₁ (homothety p₁ c p₂) = ‖c‖₊ * nndist p₁ p₂ :=
NNReal.eq <| dist_center_homothety _ _ _
```

-- snippet 24
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_midpoint_left (L149-L152)
theorem nndist_midpoint_left (p₁ p₂ : P) :
    nndist (midpoint 𝕜 p₁ p₂) p₁ = ‖(2 : 𝕜)‖₊⁻¹ * nndist p₁ p₂ :=
NNReal.eq <| dist_midpoint_left _ _
```

-- snippet 25
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_self_homothety (L127-L134)
theorem nndist_self_homothety (p₁ p₂ : P) (c : 𝕜) :
    nndist p₂ (homothety p₁ c p₂) = ‖1 - c‖₊ * nndist p₁ p₂ :=
NNReal.eq <| dist_self_homothety _ _ _

section invertibleTwo

variable [Invertible (2 : 𝕜)]
```

-- snippet 26
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_right_lineMap (L108-L111)
theorem nndist_right_lineMap (p₁ p₂ : P) (c : 𝕜) :
    nndist p₂ (lineMap p₁ p₂ c) = ‖1 - c‖₊ * nndist p₁ p₂ :=
NNReal.eq <| dist_right_lineMap _ _ _
```

-- snippet 27
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.lipschitzWith_lineMap (L71-L74)
theorem lipschitzWith_lineMap (p₁ p₂ : P) : LipschitzWith (nndist p₁ p₂) (lineMap p₁ p₂ : 𝕜 → P) :=
LipschitzWith.of_dist_le_mul fun c₁ c₂ =>
    ((dist_lineMap_lineMap p₁ p₂ c₁ c₂).trans (mul_comm _ _)).le
```

-- snippet 28
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_homothety_center (L51-L53)
theorem dist_homothety_center (p₁ p₂ : P) (c : 𝕜) :
    dist (homothety p₁ c p₂) p₁ = ‖c‖ * dist p₁ p₂ := by rw [dist_comm, dist_center_homothety]
```

-- snippet 29
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_midpoint_left (L145-L147)
theorem dist_midpoint_left (p₁ p₂ : P) : dist (midpoint 𝕜 p₁ p₂) p₁ = ‖(2 : 𝕜)‖⁻¹ * dist p₁ p₂ := by
rw [dist_comm, dist_left_midpoint]
```

-- snippet 30
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_left_midpoint (L136-L138)
theorem dist_left_midpoint (p₁ p₂ : P) : dist p₁ (midpoint 𝕜 p₁ p₂) = ‖(2 : 𝕜)‖⁻¹ * dist p₁ p₂ := by
rw [midpoint, dist_comm, dist_lineMap_left, invOf_eq_inv, ← norm_inv]
```

-- snippet 31
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_homothety_self (L118-L121)
theorem nndist_homothety_self (p₁ p₂ : P) (c : 𝕜) :
    nndist (homothety p₁ c p₂) p₂ = ‖1 - c‖₊ * nndist p₁ p₂ :=
NNReal.eq <| dist_homothety_self _ _ _
```

<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.Analysis.Normed.Group.Int).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]Prove the following theorem. The retrieved context below may help.

```lean
theorem norm_zpow_le_mul_norm (n : ℤ) (a : α) : ‖a ^ n‖ ≤ ‖n‖ * ‖a‖
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Analysis.Normed.Group.Int.instNormedAddCommGroup (L20-L25)
instance instNormedAddCommGroup : NormedAddCommGroup ℤ where
  norm n := ‖(n : ℝ)‖
dist_eq m n := by
    simp only [dist_eq, norm, cast_add, cast_neg]
    rw [abs_sub_comm, neg_add_eq_sub]
```

-- snippet 2
```lean
-- Mathlib.Analysis.Normed.Group.Int.norm_cast_real (L27-L29)
theorem norm_cast_real (m : ℤ) : ‖(m : ℝ)‖ = ‖m‖ :=
rfl
```

-- snippet 3
```lean
-- Mathlib.Analysis.Normed.Group.Int.norm_eq_abs (L30-L32)
theorem norm_eq_abs (n : ℤ) : ‖n‖ = |(n : ℝ)| :=
rfl
```

-- snippet 4
```lean
-- Mathlib.Analysis.Normed.Group.Int.norm_natCast (L33-L34)
theorem norm_natCast (n : ℕ) : ‖(n : ℤ)‖ = n := by simp [Int.norm_eq_abs]
```

-- snippet 5
```lean
-- Mathlib.Analysis.Normed.Group.Int.abs_le_floor_nnreal_iff (L42-L48)
theorem abs_le_floor_nnreal_iff (z : ℤ) (c : ℝ≥0) : |z| ≤ ⌊c⌋₊ ↔ ‖z‖₊ ≤ c := by
rw [Int.abs_eq_natAbs, Int.ofNat_le, Nat.le_floor_iff (zero_le c), NNReal.natCast_natAbs z]

end Int

-- Now that we've installed the norm on `ℤ`,
-- we can state some lemmas about `zsmul`.
```

-- snippet 6
```lean
-- Mathlib.Analysis.Normed.Group.Int.nnnorm_zpow_le_mul_norm (L58-L60)
theorem nnnorm_zpow_le_mul_norm (n : ℤ) (a : α) : ‖a ^ n‖₊ ≤ ‖n‖₊ * ‖a‖₊ := by
simpa only [← NNReal.coe_le_coe, NNReal.coe_mul] using norm_zpow_le_mul_norm n a
```

-- snippet 7
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_lineMap_lineMap (L67-L70)
theorem nndist_lineMap_lineMap (p₁ p₂ : P) (c₁ c₂ : 𝕜) :
    nndist (lineMap p₁ p₂ c₁) (lineMap p₁ p₂ c₂) = nndist c₁ c₂ * nndist p₁ p₂ :=
NNReal.eq <| dist_lineMap_lineMap _ _ _ _
```

-- snippet 8
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_midpoint_right (L159-L162)
theorem nndist_midpoint_right (p₁ p₂ : P) :
    nndist (midpoint 𝕜 p₁ p₂) p₂ = ‖(2 : 𝕜)‖₊⁻¹ * nndist p₁ p₂ :=
NNReal.eq <| dist_midpoint_right _ _
```

-- snippet 9
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_right_lineMap (L104-L106)
theorem dist_right_lineMap (p₁ p₂ : P) (c : 𝕜) : dist p₂ (lineMap p₁ p₂ c) = ‖1 - c‖ * dist p₁ p₂ :=
(dist_comm _ _).trans (dist_lineMap_right _ _ _)
```

-- snippet 10
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_center_homothety (L41-L44)
theorem dist_center_homothety (p₁ p₂ : P) (c : 𝕜) :
    dist p₁ (homothety p₁ c p₂) = ‖c‖ * dist p₁ p₂ := by
simp [homothety_def, norm_smul, ← dist_eq_norm_vsub, dist_comm]
```

-- snippet 11
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_lineMap_lineMap (L60-L65)
theorem dist_lineMap_lineMap (p₁ p₂ : P) (c₁ c₂ : 𝕜) :
    dist (lineMap p₁ p₂ c₁) (lineMap p₁ p₂ c₂) = dist c₁ c₂ * dist p₁ p₂ := by
rw [dist_comm p₁ p₂]
  simp only [lineMap_apply, dist_eq_norm_vsub, vadd_vsub_vadd_cancel_right,
    ← sub_smul, norm_smul, vsub_eq_sub]
```

-- snippet 12
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_lineMap_right (L99-L102)
theorem nndist_lineMap_right (p₁ p₂ : P) (c : 𝕜) :
    nndist (lineMap p₁ p₂ c) p₂ = ‖1 - c‖₊ * nndist p₁ p₂ :=
NNReal.eq <| dist_lineMap_right _ _ _
```

-- snippet 13
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_homothety_center (L55-L58)
theorem nndist_homothety_center (p₁ p₂ : P) (c : 𝕜) :
    nndist (homothety p₁ c p₂) p₁ = ‖c‖₊ * nndist p₁ p₂ :=
NNReal.eq <| dist_homothety_center _ _ _
```

-- snippet 14
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_homothety_self (L113-L116)
theorem dist_homothety_self (p₁ p₂ : P) (c : 𝕜) :
    dist (homothety p₁ c p₂) p₂ = ‖1 - c‖ * dist p₁ p₂ := by
rw [homothety_eq_lineMap, dist_lineMap_right]
```

-- snippet 15
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_lineMap_left (L80-L83)
theorem nndist_lineMap_left (p₁ p₂ : P) (c : 𝕜) :
    nndist (lineMap p₁ p₂ c) p₁ = ‖c‖₊ * nndist p₁ p₂ :=
NNReal.eq <| dist_lineMap_left _ _ _
```

-- snippet 16
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_self_homothety (L123-L125)
theorem dist_self_homothety (p₁ p₂ : P) (c : 𝕜) :
    dist p₂ (homothety p₁ c p₂) = ‖1 - c‖ * dist p₁ p₂ := by rw [dist_comm, dist_homothety_self]
```

-- snippet 17
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_lineMap_left (L76-L78)
theorem dist_lineMap_left (p₁ p₂ : P) (c : 𝕜) : dist (lineMap p₁ p₂ c) p₁ = ‖c‖ * dist p₁ p₂ := by
simpa only [lineMap_apply_zero, dist_zero_right] using dist_lineMap_lineMap p₁ p₂ c 0
```

-- snippet 18
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_lineMap_right (L94-L97)
theorem dist_lineMap_right (p₁ p₂ : P) (c : 𝕜) :
    dist (lineMap p₁ p₂ c) p₂ = ‖1 - c‖ * dist p₁ p₂ := by
simpa only [lineMap_apply_one, dist_eq_norm'] using dist_lineMap_lineMap p₁ p₂ c 1
```

-- snippet 19
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_midpoint_right (L154-L157)
theorem dist_midpoint_right (p₁ p₂ : P) :
    dist (midpoint 𝕜 p₁ p₂) p₂ = ‖(2 : 𝕜)‖⁻¹ * dist p₁ p₂ := by
rw [midpoint_comm, dist_midpoint_left, dist_comm]
```

-- snippet 20
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_left_lineMap (L89-L92)
theorem nndist_left_lineMap (p₁ p₂ : P) (c : 𝕜) :
    nndist p₁ (lineMap p₁ p₂ c) = ‖c‖₊ * nndist p₁ p₂ :=
NNReal.eq <| dist_left_lineMap _ _ _
```

-- snippet 21
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_left_lineMap (L85-L87)
theorem dist_left_lineMap (p₁ p₂ : P) (c : 𝕜) : dist p₁ (lineMap p₁ p₂ c) = ‖c‖ * dist p₁ p₂ :=
(dist_comm _ _).trans (dist_lineMap_left _ _ _)
```

-- snippet 22
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_left_midpoint (L140-L143)
theorem nndist_left_midpoint (p₁ p₂ : P) :
    nndist p₁ (midpoint 𝕜 p₁ p₂) = ‖(2 : 𝕜)‖₊⁻¹ * nndist p₁ p₂ :=
NNReal.eq <| dist_left_midpoint _ _
```

-- snippet 23
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_center_homothety (L46-L49)
theorem nndist_center_homothety (p₁ p₂ : P) (c : 𝕜) :
    nndist p₁ (homothety p₁ c p₂) = ‖c‖₊ * nndist p₁ p₂ :=
NNReal.eq <| dist_center_homothety _ _ _
```

-- snippet 24
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_midpoint_left (L149-L152)
theorem nndist_midpoint_left (p₁ p₂ : P) :
    nndist (midpoint 𝕜 p₁ p₂) p₁ = ‖(2 : 𝕜)‖₊⁻¹ * nndist p₁ p₂ :=
NNReal.eq <| dist_midpoint_left _ _
```

-- snippet 25
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_self_homothety (L127-L134)
theorem nndist_self_homothety (p₁ p₂ : P) (c : 𝕜) :
    nndist p₂ (homothety p₁ c p₂) = ‖1 - c‖₊ * nndist p₁ p₂ :=
NNReal.eq <| dist_self_homothety _ _ _

section invertibleTwo

variable [Invertible (2 : 𝕜)]
```

-- snippet 26
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_right_lineMap (L108-L111)
theorem nndist_right_lineMap (p₁ p₂ : P) (c : 𝕜) :
    nndist p₂ (lineMap p₁ p₂ c) = ‖1 - c‖₊ * nndist p₁ p₂ :=
NNReal.eq <| dist_right_lineMap _ _ _
```

-- snippet 27
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.lipschitzWith_lineMap (L71-L74)
theorem lipschitzWith_lineMap (p₁ p₂ : P) : LipschitzWith (nndist p₁ p₂) (lineMap p₁ p₂ : 𝕜 → P) :=
LipschitzWith.of_dist_le_mul fun c₁ c₂ =>
    ((dist_lineMap_lineMap p₁ p₂ c₁ c₂).trans (mul_comm _ _)).le
```

-- snippet 28
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_homothety_center (L51-L53)
theorem dist_homothety_center (p₁ p₂ : P) (c : 𝕜) :
    dist (homothety p₁ c p₂) p₁ = ‖c‖ * dist p₁ p₂ := by rw [dist_comm, dist_center_homothety]
```

-- snippet 29
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_midpoint_left (L145-L147)
theorem dist_midpoint_left (p₁ p₂ : P) : dist (midpoint 𝕜 p₁ p₂) p₁ = ‖(2 : 𝕜)‖⁻¹ * dist p₁ p₂ := by
rw [dist_comm, dist_left_midpoint]
```

-- snippet 30
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.dist_left_midpoint (L136-L138)
theorem dist_left_midpoint (p₁ p₂ : P) : dist p₁ (midpoint 𝕜 p₁ p₂) = ‖(2 : 𝕜)‖⁻¹ * dist p₁ p₂ := by
rw [midpoint, dist_comm, dist_lineMap_left, invOf_eq_inv, ← norm_inv]
```

-- snippet 31
```lean
-- Mathlib.Analysis.Normed.Affine.AddTorsor.nndist_homothety_self (L118-L121)
theorem nndist_homothety_self (p₁ p₂ : P) (c : 𝕜) :
    nndist (homothety p₁ c p₂) p₂ = ‖1 - c‖₊ * nndist p₁ p₂ :=
NNReal.eq <| dist_homothety_self _ _ _
```
[/INST]

mistral-common:Tekken v15 (Mistral chat template, [INST]/[SYSTEM_PROMPT])


[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.Order.Filter.Map).

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

```lean
theorem map_biInf_eq {ι : Type w} {f : ι → Filter α} {m : α → β} {p : ι → Prop}
    (h : DirectedOn (f ⁻¹'o (· ≥ ·)) { x | p x }) (ne : ∃ i, p i) :
    map m (⨅ (i) (_ : p i), f i) = ⨅ (i) (_ : p i), map m (f i)
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Order.Filter.Map.map_principal (L34-L38)
theorem map_principal {s : Set α} {f : α → β} : map f (𝓟 s) = 𝓟 (Set.image f s) :=
Filter.ext fun _ => image_subset_iff.symm

variable {f : Filter α} {m : α → β} {m' : β → γ} {s : Set α} {t : Set β}
```

-- snippet 2
```lean
-- Mathlib.Order.Filter.Map.eventually_map (L40-L42)
theorem eventually_map {P : β → Prop} : (∀ᶠ b in map m f, P b) ↔ ∀ᶠ a in f, P (m a) :=
Iff.rfl
```

-- snippet 3
```lean
-- Mathlib.Order.Filter.Map.frequently_map (L44-L46)
theorem frequently_map {P : β → Prop} : (∃ᶠ b in map m f, P b) ↔ ∃ᶠ a in f, P (m a) :=
Iff.rfl
```

-- snippet 4
```lean
-- Mathlib.Order.Filter.Map.eventuallyEq_map (L48-L49)
theorem eventuallyEq_map {f₁ f₂ : β → γ} : f₁ =ᶠ[map m f] f₂ ↔ f₁ ∘ m =ᶠ[f] f₂ ∘ m := .rfl
```

-- snippet 5
```lean
-- Mathlib.Order.Filter.Map.eventuallyLE_map (L51-L52)
theorem eventuallyLE_map [LE γ] {f₁ f₂ : β → γ} : f₁ ≤ᶠ[map m f] f₂ ↔ f₁ ∘ m ≤ᶠ[f] f₂ ∘ m := .rfl
```

-- snippet 6
```lean
-- Mathlib.Order.Filter.Map.mem_map (L54-L56)
theorem mem_map : t ∈ map m f ↔ m ⁻¹' t ∈ f :=
Iff.rfl
```

-- snippet 7
```lean
-- Mathlib.Order.Filter.Map.mem_map' (L57-L59)
theorem mem_map' : t ∈ map m f ↔ { x | m x ∈ t } ∈ f :=
Iff.rfl
```

-- snippet 8
```lean
-- Mathlib.Order.Filter.Map.image_mem_map (L60-L66)
theorem image_mem_map (hs : s ∈ f) : m '' s ∈ map m f :=
f.sets_of_superset hs <| subset_preimage_image m s

-- The simpNF linter says that the LHS can be simplified via `Filter.mem_map`.
-- However this is a higher priority lemma.
-- It seems the side condition `hf` is not applied by `simpNF`.
-- https://github.com/leanprover/std4/issues/207
```

-- snippet 9
```lean
-- Mathlib.Order.Filter.Map.image_mem_map_iff (L68-L70)
theorem image_mem_map_iff (hf : Injective m) : m '' s ∈ map m f ↔ s ∈ f :=
⟨fun h => by rwa [← preimage_image_eq s hf], image_mem_map⟩
```

-- snippet 10
```lean
-- Mathlib.Order.Filter.Map.range_mem_map (L71-L74)
theorem range_mem_map : range m ∈ map m f := by
rw [← image_univ]
  exact image_mem_map univ_mem
```

-- snippet 11
```lean
-- Mathlib.Order.Filter.Map.mem_map_iff_exists_image (L75-L78)
theorem mem_map_iff_exists_image : t ∈ map m f ↔ ∃ s ∈ f, m '' s ⊆ t :=
⟨fun ht => ⟨m ⁻¹' t, ht, image_preimage_subset _ _⟩, fun ⟨_, hs, ht⟩ =>
    mem_of_superset (image_mem_map hs) ht⟩
```

-- snippet 12
```lean
-- Mathlib.Order.Filter.Map.map_id (L80-L82)
theorem map_id : Filter.map id f = f :=
filter_eq <| rfl
```

-- snippet 13
```lean
-- Mathlib.Order.Filter.Map.map_id' (L84-L86)
theorem map_id' : Filter.map (fun x => x) f = f :=
map_id
```

-- snippet 14
```lean
-- Mathlib.Order.Filter.Map.map_compose (L88-L90)
theorem map_compose : Filter.map m' ∘ Filter.map m = Filter.map (m' ∘ m) :=
funext fun _ => filter_eq <| rfl
```

-- snippet 15
```lean
-- Mathlib.Order.Filter.Map.map_map (L92-L96)
theorem map_map : Filter.map m' (Filter.map m f) = Filter.map (m' ∘ m) f :=
congr_fun Filter.map_compose f

/-- If functions `m₁` and `m₂` are eventually equal at a filter `f`, then
they map this filter to the same filter. -/
```

-- snippet 16
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.tendsto_ratCast_atBot_iff (L113-L117)
theorem tendsto_ratCast_atBot_iff [Field R] [LinearOrder R] [IsStrictOrderedRing R]
    [Archimedean R] {f : α → ℚ}
    {l : Filter α} : Tendsto (fun n => (f n : R)) l atBot ↔ Tendsto f l atBot := by
rw [← @Rat.comap_cast_atBot R, tendsto_comap_iff]; rfl
```

-- snippet 17
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.map_add_atTop_eq (L161-L164)
theorem map_add_atTop_eq [AddCommGroup α] [PartialOrder α] [IsOrderedAddMonoid α]
    [IsDirectedOrder α] (k : α) : map (fun a => a + k) atTop = atTop :=
map_atTop_eq_of_gc (fun a => a - k) 0 add_left_mono (by simp [le_sub_iff_add_le]) (by simp)
```

-- snippet 18
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.tendsto_intCast_atTop_iff (L70-L74)
theorem tendsto_intCast_atTop_iff [Ring R] [PartialOrder R] [IsStrictOrderedRing R] [Archimedean R]
    {f : α → ℤ}
    {l : Filter α} : Tendsto (fun n => (f n : R)) l atTop ↔ Tendsto f l atTop := by
rw [← @Int.comap_cast_atTop R, tendsto_comap_iff]; rfl
```

-- snippet 19
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.atTop_hasAntitoneBasis_of_archimedean (L128-L132)
theorem atTop_hasAntitoneBasis_of_archimedean [Semiring R] [PartialOrder R] [IsOrderedRing R]
    [Archimedean R] :
    (atTop : Filter R).HasAntitoneBasis fun n : ℕ => Ici n :=
hasAntitoneBasis_atTop.comp_mono Nat.mono_cast tendsto_natCast_atTop_atTop
```

-- snippet 20
```lean
-- Mathlib.Order.Filter.AtTopBot.Basic.hasAntitoneBasis_atTop (L32-L34)
theorem hasAntitoneBasis_atTop [Nonempty α] : (@atTop α _).HasAntitoneBasis Ici :=
.iInf_principal fun _ _ ↦ Ici_subset_Ici.2
```

-- snippet 21
```lean
-- Mathlib.Order.Filter.AtTopBot.Basic.atTop_neBot (L58-L59)
lemma atTop_neBot : NeBot (atTop : Filter α) := atTop_basis.neBot_iff.2 fun _ => nonempty_Ici
```

-- snippet 22
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.Filter (L52-L56)
theorem Filter.Eventually.natCast_atTop [Semiring R] [PartialOrder R] [IsOrderedRing R]
    [Archimedean R] {p : R → Prop}
    (h : ∀ᶠ (x : R) in atTop, p x) : ∀ᶠ (n : ℕ) in atTop, p n :=
tendsto_natCast_atTop_atTop.eventually h
```

-- snippet 23
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.tendsto_intCast_atBot_iff (L75-L79)
theorem tendsto_intCast_atBot_iff [Ring R] [PartialOrder R] [IsStrictOrderedRing R]
    [Archimedean R] {f : α → ℤ}
    {l : Filter α} : Tendsto (fun n => (f n : R)) l atBot ↔ Tendsto f l atBot := by
rw [← @Int.comap_cast_atBot R, tendsto_comap_iff]; rfl
```

-- snippet 24
```lean
-- Mathlib.Order.Filter.AtTopBot.Basic.atTop_basis_Ioi' (L42-L48)
lemma atTop_basis_Ioi' [NoMaxOrder α] (a : α) : atTop.HasBasis (a < ·) Ioi := by
have : Nonempty α := ⟨a⟩
  refine atTop_basis_Ioi.to_hasBasis (fun b _ ↦ ?_) fun b _ ↦ ⟨b, trivial, Subset.rfl⟩
  obtain ⟨c, hac, hbc⟩ := exists_ge_ge a b
  obtain ⟨d, hcd⟩ := exists_gt c
  exact ⟨d, hac.trans_lt hcd, Ioi_subset_Ioi (hbc.trans hcd.le)⟩
```

-- snippet 25
```lean
-- Mathlib.Order.Filter.AtTopBot.Basic.atTop_basis_Ioi (L38-L41)
lemma atTop_basis_Ioi [Nonempty α] [NoMaxOrder α] : (@atTop α _).HasBasis (fun _ => True) Ioi :=
atTop_basis.to_hasBasis (fun a ha => ⟨a, ha, Ioi_subset_Ici_self⟩) fun a ha =>
    (exists_gt a).imp fun _b hb => ⟨ha, Ici_subset_Ioi.2 hb⟩
```

-- snippet 26
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.tendsto_ratCast_atTop_iff (L108-L112)
theorem tendsto_ratCast_atTop_iff [Field R] [LinearOrder R] [IsStrictOrderedRing R] [Archimedean R]
    {f : α → ℚ}
    {l : Filter α} : Tendsto (fun n => (f n : R)) l atTop ↔ Tendsto f l atTop := by
rw [← @Rat.comap_cast_atTop R, tendsto_comap_iff]; rfl
```

-- snippet 27
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.PNat (L40-L43)
theorem PNat.tendsto_comp_val_iff {β : Type*} {f : ℕ → β} {l : Filter β} :
    Tendsto (fun x : ℕ+ => f x) atTop l ↔ Tendsto f atTop l := by
exact tendsto_comp_val_Ioi_atTop
```

-- snippet 28
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.atBot_hasCountableBasis_of_archimedean (L138-L146)
theorem atBot_hasCountableBasis_of_archimedean [Ring R] [PartialOrder R] [IsOrderedRing R]
    [Archimedean R] :
    (atBot : Filter R).HasCountableBasis (fun _ : ℤ => True) fun m => Iic m where
  countable := to_countable _
toHasBasis :=
    atBot_basis.to_hasBasis
      (fun x _ => let ⟨m, hm⟩ := exists_int_le x; ⟨m, trivial, Iic_subset_Iic.2 hm⟩)
      fun m _ => ⟨m, trivial, Subset.rfl⟩
```

-- snippet 29
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.tendsto_natCast_atTop_iff (L35-L39)
theorem tendsto_natCast_atTop_iff [Semiring R] [PartialOrder R] [IsStrictOrderedRing R]
    [Archimedean R] {f : α → ℕ}
    {l : Filter α} : Tendsto (fun n => (f n : R)) l atTop ↔ Tendsto f l atTop :=
tendsto_atTop_embedding (fun _ _ => Nat.cast_le) exists_nat_ge
```

-- snippet 30
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.atTop_hasCountableBasis_of_archimedean (L133-L137)
theorem atTop_hasCountableBasis_of_archimedean [Semiring R] [PartialOrder R] [IsOrderedRing R]
    [Archimedean R] :
    (atTop : Filter R).HasCountableBasis (fun _ : ℕ => True) fun n => Ici n :=
⟨atTop_hasAntitoneBasis_of_archimedean.1, to_countable _⟩
```

-- snippet 31
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.tendsto_natCast_atTop_atTop (L44-L48)
theorem tendsto_natCast_atTop_atTop [Semiring R] [PartialOrder R] [IsOrderedRing R]
    [Archimedean R] :
    Tendsto ((↑) : ℕ → R) atTop atTop :=
Nat.mono_cast.tendsto_atTop_atTop exists_nat_ge
```

-- snippet 32
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.Nat (L31-L34)
theorem Nat.comap_cast_atTop [Semiring R] [PartialOrder R] [IsStrictOrderedRing R] [Archimedean R] :
    comap ((↑) : ℕ → R) atTop = atTop :=
comap_embedding_atTop (fun _ _ => Nat.cast_le) exists_nat_ge
```

-- snippet 33
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.tendsto_PNat_val_atTop_atTop (L49-L51)
lemma tendsto_PNat_val_atTop_atTop : Tendsto PNat.val atTop atTop :=
tendsto_atTop_atTop_of_monotone (fun _ _ h ↦ h) fun a ↦ ⟨Nat.succPNat a, Nat.le_succ a⟩
```

-- snippet 34
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.Int (L64-L69)
theorem Int.comap_cast_atBot [Ring R] [PartialOrder R] [IsStrictOrderedRing R] [Archimedean R] :
    comap ((↑) : ℤ → R) atBot = atBot :=
comap_embedding_atBot (fun _ _ => Int.cast_le) fun r =>
    let ⟨n, hn⟩ := exists_nat_ge (-r)
    ⟨-n, by simpa [neg_le] using hn⟩
```

-- snippet 35
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.tendsto_intCast_atTop_atTop (L80-L84)
theorem tendsto_intCast_atTop_atTop [Ring R] [PartialOrder R] [IsStrictOrderedRing R]
    [Archimedean R] :
    Tendsto ((↑) : ℤ → R) atTop atTop :=
tendsto_intCast_atTop_iff.2 tendsto_id
```

-- snippet 36
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.map_sub_atTop_eq (L165-L177)
theorem map_sub_atTop_eq [AddCommGroup α] [PartialOrder α] [IsOrderedAddMonoid α]
    [IsDirectedOrder α] (k : α) : map (fun a => a - k) atTop = atTop := by
simp_rw [sub_eq_add_neg]
  apply map_add_atTop_eq

section LinearOrderedSemiring

variable [Semiring R] [LinearOrder R] [IsStrictOrderedRing R] [Archimedean R]

/-- If a function tends to infinity along a filter, then this function multiplied by a positive
constant (on the left) also tends to infinity. The archimedean assumption is convenient to get a
statement that works on `ℕ`, `ℤ` and `ℝ`, although not necessary (a version in ordered fields is
given in `Filter.Tendsto.const_mul_atTop`). -/
```

-- snippet 37
```lean
-- Mathlib.Order.Filter.AtTopBot.Basic.atTop_basis (L35-L37)
theorem atTop_basis [Nonempty α] : (@atTop α _).HasBasis (fun _ => True) Ici :=
hasAntitoneBasis_atTop.1
```

-- snippet 38
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.Rat (L96-L100)
theorem Rat.comap_cast_atTop [Field R] [LinearOrder R] [IsStrictOrderedRing R] [Archimedean R] :
    comap ((↑) : ℚ → R) atTop = atTop :=
comap_embedding_atTop (fun _ _ => Rat.cast_le) fun r =>
    let ⟨n, hn⟩ := exists_nat_ge r; ⟨n, by simpa⟩
```

-- snippet 39
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.Tendsto (L178-L195)
theorem Tendsto.const_mul_atTop' (hr : 0 < r) (hf : Tendsto f l atTop) :
    Tendsto (fun x => r * f x) l atTop := by
refine tendsto_atTop.2 fun b => ?_
  obtain ⟨n : ℕ, hn : 1 ≤ n • r⟩ := Archimedean.arch 1 hr
  rw [nsmul_eq_mul'] at hn
  filter_upwards [tendsto_atTop.1 hf (n * max b 0)] with x hx
  calc
    b ≤ 1 * max b 0 := by
    { rw [one_mul]
      exact le_max_left _ _ }
    _ ≤ r * n * max b 0 := by gcongr
    _ = r * (n * max b 0) := by rw [mul_assoc]
    _ ≤ r * f x := by gcongr

/-- If a function tends to infinity along a filter, then this function multiplied by a positive
constant (on the right) also tends to infinity. The archimedean assumption is convenient to get a
statement that works on `ℕ`, `ℤ` and `ℝ`, although not necessary (a version in ordered fields is
given in `Filter.Tendsto.atTop_mul_const`). -/
```

-- snippet 40
```lean
-- Mathlib.Order.Filter.AtTopBot.Basic.atTop_basis' (L49-L56)
theorem atTop_basis' (a : α) : atTop.HasBasis (a ≤ ·) Ici := by
have : Nonempty α := ⟨a⟩
  refine atTop_basis.to_hasBasis (fun b _ ↦ ?_) fun b _ ↦ ⟨b, trivial, Subset.rfl⟩
  obtain ⟨c, hac, hbc⟩ := exists_ge_ge a b
  exact ⟨c, hac, Ici_subset_Ici.2 hbc⟩

variable [Nonempty α]
```

<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.Order.Filter.Map).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]Prove the following theorem. The retrieved context below may help.

```lean
theorem map_biInf_eq {ι : Type w} {f : ι → Filter α} {m : α → β} {p : ι → Prop}
    (h : DirectedOn (f ⁻¹'o (· ≥ ·)) { x | p x }) (ne : ∃ i, p i) :
    map m (⨅ (i) (_ : p i), f i) = ⨅ (i) (_ : p i), map m (f i)
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Order.Filter.Map.map_principal (L34-L38)
theorem map_principal {s : Set α} {f : α → β} : map f (𝓟 s) = 𝓟 (Set.image f s) :=
Filter.ext fun _ => image_subset_iff.symm

variable {f : Filter α} {m : α → β} {m' : β → γ} {s : Set α} {t : Set β}
```

-- snippet 2
```lean
-- Mathlib.Order.Filter.Map.eventually_map (L40-L42)
theorem eventually_map {P : β → Prop} : (∀ᶠ b in map m f, P b) ↔ ∀ᶠ a in f, P (m a) :=
Iff.rfl
```

-- snippet 3
```lean
-- Mathlib.Order.Filter.Map.frequently_map (L44-L46)
theorem frequently_map {P : β → Prop} : (∃ᶠ b in map m f, P b) ↔ ∃ᶠ a in f, P (m a) :=
Iff.rfl
```

-- snippet 4
```lean
-- Mathlib.Order.Filter.Map.eventuallyEq_map (L48-L49)
theorem eventuallyEq_map {f₁ f₂ : β → γ} : f₁ =ᶠ[map m f] f₂ ↔ f₁ ∘ m =ᶠ[f] f₂ ∘ m := .rfl
```

-- snippet 5
```lean
-- Mathlib.Order.Filter.Map.eventuallyLE_map (L51-L52)
theorem eventuallyLE_map [LE γ] {f₁ f₂ : β → γ} : f₁ ≤ᶠ[map m f] f₂ ↔ f₁ ∘ m ≤ᶠ[f] f₂ ∘ m := .rfl
```

-- snippet 6
```lean
-- Mathlib.Order.Filter.Map.mem_map (L54-L56)
theorem mem_map : t ∈ map m f ↔ m ⁻¹' t ∈ f :=
Iff.rfl
```

-- snippet 7
```lean
-- Mathlib.Order.Filter.Map.mem_map' (L57-L59)
theorem mem_map' : t ∈ map m f ↔ { x | m x ∈ t } ∈ f :=
Iff.rfl
```

-- snippet 8
```lean
-- Mathlib.Order.Filter.Map.image_mem_map (L60-L66)
theorem image_mem_map (hs : s ∈ f) : m '' s ∈ map m f :=
f.sets_of_superset hs <| subset_preimage_image m s

-- The simpNF linter says that the LHS can be simplified via `Filter.mem_map`.
-- However this is a higher priority lemma.
-- It seems the side condition `hf` is not applied by `simpNF`.
-- https://github.com/leanprover/std4/issues/207
```

-- snippet 9
```lean
-- Mathlib.Order.Filter.Map.image_mem_map_iff (L68-L70)
theorem image_mem_map_iff (hf : Injective m) : m '' s ∈ map m f ↔ s ∈ f :=
⟨fun h => by rwa [← preimage_image_eq s hf], image_mem_map⟩
```

-- snippet 10
```lean
-- Mathlib.Order.Filter.Map.range_mem_map (L71-L74)
theorem range_mem_map : range m ∈ map m f := by
rw [← image_univ]
  exact image_mem_map univ_mem
```

-- snippet 11
```lean
-- Mathlib.Order.Filter.Map.mem_map_iff_exists_image (L75-L78)
theorem mem_map_iff_exists_image : t ∈ map m f ↔ ∃ s ∈ f, m '' s ⊆ t :=
⟨fun ht => ⟨m ⁻¹' t, ht, image_preimage_subset _ _⟩, fun ⟨_, hs, ht⟩ =>
    mem_of_superset (image_mem_map hs) ht⟩
```

-- snippet 12
```lean
-- Mathlib.Order.Filter.Map.map_id (L80-L82)
theorem map_id : Filter.map id f = f :=
filter_eq <| rfl
```

-- snippet 13
```lean
-- Mathlib.Order.Filter.Map.map_id' (L84-L86)
theorem map_id' : Filter.map (fun x => x) f = f :=
map_id
```

-- snippet 14
```lean
-- Mathlib.Order.Filter.Map.map_compose (L88-L90)
theorem map_compose : Filter.map m' ∘ Filter.map m = Filter.map (m' ∘ m) :=
funext fun _ => filter_eq <| rfl
```

-- snippet 15
```lean
-- Mathlib.Order.Filter.Map.map_map (L92-L96)
theorem map_map : Filter.map m' (Filter.map m f) = Filter.map (m' ∘ m) f :=
congr_fun Filter.map_compose f

/-- If functions `m₁` and `m₂` are eventually equal at a filter `f`, then
they map this filter to the same filter. -/
```

-- snippet 16
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.tendsto_ratCast_atBot_iff (L113-L117)
theorem tendsto_ratCast_atBot_iff [Field R] [LinearOrder R] [IsStrictOrderedRing R]
    [Archimedean R] {f : α → ℚ}
    {l : Filter α} : Tendsto (fun n => (f n : R)) l atBot ↔ Tendsto f l atBot := by
rw [← @Rat.comap_cast_atBot R, tendsto_comap_iff]; rfl
```

-- snippet 17
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.map_add_atTop_eq (L161-L164)
theorem map_add_atTop_eq [AddCommGroup α] [PartialOrder α] [IsOrderedAddMonoid α]
    [IsDirectedOrder α] (k : α) : map (fun a => a + k) atTop = atTop :=
map_atTop_eq_of_gc (fun a => a - k) 0 add_left_mono (by simp [le_sub_iff_add_le]) (by simp)
```

-- snippet 18
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.tendsto_intCast_atTop_iff (L70-L74)
theorem tendsto_intCast_atTop_iff [Ring R] [PartialOrder R] [IsStrictOrderedRing R] [Archimedean R]
    {f : α → ℤ}
    {l : Filter α} : Tendsto (fun n => (f n : R)) l atTop ↔ Tendsto f l atTop := by
rw [← @Int.comap_cast_atTop R, tendsto_comap_iff]; rfl
```

-- snippet 19
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.atTop_hasAntitoneBasis_of_archimedean (L128-L132)
theorem atTop_hasAntitoneBasis_of_archimedean [Semiring R] [PartialOrder R] [IsOrderedRing R]
    [Archimedean R] :
    (atTop : Filter R).HasAntitoneBasis fun n : ℕ => Ici n :=
hasAntitoneBasis_atTop.comp_mono Nat.mono_cast tendsto_natCast_atTop_atTop
```

-- snippet 20
```lean
-- Mathlib.Order.Filter.AtTopBot.Basic.hasAntitoneBasis_atTop (L32-L34)
theorem hasAntitoneBasis_atTop [Nonempty α] : (@atTop α _).HasAntitoneBasis Ici :=
.iInf_principal fun _ _ ↦ Ici_subset_Ici.2
```

-- snippet 21
```lean
-- Mathlib.Order.Filter.AtTopBot.Basic.atTop_neBot (L58-L59)
lemma atTop_neBot : NeBot (atTop : Filter α) := atTop_basis.neBot_iff.2 fun _ => nonempty_Ici
```

-- snippet 22
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.Filter (L52-L56)
theorem Filter.Eventually.natCast_atTop [Semiring R] [PartialOrder R] [IsOrderedRing R]
    [Archimedean R] {p : R → Prop}
    (h : ∀ᶠ (x : R) in atTop, p x) : ∀ᶠ (n : ℕ) in atTop, p n :=
tendsto_natCast_atTop_atTop.eventually h
```

-- snippet 23
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.tendsto_intCast_atBot_iff (L75-L79)
theorem tendsto_intCast_atBot_iff [Ring R] [PartialOrder R] [IsStrictOrderedRing R]
    [Archimedean R] {f : α → ℤ}
    {l : Filter α} : Tendsto (fun n => (f n : R)) l atBot ↔ Tendsto f l atBot := by
rw [← @Int.comap_cast_atBot R, tendsto_comap_iff]; rfl
```

-- snippet 24
```lean
-- Mathlib.Order.Filter.AtTopBot.Basic.atTop_basis_Ioi' (L42-L48)
lemma atTop_basis_Ioi' [NoMaxOrder α] (a : α) : atTop.HasBasis (a < ·) Ioi := by
have : Nonempty α := ⟨a⟩
  refine atTop_basis_Ioi.to_hasBasis (fun b _ ↦ ?_) fun b _ ↦ ⟨b, trivial, Subset.rfl⟩
  obtain ⟨c, hac, hbc⟩ := exists_ge_ge a b
  obtain ⟨d, hcd⟩ := exists_gt c
  exact ⟨d, hac.trans_lt hcd, Ioi_subset_Ioi (hbc.trans hcd.le)⟩
```

-- snippet 25
```lean
-- Mathlib.Order.Filter.AtTopBot.Basic.atTop_basis_Ioi (L38-L41)
lemma atTop_basis_Ioi [Nonempty α] [NoMaxOrder α] : (@atTop α _).HasBasis (fun _ => True) Ioi :=
atTop_basis.to_hasBasis (fun a ha => ⟨a, ha, Ioi_subset_Ici_self⟩) fun a ha =>
    (exists_gt a).imp fun _b hb => ⟨ha, Ici_subset_Ioi.2 hb⟩
```

-- snippet 26
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.tendsto_ratCast_atTop_iff (L108-L112)
theorem tendsto_ratCast_atTop_iff [Field R] [LinearOrder R] [IsStrictOrderedRing R] [Archimedean R]
    {f : α → ℚ}
    {l : Filter α} : Tendsto (fun n => (f n : R)) l atTop ↔ Tendsto f l atTop := by
rw [← @Rat.comap_cast_atTop R, tendsto_comap_iff]; rfl
```

-- snippet 27
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.PNat (L40-L43)
theorem PNat.tendsto_comp_val_iff {β : Type*} {f : ℕ → β} {l : Filter β} :
    Tendsto (fun x : ℕ+ => f x) atTop l ↔ Tendsto f atTop l := by
exact tendsto_comp_val_Ioi_atTop
```

-- snippet 28
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.atBot_hasCountableBasis_of_archimedean (L138-L146)
theorem atBot_hasCountableBasis_of_archimedean [Ring R] [PartialOrder R] [IsOrderedRing R]
    [Archimedean R] :
    (atBot : Filter R).HasCountableBasis (fun _ : ℤ => True) fun m => Iic m where
  countable := to_countable _
toHasBasis :=
    atBot_basis.to_hasBasis
      (fun x _ => let ⟨m, hm⟩ := exists_int_le x; ⟨m, trivial, Iic_subset_Iic.2 hm⟩)
      fun m _ => ⟨m, trivial, Subset.rfl⟩
```

-- snippet 29
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.tendsto_natCast_atTop_iff (L35-L39)
theorem tendsto_natCast_atTop_iff [Semiring R] [PartialOrder R] [IsStrictOrderedRing R]
    [Archimedean R] {f : α → ℕ}
    {l : Filter α} : Tendsto (fun n => (f n : R)) l atTop ↔ Tendsto f l atTop :=
tendsto_atTop_embedding (fun _ _ => Nat.cast_le) exists_nat_ge
```

-- snippet 30
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.atTop_hasCountableBasis_of_archimedean (L133-L137)
theorem atTop_hasCountableBasis_of_archimedean [Semiring R] [PartialOrder R] [IsOrderedRing R]
    [Archimedean R] :
    (atTop : Filter R).HasCountableBasis (fun _ : ℕ => True) fun n => Ici n :=
⟨atTop_hasAntitoneBasis_of_archimedean.1, to_countable _⟩
```

-- snippet 31
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.tendsto_natCast_atTop_atTop (L44-L48)
theorem tendsto_natCast_atTop_atTop [Semiring R] [PartialOrder R] [IsOrderedRing R]
    [Archimedean R] :
    Tendsto ((↑) : ℕ → R) atTop atTop :=
Nat.mono_cast.tendsto_atTop_atTop exists_nat_ge
```

-- snippet 32
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.Nat (L31-L34)
theorem Nat.comap_cast_atTop [Semiring R] [PartialOrder R] [IsStrictOrderedRing R] [Archimedean R] :
    comap ((↑) : ℕ → R) atTop = atTop :=
comap_embedding_atTop (fun _ _ => Nat.cast_le) exists_nat_ge
```

-- snippet 33
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.tendsto_PNat_val_atTop_atTop (L49-L51)
lemma tendsto_PNat_val_atTop_atTop : Tendsto PNat.val atTop atTop :=
tendsto_atTop_atTop_of_monotone (fun _ _ h ↦ h) fun a ↦ ⟨Nat.succPNat a, Nat.le_succ a⟩
```

-- snippet 34
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.Int (L64-L69)
theorem Int.comap_cast_atBot [Ring R] [PartialOrder R] [IsStrictOrderedRing R] [Archimedean R] :
    comap ((↑) : ℤ → R) atBot = atBot :=
comap_embedding_atBot (fun _ _ => Int.cast_le) fun r =>
    let ⟨n, hn⟩ := exists_nat_ge (-r)
    ⟨-n, by simpa [neg_le] using hn⟩
```

-- snippet 35
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.tendsto_intCast_atTop_atTop (L80-L84)
theorem tendsto_intCast_atTop_atTop [Ring R] [PartialOrder R] [IsStrictOrderedRing R]
    [Archimedean R] :
    Tendsto ((↑) : ℤ → R) atTop atTop :=
tendsto_intCast_atTop_iff.2 tendsto_id
```

-- snippet 36
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.map_sub_atTop_eq (L165-L177)
theorem map_sub_atTop_eq [AddCommGroup α] [PartialOrder α] [IsOrderedAddMonoid α]
    [IsDirectedOrder α] (k : α) : map (fun a => a - k) atTop = atTop := by
simp_rw [sub_eq_add_neg]
  apply map_add_atTop_eq

section LinearOrderedSemiring

variable [Semiring R] [LinearOrder R] [IsStrictOrderedRing R] [Archimedean R]

/-- If a function tends to infinity along a filter, then this function multiplied by a positive
constant (on the left) also tends to infinity. The archimedean assumption is convenient to get a
statement that works on `ℕ`, `ℤ` and `ℝ`, although not necessary (a version in ordered fields is
given in `Filter.Tendsto.const_mul_atTop`). -/
```

-- snippet 37
```lean
-- Mathlib.Order.Filter.AtTopBot.Basic.atTop_basis (L35-L37)
theorem atTop_basis [Nonempty α] : (@atTop α _).HasBasis (fun _ => True) Ici :=
hasAntitoneBasis_atTop.1
```

-- snippet 38
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.Rat (L96-L100)
theorem Rat.comap_cast_atTop [Field R] [LinearOrder R] [IsStrictOrderedRing R] [Archimedean R] :
    comap ((↑) : ℚ → R) atTop = atTop :=
comap_embedding_atTop (fun _ _ => Rat.cast_le) fun r =>
    let ⟨n, hn⟩ := exists_nat_ge r; ⟨n, by simpa⟩
```

-- snippet 39
```lean
-- Mathlib.Order.Filter.AtTopBot.Archimedean.Tendsto (L178-L195)
theorem Tendsto.const_mul_atTop' (hr : 0 < r) (hf : Tendsto f l atTop) :
    Tendsto (fun x => r * f x) l atTop := by
refine tendsto_atTop.2 fun b => ?_
  obtain ⟨n : ℕ, hn : 1 ≤ n • r⟩ := Archimedean.arch 1 hr
  rw [nsmul_eq_mul'] at hn
  filter_upwards [tendsto_atTop.1 hf (n * max b 0)] with x hx
  calc
    b ≤ 1 * max b 0 := by
    { rw [one_mul]
      exact le_max_left _ _ }
    _ ≤ r * n * max b 0 := by gcongr
    _ = r * (n * max b 0) := by rw [mul_assoc]
    _ ≤ r * f x := by gcongr

/-- If a function tends to infinity along a filter, then this function multiplied by a positive
constant (on the right) also tends to infinity. The archimedean assumption is convenient to get a
statement that works on `ℕ`, `ℤ` and `ℝ`, although not necessary (a version in ordered fields is
given in `Filter.Tendsto.atTop_mul_const`). -/
```

-- snippet 40
```lean
-- Mathlib.Order.Filter.AtTopBot.Basic.atTop_basis' (L49-L56)
theorem atTop_basis' (a : α) : atTop.HasBasis (a ≤ ·) Ici := by
have : Nonempty α := ⟨a⟩
  refine atTop_basis.to_hasBasis (fun b _ ↦ ?_) fun b _ ↦ ⟨b, trivial, Subset.rfl⟩
  obtain ⟨c, hac, hbc⟩ := exists_ge_ge a b
  exact ⟨c, hac, Ici_subset_Ici.2 hbc⟩

variable [Nonempty α]
```
[/INST]


[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.Combinatorics.SimpleGraph.Walks.Operations).

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

```lean
lemma drop_add_eq (p : G.Walk u v) (n m : ℕ) :
    p.drop (n + m) = ((p.drop n).drop m).copy (drop_getVert ..) rfl
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.copy_rfl_rfl (L52-L53)
theorem copy_rfl_rfl {u v} (p : G.Walk u v) : p.copy rfl rfl = p := rfl
```

-- snippet 2
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.copy_copy (L55-L60)
theorem copy_copy {u v u' v' u'' v''} (p : G.Walk u v)
    (hu : u = u') (hv : v = v') (hu' : u' = u'') (hv' : v' = v'') :
    (p.copy hu hv).copy hu' hv' = p.copy (hu.trans hu') (hv.trans hv') := by
subst_vars
  rfl
```

-- snippet 3
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.copy_nil (L62-L65)
theorem copy_nil {u u'} (hu : u = u') : (Walk.nil : G.Walk u u).copy hu hu = nil := by
subst_vars
  rfl
```

-- snippet 4
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.copy_cons (L66-L70)
theorem copy_cons {u v w u' w'} (h : G.Adj u v) (p : G.Walk v w) (hu : u = u') (hw : w = w') :
    (Walk.cons h p).copy hu hw = Walk.cons (hu ▸ h) (p.copy rfl hw) := by
subst_vars
  rfl
```

-- snippet 5
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.cons_copy (L72-L77)
theorem cons_copy {u v w v' w'} (h : G.Adj u v) (p : G.Walk v' w') (hv : v' = v) (hw : w' = w) :
    cons h (p.copy hv hw) = (Walk.cons (hv ▸ h) p).copy rfl hw := by
subst_vars
  rfl

/-- The concatenation of two compatible walks. -/
```

-- snippet 6
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.append (L79-L84)
def append {u v w : V} : G.Walk u v → G.Walk v w → G.Walk u w
  | nil, q => q
  | cons h p, q => cons h (p.append q)

/-- The reversed version of `SimpleGraph.Walk.cons`, concatenating an edge to
the end of a walk. -/
```

-- snippet 7
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.concat (L85-L86)
def concat {u v w : V} (p : G.Walk u v) (h : G.Adj v w) : G.Walk u w := p.append (cons h nil)
```

-- snippet 8
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.concat_eq_append (L87-L95)
theorem concat_eq_append {u v w : V} (p : G.Walk u v) (h : G.Adj v w) :
    p.concat h = p.append (cons h nil) := rfl
/-- The concatenation of the reverse of the first walk with the second walk. -/
protected def reverseAux {u v w : V} : G.Walk u v → G.Walk u w → G.Walk v w
  | nil, q => q
  | cons h p, q => Walk.reverseAux p (cons (G.symm h) q)

/-- The walk in reverse. -/
```

-- snippet 9
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.reverse (L97-L98)
def reverse {u v : V} (w : G.Walk u v) : G.Walk v u := w.reverseAux nil
```

-- snippet 10
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.cons_append (L100-L102)
theorem cons_append {u v w x : V} (h : G.Adj u v) (p : G.Walk v w) (q : G.Walk w x) :
    (cons h p).append q = cons h (p.append q) := rfl
```

-- snippet 11
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.cons_nil_append (L104-L106)
theorem cons_nil_append {u v w : V} (h : G.Adj u v) (p : G.Walk v w) :
    (cons h nil).append p = cons h p := rfl
```

-- snippet 12
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.nil_append (L108-L110)
theorem nil_append {u v : V} (p : G.Walk u v) : nil.append p = p :=
rfl
```

-- snippet 13
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.append_nil (L112-L114)
theorem append_nil {u v : V} (p : G.Walk u v) : p.append nil = p := by
induction p <;> simp [*]
```

-- snippet 14
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.append_assoc (L115-L118)
theorem append_assoc {u v w x : V} (p : G.Walk u v) (q : G.Walk v w) (r : G.Walk w x) :
    p.append (q.append r) = (p.append q).append r := by
induction p <;> simp [*]
```

-- snippet 15
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.append_copy_copy (L120-L125)
theorem append_copy_copy {u v w u' v' w'} (p : G.Walk u v) (q : G.Walk v w)
    (hu : u = u') (hv : v = v') (hw : w = w') :
    (p.copy hu hv).append (q.copy hv hw) = (p.append q).copy hu hw := by
subst_vars
  rfl
```

-- snippet 16
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isTree_iff_minimal_connected (L360-L368)
lemma isTree_iff_minimal_connected : IsTree G ↔ Minimal Connected G := by
refine ⟨fun htree ↦ ⟨htree.connected, fun G' h' hle u v hadj ↦ ?_⟩, isTree_of_minimal_connected⟩
  have ⟨p, hp⟩ := h'.exists_isPath u v
  have := congrArg Walk.edges <| congrArg Subtype.val <|
    htree.isAcyclic.path_unique ⟨p.mapLe hle, hp.mapLe hle⟩ <| Path.singleton hadj
  simp only [edges_map, Hom.coe_ofLE, Sym2.map_id, List.map_id_fun, id_eq] at this
  simp [this, p.adj_of_mem_edges]

/-- Connecting two unreachable vertices by an edge preserves acyclicity. -/
```

-- snippet 17
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_iff_forall_adj_isBridge (L167-L180)
theorem isAcyclic_iff_forall_adj_isBridge :
    G.IsAcyclic ↔ ∀ ⦃v w : V⦄, G.Adj v w → G.IsBridge s(v, w) := by
simp_rw [isBridge_iff_adj_and_forall_cycle_notMem]
  constructor
  · intro ha v w hvw
    apply And.intro hvw
    intro u p hp
    cases ha p hp
  · rintro hb v (_ | ⟨ha, p⟩) hp
    · exact hp.not_of_nil
    · apply (hb ha).2 _ hp
      rw [Walk.edges_cons]
      apply List.mem_cons_self
```

-- snippet 18
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.IsAcyclic (L55-L57)
def IsAcyclic : Prop := ∀ ⦃v : V⦄ (c : G.Walk v v), ¬c.IsCycle
/-- A *tree* is a connected acyclic graph. -/
```

-- snippet 19
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_iff_pairwise_not_isEdgeReachable_two (L650-L658)
lemma isAcyclic_iff_pairwise_not_isEdgeReachable_two :
    G.IsAcyclic ↔ Pairwise (¬G.IsEdgeReachable 2 · ·) := by
refine ⟨fun h _ _ hne he ↦ ?_, fun h ↦ ?_⟩
  · obtain ⟨w, hw⟩ := exists_isCycle_of_two_le_isEdgeReachable hne le_rfl he
    exact h w hw
  · refine isAcyclic_iff_forall_adj_isBridge.mpr fun _ _ hadj ↦ ?_
    exact isBridge_iff_adj_and_not_isEdgeConnected_two.mpr ⟨hadj, h hadj.ne⟩

end SimpleGraph
```

-- snippet 20
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isTree_iff_connected_and_card (L486-L499)
lemma isTree_iff_connected_and_card [Finite V] :
    G.IsTree ↔ G.Connected ∧ Nat.card G.edgeSet + 1 = Nat.card V := by
have := Fintype.ofFinite V
  classical
  refine ⟨fun h ↦ ⟨h.connected, by simpa [edgeFinset] using h.card_edgeFinset⟩,
    fun ⟨h₁, h₂⟩ ↦ ⟨h₁, ?_⟩⟩
  simp_rw [isAcyclic_iff_forall_adj_isBridge]
  refine fun x y h ↦ by_contra fun hbr ↦
    (h₁.connected_delete_edge_of_not_isBridge hbr).card_vert_le_card_edgeSet_add_one.not_gt ?_
  rw [Nat.card_eq_fintype_card, ← edgeFinset_card, ← h₂, Nat.card_eq_fintype_card,
    ← edgeFinset_card, add_lt_add_iff_right]
  exact Finset.card_lt_card <| by simpa [deleteEdges, edgeFinset]

/-- The minimum degree of all vertices in a nontrivial tree is one. -/
```

-- snippet 21
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_sSup_of_isAcyclic_directedOn (L118-L126)
lemma isAcyclic_sSup_of_isAcyclic_directedOn (Hs : Set <| SimpleGraph V)
    (h_acyc : ∀ H ∈ Hs, H.IsAcyclic) (h_dir : DirectedOn (· ≤ ·) Hs) : IsAcyclic (sSup Hs) := by
rcases Hs.eq_empty_or_nonempty with rfl | hnemp
  · simp
  · intro u p hp
    obtain ⟨H, hH, hpH⟩ := p.exists_mem_contains_edges_of_directed Hs hnemp h_dir
    exact h_acyc H hH (p.transfer H hpH) <| Walk.IsCycle.transfer hp hpH

/-- Every acyclic subgraph `H ≤ G` is contained in a maximal such subgraph. -/
```

-- snippet 22
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.reachable_eq_of_maximal_isAcyclic (L397-L412)
lemma reachable_eq_of_maximal_isAcyclic (F : SimpleGraph V)
    (h : Maximal (fun H ↦ H ≤ G ∧ H.IsAcyclic) F) : F.Reachable = G.Reachable := by
ext u v
  refine ⟨.mono h.prop.left, fun ⟨p⟩ ↦ ?_⟩
  by_contra
  let s : F.ConnectedComponent := .mk _ u
  have : v ∉ s := this ∘ s.reachable_of_mem_supp rfl
  have : ∃ d ∈ p.darts, d.fst ∈ s ∧ d.snd ∉ s := p.exists_boundary_dart s rfl this
  rcases this with ⟨⟨⟨u', v'⟩, huv⟩, _, hu, hv⟩
  have : ¬F.Reachable v' u' := mt ConnectedComponent.sound <| s.mem_supp_iff u' |>.mp hu ▸ hv
  suffices F ⊔ fromEdgeSet {s(v', u')} ≤ F by
    grind [Adj.reachable, sup_le_iff, le_iff_adj, fromEdgeSet_adj]
  refine h.le_of_ge ⟨?_, h.prop.right.isAcyclic_sup_fromEdgeSet_of_not_reachable this⟩ le_sup_left
  grind [Maximal, sup_le, le_iff_adj, fromEdgeSet_adj, huv.symm]

/-- A subgraph is maximal acyclic iff its reachability relation agrees with the larger graph. -/
```

-- snippet 23
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.Iso (L80-L83)
lemma Iso.isAcyclic_iff (f : G ≃g G') : G.IsAcyclic ↔ G'.IsAcyclic :=
⟨fun h ↦ h.embedding f.symm, fun h ↦ h.embedding f⟩

/-- Isomorphic graphs are trees together. -/
```

-- snippet 24
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_iff_forall_edge_isBridge (L181-L184)
theorem isAcyclic_iff_forall_edge_isBridge :
    G.IsAcyclic ↔ ∀ ⦃e⦄, e ∈ (G.edgeSet) → G.IsBridge e := by
simp [isAcyclic_iff_forall_adj_isBridge, Sym2.forall]
```

-- snippet 25
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.IsTree (L154-L156)
lemma IsTree.of_subsingleton [Nonempty V] [Subsingleton V] {G : SimpleGraph V} : G.IsTree :=
⟨.of_subsingleton, .of_subsingleton⟩
```

-- snippet 26
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.exists_isAcyclic_reachable_eq_le_of_le_of_isAcyclic (L450-L456)
theorem exists_isAcyclic_reachable_eq_le_of_le_of_isAcyclic {H : SimpleGraph V} (hH_le : H ≤ G)
    (hH_isAcyclic : H.IsAcyclic) :
    ∃ F : SimpleGraph V, H ≤ F ∧ F ≤ G ∧ F.IsAcyclic ∧ F.Reachable = G.Reachable := by
obtain ⟨F, hF⟩ := G.exists_maximal_isAcyclic_of_le_isAcyclic hH_le hH_isAcyclic
  grind [maximal_isAcyclic_iff_reachable_eq, Maximal]

/-- Every graph has a spanning forest. -/
```

-- snippet 27
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.maximal_isAcyclic_iff_reachable_eq (L413-L427)
theorem maximal_isAcyclic_iff_reachable_eq {F : SimpleGraph V} (hle : F ≤ G) (hF : F.IsAcyclic) :
    Maximal (fun F ↦ F ≤ G ∧ F.IsAcyclic) F ↔ F.Reachable = G.Reachable := by
refine ⟨reachable_eq_of_maximal_isAcyclic F, fun h ↦ ?_⟩
  by_contra
  have ⟨H, hFH, hHG, hH⟩ := exists_gt_of_not_maximal ⟨hle, hF⟩ this
  have ⟨e, heH, heF⟩ := Set.exists_of_ssubset <| edgeSet_strict_mono hFH
  have h_bridge : (F ⊔ fromEdgeSet {e}).IsBridge e := by
    refine isAcyclic_iff_forall_edge_isBridge.mp ?_ <| by simp [H.not_isDiag_of_mem_edgeSet heH]
    exact hH.anti <| sup_le_iff.mpr ⟨hFH.le, H.fromEdgeSet_le.mpr <| by grind⟩
  have : (F ⊔ fromEdgeSet {e}) \ fromEdgeSet {e} = F := by simpa using heF
  cases e
  rw [isBridge_iff, this, h] at h_bridge
  exact h_bridge.right <| hHG heH |>.reachable

/-- A subgraph of a connected graph is maximal acyclic iff it is a tree. -/
```

-- snippet 28
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isTree_of_minimal_connected (L353-L359)
lemma isTree_of_minimal_connected (h : Minimal Connected G) : IsTree G := by
rw [isTree_iff, and_iff_right h.prop, isAcyclic_iff_forall_adj_isBridge]
  exact fun _ _ _ ↦ by_contra fun hbr ↦ h.not_prop_of_lt
    (by simpa [deleteEdges, ← edgeSet_ssubset_edgeSet])
    <| h.prop.connected_delete_edge_of_not_isBridge hbr

set_option backward.isDefEq.respectTransparency false in
```

-- snippet 29
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isTree_iff_existsUnique_path (L248-L269)
theorem isTree_iff_existsUnique_path :
    G.IsTree ↔ Nonempty V ∧ ∀ v w : V, ∃! p : G.Walk v w, p.IsPath := by
classical
  rw [isTree_iff, isAcyclic_iff_path_unique]
  constructor
  · rintro ⟨hc, hu⟩
    refine ⟨hc.nonempty, ?_⟩
    intro v w
    let q := (hc v w).some.toPath
    use q
    simp only [true_and, Path.isPath]
    intro p hp
    specialize hu ⟨p, hp⟩ q
    exact Subtype.ext_iff.mp hu
  · rintro ⟨hV, h⟩
    refine ⟨Connected.mk ?_, ?_⟩
    · intro v w
      obtain ⟨p, _⟩ := h v w
      exact p.reachable
    · rintro v w ⟨p, hp⟩ ⟨q, hq⟩
      simp only [ExistsUnique.unique (h v w) hp hq]
```

-- snippet 30
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_sup_fromEdgeSet_iff (L380-L396)
theorem isAcyclic_sup_fromEdgeSet_iff {u v : V} :
    (G ⊔ fromEdgeSet {s(u, v)}).IsAcyclic ↔
      G.IsAcyclic ∧ (G.Reachable u v → u = v ∨ G.Adj u v) := by
by_cases huv : u = v
  · grind [sup_eq_left, fromEdgeSet_le, Sym2.mem_diagSet, Sym2.mk_isDiag_iff]
  by_cases hadj : G.Adj u v
  · grind [sup_eq_left, fromEdgeSet_le, mem_edgeSet]
  refine ⟨?_, fun ⟨hacyc, hreach⟩ ↦ hacyc.isAcyclic_sup_fromEdgeSet_of_not_reachable <| by grind⟩
  refine fun hacyc ↦ ⟨hacyc.anti le_sup_left, fun hreach ↦ False.elim ?_⟩
  have := isAcyclic_iff_forall_edge_isBridge.mp (e := s(u, v)) hacyc <| by simp [huv]
  refine isBridge_iff.mp this |>.right <| hreach.mono <| Eq.le <| Eq.symm ?_
  rw [sup_sdiff_right_self]
  exact deleteEdges_eq_self.mpr <| Set.disjoint_singleton_right.mpr hadj

/--
The reachability relation of a maximal acyclic subgraph agrees with that of the larger graph.
-/
```

-- snippet 31
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.Subgraph (L151-L153)
lemma Subgraph.isAcyclic_coe_bot (G : SimpleGraph V) : (⊥ : G.Subgraph).coe.IsAcyclic :=
@IsAcyclic.of_subsingleton _ (Set.isEmpty_coe_sort.mpr rfl).instSubsingleton _
```

-- snippet 32
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.exists_isAcyclic_reachable_eq_le (L457-L462)
theorem exists_isAcyclic_reachable_eq_le :
    ∃ F ≤ G, F.IsAcyclic ∧ F.Reachable = G.Reachable := by
obtain ⟨F, hF⟩ := G.exists_isAcyclic_reachable_eq_le_of_le_of_isAcyclic bot_le isAcyclic_bot
  grind

/-- Every acyclic subgraph of a connected graph can be extended to a spanning tree. -/
```

-- snippet 33
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.Connected (L428-L436)
theorem Connected.maximal_le_isAcyclic_iff_isTree {T : SimpleGraph V} (hG : G.Connected)
    (hT : T ≤ G) : Maximal (fun H ↦ H ≤ G ∧ H.IsAcyclic) T ↔ T.IsTree := by
have := hG.nonempty
  refine ⟨fun h ↦ ⟨⟨fun u v ↦ ?_⟩, h.1.2⟩, fun hT' ↦ ?_⟩
  · exact G.reachable_eq_of_maximal_isAcyclic T h ▸ hG.preconnected u v
  · rw [maximal_isAcyclic_iff_reachable_eq hT hT'.isAcyclic,
      T.preconnected_iff_reachable_eq_top.mp hT'.preconnected,
      G.preconnected_iff_reachable_eq_top.mp hG.preconnected]
```

-- snippet 34
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isTree_iff_maximal_isAcyclic (L444-L449)
theorem isTree_iff_maximal_isAcyclic : G.IsTree ↔ Nonempty V ∧ Maximal IsAcyclic G := by
refine ⟨fun h ↦ ?_, fun ⟨_, h⟩ ↦ G.maximal_isAcyclic_iff_isTree.mp h⟩
  have := h.nonempty
  exact ⟨this, G.maximal_isAcyclic_iff_isTree.mpr h⟩

/-- Every acyclic subgraph can be extended to a spanning forest. -/
```

-- snippet 35
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.exists_isCycle_of_two_le_isEdgeReachable (L642-L649)
lemma exists_isCycle_of_two_le_isEdgeReachable {u v : V} (huv : u ≠ v) {n : ℕ} (hn : 2 ≤ n)
    (h : G.IsEdgeReachable n u v) : ∃ w : G.Walk u u, w.IsCycle := by
classical
  obtain ⟨w, hw, h⟩ := exists_adj_isEdgeReachable_two huv (h.anti hn)
  have := @h {s(u, w)} (by simp)
  obtain ⟨w, p, hp₁, hp₂⟩ := adj_and_reachable_delete_edges_iff_exists_cycle.mp ⟨hw, this⟩
  exact ⟨p.rotate _ (p.fst_mem_support_of_mem_edges hp₂), IsCycle.rotate hp₁ _⟩
```

-- snippet 36
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.exists_maximal_isAcyclic_of_le_isAcyclic (L127-L135)
theorem exists_maximal_isAcyclic_of_le_isAcyclic
    {H : SimpleGraph V} (hHG : H ≤ G) (hH : H.IsAcyclic) :
    ∃ H' : SimpleGraph V, H ≤ H' ∧ Maximal (fun H => H ≤ G ∧ H.IsAcyclic) H' := by
refine zorn_le_nonempty₀ {H | H ≤ G ∧ H.IsAcyclic} (fun c hcs hc y hy ↦ ?_) _ ⟨hHG, hH⟩
  refine ⟨sSup c, ⟨?_, ?_⟩, fun _ ↦ le_sSup⟩
  · grind [sSup_le_iff]
  · exact isAcyclic_sSup_of_isAcyclic_directedOn c (by grind) hc.directedOn

/-- A connected component of an acyclic graph is a tree. -/
```

-- snippet 37
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_add_edge_iff_of_not_reachable (L374-L379)
theorem isAcyclic_add_edge_iff_of_not_reachable (x y : V) (hxy : ¬ G.Reachable x y) :
    (G ⊔ fromEdgeSet {s(x, y)}).IsAcyclic ↔ IsAcyclic G :=
⟨.anti le_sup_left, .isAcyclic_sup_fromEdgeSet_of_not_reachable hxy⟩

/-- Adding an edge results in an acyclic graph iff the original graph was acyclic and
the edge connects vertices that previously had no path between them. -/
```

-- snippet 38
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_of_path_unique (L214-L224)
theorem isAcyclic_of_path_unique (h : ∀ (v w : V) (p q : G.Path v w), p = q) : G.IsAcyclic := by
intro v c hc
  simp only [Walk.isCycle_def, Ne] at hc
  cases c with
  | nil => cases hc.2.1 rfl
  | cons ha c' =>
    simp only [Walk.isTrail_cons, Walk.support_cons, List.tail_cons] at hc
    specialize h _ _ ⟨c', by simp only [Walk.isPath_def, hc.2]⟩ (Path.singleton ha.symm)
    rw [Path.singleton, Subtype.mk.injEq] at h
    simp [h] at hc
```

-- snippet 39
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_iff_path_unique (L225-L227)
theorem isAcyclic_iff_path_unique : G.IsAcyclic ↔ ∀ ⦃v w : V⦄ (p q : G.Path v w), p = q :=
⟨IsAcyclic.path_unique, isAcyclic_of_path_unique⟩
```

-- snippet 40
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.maximal_isAcyclic_iff_isTree (L438-L443)
theorem maximal_isAcyclic_iff_isTree [Nonempty V] {T : SimpleGraph V} :
    Maximal IsAcyclic T ↔ T.IsTree := by
simp [← connected_top.maximal_le_isAcyclic_iff_isTree le_top]

/-- A maximally acyclic graph is a tree. This is similar to `maximal_isAcyclic_iff_isTree` except
with `Nonempty V` as part of the iff rather than an assumption. -/
```

<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.Combinatorics.SimpleGraph.Walks.Operations).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]Prove the following theorem. The retrieved context below may help.

```lean
lemma drop_add_eq (p : G.Walk u v) (n m : ℕ) :
    p.drop (n + m) = ((p.drop n).drop m).copy (drop_getVert ..) rfl
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.copy_rfl_rfl (L52-L53)
theorem copy_rfl_rfl {u v} (p : G.Walk u v) : p.copy rfl rfl = p := rfl
```

-- snippet 2
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.copy_copy (L55-L60)
theorem copy_copy {u v u' v' u'' v''} (p : G.Walk u v)
    (hu : u = u') (hv : v = v') (hu' : u' = u'') (hv' : v' = v'') :
    (p.copy hu hv).copy hu' hv' = p.copy (hu.trans hu') (hv.trans hv') := by
subst_vars
  rfl
```

-- snippet 3
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.copy_nil (L62-L65)
theorem copy_nil {u u'} (hu : u = u') : (Walk.nil : G.Walk u u).copy hu hu = nil := by
subst_vars
  rfl
```

-- snippet 4
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.copy_cons (L66-L70)
theorem copy_cons {u v w u' w'} (h : G.Adj u v) (p : G.Walk v w) (hu : u = u') (hw : w = w') :
    (Walk.cons h p).copy hu hw = Walk.cons (hu ▸ h) (p.copy rfl hw) := by
subst_vars
  rfl
```

-- snippet 5
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.cons_copy (L72-L77)
theorem cons_copy {u v w v' w'} (h : G.Adj u v) (p : G.Walk v' w') (hv : v' = v) (hw : w' = w) :
    cons h (p.copy hv hw) = (Walk.cons (hv ▸ h) p).copy rfl hw := by
subst_vars
  rfl

/-- The concatenation of two compatible walks. -/
```

-- snippet 6
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.append (L79-L84)
def append {u v w : V} : G.Walk u v → G.Walk v w → G.Walk u w
  | nil, q => q
  | cons h p, q => cons h (p.append q)

/-- The reversed version of `SimpleGraph.Walk.cons`, concatenating an edge to
the end of a walk. -/
```

-- snippet 7
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.concat (L85-L86)
def concat {u v w : V} (p : G.Walk u v) (h : G.Adj v w) : G.Walk u w := p.append (cons h nil)
```

-- snippet 8
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.concat_eq_append (L87-L95)
theorem concat_eq_append {u v w : V} (p : G.Walk u v) (h : G.Adj v w) :
    p.concat h = p.append (cons h nil) := rfl
/-- The concatenation of the reverse of the first walk with the second walk. -/
protected def reverseAux {u v w : V} : G.Walk u v → G.Walk u w → G.Walk v w
  | nil, q => q
  | cons h p, q => Walk.reverseAux p (cons (G.symm h) q)

/-- The walk in reverse. -/
```

-- snippet 9
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.reverse (L97-L98)
def reverse {u v : V} (w : G.Walk u v) : G.Walk v u := w.reverseAux nil
```

-- snippet 10
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.cons_append (L100-L102)
theorem cons_append {u v w x : V} (h : G.Adj u v) (p : G.Walk v w) (q : G.Walk w x) :
    (cons h p).append q = cons h (p.append q) := rfl
```

-- snippet 11
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.cons_nil_append (L104-L106)
theorem cons_nil_append {u v w : V} (h : G.Adj u v) (p : G.Walk v w) :
    (cons h nil).append p = cons h p := rfl
```

-- snippet 12
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.nil_append (L108-L110)
theorem nil_append {u v : V} (p : G.Walk u v) : nil.append p = p :=
rfl
```

-- snippet 13
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.append_nil (L112-L114)
theorem append_nil {u v : V} (p : G.Walk u v) : p.append nil = p := by
induction p <;> simp [*]
```

-- snippet 14
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.append_assoc (L115-L118)
theorem append_assoc {u v w x : V} (p : G.Walk u v) (q : G.Walk v w) (r : G.Walk w x) :
    p.append (q.append r) = (p.append q).append r := by
induction p <;> simp [*]
```

-- snippet 15
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.append_copy_copy (L120-L125)
theorem append_copy_copy {u v w u' v' w'} (p : G.Walk u v) (q : G.Walk v w)
    (hu : u = u') (hv : v = v') (hw : w = w') :
    (p.copy hu hv).append (q.copy hv hw) = (p.append q).copy hu hw := by
subst_vars
  rfl
```

-- snippet 16
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isTree_iff_minimal_connected (L360-L368)
lemma isTree_iff_minimal_connected : IsTree G ↔ Minimal Connected G := by
refine ⟨fun htree ↦ ⟨htree.connected, fun G' h' hle u v hadj ↦ ?_⟩, isTree_of_minimal_connected⟩
  have ⟨p, hp⟩ := h'.exists_isPath u v
  have := congrArg Walk.edges <| congrArg Subtype.val <|
    htree.isAcyclic.path_unique ⟨p.mapLe hle, hp.mapLe hle⟩ <| Path.singleton hadj
  simp only [edges_map, Hom.coe_ofLE, Sym2.map_id, List.map_id_fun, id_eq] at this
  simp [this, p.adj_of_mem_edges]

/-- Connecting two unreachable vertices by an edge preserves acyclicity. -/
```

-- snippet 17
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_iff_forall_adj_isBridge (L167-L180)
theorem isAcyclic_iff_forall_adj_isBridge :
    G.IsAcyclic ↔ ∀ ⦃v w : V⦄, G.Adj v w → G.IsBridge s(v, w) := by
simp_rw [isBridge_iff_adj_and_forall_cycle_notMem]
  constructor
  · intro ha v w hvw
    apply And.intro hvw
    intro u p hp
    cases ha p hp
  · rintro hb v (_ | ⟨ha, p⟩) hp
    · exact hp.not_of_nil
    · apply (hb ha).2 _ hp
      rw [Walk.edges_cons]
      apply List.mem_cons_self
```

-- snippet 18
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.IsAcyclic (L55-L57)
def IsAcyclic : Prop := ∀ ⦃v : V⦄ (c : G.Walk v v), ¬c.IsCycle
/-- A *tree* is a connected acyclic graph. -/
```

-- snippet 19
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_iff_pairwise_not_isEdgeReachable_two (L650-L658)
lemma isAcyclic_iff_pairwise_not_isEdgeReachable_two :
    G.IsAcyclic ↔ Pairwise (¬G.IsEdgeReachable 2 · ·) := by
refine ⟨fun h _ _ hne he ↦ ?_, fun h ↦ ?_⟩
  · obtain ⟨w, hw⟩ := exists_isCycle_of_two_le_isEdgeReachable hne le_rfl he
    exact h w hw
  · refine isAcyclic_iff_forall_adj_isBridge.mpr fun _ _ hadj ↦ ?_
    exact isBridge_iff_adj_and_not_isEdgeConnected_two.mpr ⟨hadj, h hadj.ne⟩

end SimpleGraph
```

-- snippet 20
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isTree_iff_connected_and_card (L486-L499)
lemma isTree_iff_connected_and_card [Finite V] :
    G.IsTree ↔ G.Connected ∧ Nat.card G.edgeSet + 1 = Nat.card V := by
have := Fintype.ofFinite V
  classical
  refine ⟨fun h ↦ ⟨h.connected, by simpa [edgeFinset] using h.card_edgeFinset⟩,
    fun ⟨h₁, h₂⟩ ↦ ⟨h₁, ?_⟩⟩
  simp_rw [isAcyclic_iff_forall_adj_isBridge]
  refine fun x y h ↦ by_contra fun hbr ↦
    (h₁.connected_delete_edge_of_not_isBridge hbr).card_vert_le_card_edgeSet_add_one.not_gt ?_
  rw [Nat.card_eq_fintype_card, ← edgeFinset_card, ← h₂, Nat.card_eq_fintype_card,
    ← edgeFinset_card, add_lt_add_iff_right]
  exact Finset.card_lt_card <| by simpa [deleteEdges, edgeFinset]

/-- The minimum degree of all vertices in a nontrivial tree is one. -/
```

-- snippet 21
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_sSup_of_isAcyclic_directedOn (L118-L126)
lemma isAcyclic_sSup_of_isAcyclic_directedOn (Hs : Set <| SimpleGraph V)
    (h_acyc : ∀ H ∈ Hs, H.IsAcyclic) (h_dir : DirectedOn (· ≤ ·) Hs) : IsAcyclic (sSup Hs) := by
rcases Hs.eq_empty_or_nonempty with rfl | hnemp
  · simp
  · intro u p hp
    obtain ⟨H, hH, hpH⟩ := p.exists_mem_contains_edges_of_directed Hs hnemp h_dir
    exact h_acyc H hH (p.transfer H hpH) <| Walk.IsCycle.transfer hp hpH

/-- Every acyclic subgraph `H ≤ G` is contained in a maximal such subgraph. -/
```

-- snippet 22
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.reachable_eq_of_maximal_isAcyclic (L397-L412)
lemma reachable_eq_of_maximal_isAcyclic (F : SimpleGraph V)
    (h : Maximal (fun H ↦ H ≤ G ∧ H.IsAcyclic) F) : F.Reachable = G.Reachable := by
ext u v
  refine ⟨.mono h.prop.left, fun ⟨p⟩ ↦ ?_⟩
  by_contra
  let s : F.ConnectedComponent := .mk _ u
  have : v ∉ s := this ∘ s.reachable_of_mem_supp rfl
  have : ∃ d ∈ p.darts, d.fst ∈ s ∧ d.snd ∉ s := p.exists_boundary_dart s rfl this
  rcases this with ⟨⟨⟨u', v'⟩, huv⟩, _, hu, hv⟩
  have : ¬F.Reachable v' u' := mt ConnectedComponent.sound <| s.mem_supp_iff u' |>.mp hu ▸ hv
  suffices F ⊔ fromEdgeSet {s(v', u')} ≤ F by
    grind [Adj.reachable, sup_le_iff, le_iff_adj, fromEdgeSet_adj]
  refine h.le_of_ge ⟨?_, h.prop.right.isAcyclic_sup_fromEdgeSet_of_not_reachable this⟩ le_sup_left
  grind [Maximal, sup_le, le_iff_adj, fromEdgeSet_adj, huv.symm]

/-- A subgraph is maximal acyclic iff its reachability relation agrees with the larger graph. -/
```

-- snippet 23
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.Iso (L80-L83)
lemma Iso.isAcyclic_iff (f : G ≃g G') : G.IsAcyclic ↔ G'.IsAcyclic :=
⟨fun h ↦ h.embedding f.symm, fun h ↦ h.embedding f⟩

/-- Isomorphic graphs are trees together. -/
```

-- snippet 24
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_iff_forall_edge_isBridge (L181-L184)
theorem isAcyclic_iff_forall_edge_isBridge :
    G.IsAcyclic ↔ ∀ ⦃e⦄, e ∈ (G.edgeSet) → G.IsBridge e := by
simp [isAcyclic_iff_forall_adj_isBridge, Sym2.forall]
```

-- snippet 25
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.IsTree (L154-L156)
lemma IsTree.of_subsingleton [Nonempty V] [Subsingleton V] {G : SimpleGraph V} : G.IsTree :=
⟨.of_subsingleton, .of_subsingleton⟩
```

-- snippet 26
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.exists_isAcyclic_reachable_eq_le_of_le_of_isAcyclic (L450-L456)
theorem exists_isAcyclic_reachable_eq_le_of_le_of_isAcyclic {H : SimpleGraph V} (hH_le : H ≤ G)
    (hH_isAcyclic : H.IsAcyclic) :
    ∃ F : SimpleGraph V, H ≤ F ∧ F ≤ G ∧ F.IsAcyclic ∧ F.Reachable = G.Reachable := by
obtain ⟨F, hF⟩ := G.exists_maximal_isAcyclic_of_le_isAcyclic hH_le hH_isAcyclic
  grind [maximal_isAcyclic_iff_reachable_eq, Maximal]

/-- Every graph has a spanning forest. -/
```

-- snippet 27
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.maximal_isAcyclic_iff_reachable_eq (L413-L427)
theorem maximal_isAcyclic_iff_reachable_eq {F : SimpleGraph V} (hle : F ≤ G) (hF : F.IsAcyclic) :
    Maximal (fun F ↦ F ≤ G ∧ F.IsAcyclic) F ↔ F.Reachable = G.Reachable := by
refine ⟨reachable_eq_of_maximal_isAcyclic F, fun h ↦ ?_⟩
  by_contra
  have ⟨H, hFH, hHG, hH⟩ := exists_gt_of_not_maximal ⟨hle, hF⟩ this
  have ⟨e, heH, heF⟩ := Set.exists_of_ssubset <| edgeSet_strict_mono hFH
  have h_bridge : (F ⊔ fromEdgeSet {e}).IsBridge e := by
    refine isAcyclic_iff_forall_edge_isBridge.mp ?_ <| by simp [H.not_isDiag_of_mem_edgeSet heH]
    exact hH.anti <| sup_le_iff.mpr ⟨hFH.le, H.fromEdgeSet_le.mpr <| by grind⟩
  have : (F ⊔ fromEdgeSet {e}) \ fromEdgeSet {e} = F := by simpa using heF
  cases e
  rw [isBridge_iff, this, h] at h_bridge
  exact h_bridge.right <| hHG heH |>.reachable

/-- A subgraph of a connected graph is maximal acyclic iff it is a tree. -/
```

-- snippet 28
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isTree_of_minimal_connected (L353-L359)
lemma isTree_of_minimal_connected (h : Minimal Connected G) : IsTree G := by
rw [isTree_iff, and_iff_right h.prop, isAcyclic_iff_forall_adj_isBridge]
  exact fun _ _ _ ↦ by_contra fun hbr ↦ h.not_prop_of_lt
    (by simpa [deleteEdges, ← edgeSet_ssubset_edgeSet])
    <| h.prop.connected_delete_edge_of_not_isBridge hbr

set_option backward.isDefEq.respectTransparency false in
```

-- snippet 29
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isTree_iff_existsUnique_path (L248-L269)
theorem isTree_iff_existsUnique_path :
    G.IsTree ↔ Nonempty V ∧ ∀ v w : V, ∃! p : G.Walk v w, p.IsPath := by
classical
  rw [isTree_iff, isAcyclic_iff_path_unique]
  constructor
  · rintro ⟨hc, hu⟩
    refine ⟨hc.nonempty, ?_⟩
    intro v w
    let q := (hc v w).some.toPath
    use q
    simp only [true_and, Path.isPath]
    intro p hp
    specialize hu ⟨p, hp⟩ q
    exact Subtype.ext_iff.mp hu
  · rintro ⟨hV, h⟩
    refine ⟨Connected.mk ?_, ?_⟩
    · intro v w
      obtain ⟨p, _⟩ := h v w
      exact p.reachable
    · rintro v w ⟨p, hp⟩ ⟨q, hq⟩
      simp only [ExistsUnique.unique (h v w) hp hq]
```

-- snippet 30
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_sup_fromEdgeSet_iff (L380-L396)
theorem isAcyclic_sup_fromEdgeSet_iff {u v : V} :
    (G ⊔ fromEdgeSet {s(u, v)}).IsAcyclic ↔
      G.IsAcyclic ∧ (G.Reachable u v → u = v ∨ G.Adj u v) := by
by_cases huv : u = v
  · grind [sup_eq_left, fromEdgeSet_le, Sym2.mem_diagSet, Sym2.mk_isDiag_iff]
  by_cases hadj : G.Adj u v
  · grind [sup_eq_left, fromEdgeSet_le, mem_edgeSet]
  refine ⟨?_, fun ⟨hacyc, hreach⟩ ↦ hacyc.isAcyclic_sup_fromEdgeSet_of_not_reachable <| by grind⟩
  refine fun hacyc ↦ ⟨hacyc.anti le_sup_left, fun hreach ↦ False.elim ?_⟩
  have := isAcyclic_iff_forall_edge_isBridge.mp (e := s(u, v)) hacyc <| by simp [huv]
  refine isBridge_iff.mp this |>.right <| hreach.mono <| Eq.le <| Eq.symm ?_
  rw [sup_sdiff_right_self]
  exact deleteEdges_eq_self.mpr <| Set.disjoint_singleton_right.mpr hadj

/--
The reachability relation of a maximal acyclic subgraph agrees with that of the larger graph.
-/
```

-- snippet 31
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.Subgraph (L151-L153)
lemma Subgraph.isAcyclic_coe_bot (G : SimpleGraph V) : (⊥ : G.Subgraph).coe.IsAcyclic :=
@IsAcyclic.of_subsingleton _ (Set.isEmpty_coe_sort.mpr rfl).instSubsingleton _
```

-- snippet 32
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.exists_isAcyclic_reachable_eq_le (L457-L462)
theorem exists_isAcyclic_reachable_eq_le :
    ∃ F ≤ G, F.IsAcyclic ∧ F.Reachable = G.Reachable := by
obtain ⟨F, hF⟩ := G.exists_isAcyclic_reachable_eq_le_of_le_of_isAcyclic bot_le isAcyclic_bot
  grind

/-- Every acyclic subgraph of a connected graph can be extended to a spanning tree. -/
```

-- snippet 33
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.Connected (L428-L436)
theorem Connected.maximal_le_isAcyclic_iff_isTree {T : SimpleGraph V} (hG : G.Connected)
    (hT : T ≤ G) : Maximal (fun H ↦ H ≤ G ∧ H.IsAcyclic) T ↔ T.IsTree := by
have := hG.nonempty
  refine ⟨fun h ↦ ⟨⟨fun u v ↦ ?_⟩, h.1.2⟩, fun hT' ↦ ?_⟩
  · exact G.reachable_eq_of_maximal_isAcyclic T h ▸ hG.preconnected u v
  · rw [maximal_isAcyclic_iff_reachable_eq hT hT'.isAcyclic,
      T.preconnected_iff_reachable_eq_top.mp hT'.preconnected,
      G.preconnected_iff_reachable_eq_top.mp hG.preconnected]
```

-- snippet 34
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isTree_iff_maximal_isAcyclic (L444-L449)
theorem isTree_iff_maximal_isAcyclic : G.IsTree ↔ Nonempty V ∧ Maximal IsAcyclic G := by
refine ⟨fun h ↦ ?_, fun ⟨_, h⟩ ↦ G.maximal_isAcyclic_iff_isTree.mp h⟩
  have := h.nonempty
  exact ⟨this, G.maximal_isAcyclic_iff_isTree.mpr h⟩

/-- Every acyclic subgraph can be extended to a spanning forest. -/
```

-- snippet 35
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.exists_isCycle_of_two_le_isEdgeReachable (L642-L649)
lemma exists_isCycle_of_two_le_isEdgeReachable {u v : V} (huv : u ≠ v) {n : ℕ} (hn : 2 ≤ n)
    (h : G.IsEdgeReachable n u v) : ∃ w : G.Walk u u, w.IsCycle := by
classical
  obtain ⟨w, hw, h⟩ := exists_adj_isEdgeReachable_two huv (h.anti hn)
  have := @h {s(u, w)} (by simp)
  obtain ⟨w, p, hp₁, hp₂⟩ := adj_and_reachable_delete_edges_iff_exists_cycle.mp ⟨hw, this⟩
  exact ⟨p.rotate _ (p.fst_mem_support_of_mem_edges hp₂), IsCycle.rotate hp₁ _⟩
```

-- snippet 36
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.exists_maximal_isAcyclic_of_le_isAcyclic (L127-L135)
theorem exists_maximal_isAcyclic_of_le_isAcyclic
    {H : SimpleGraph V} (hHG : H ≤ G) (hH : H.IsAcyclic) :
    ∃ H' : SimpleGraph V, H ≤ H' ∧ Maximal (fun H => H ≤ G ∧ H.IsAcyclic) H' := by
refine zorn_le_nonempty₀ {H | H ≤ G ∧ H.IsAcyclic} (fun c hcs hc y hy ↦ ?_) _ ⟨hHG, hH⟩
  refine ⟨sSup c, ⟨?_, ?_⟩, fun _ ↦ le_sSup⟩
  · grind [sSup_le_iff]
  · exact isAcyclic_sSup_of_isAcyclic_directedOn c (by grind) hc.directedOn

/-- A connected component of an acyclic graph is a tree. -/
```

-- snippet 37
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_add_edge_iff_of_not_reachable (L374-L379)
theorem isAcyclic_add_edge_iff_of_not_reachable (x y : V) (hxy : ¬ G.Reachable x y) :
    (G ⊔ fromEdgeSet {s(x, y)}).IsAcyclic ↔ IsAcyclic G :=
⟨.anti le_sup_left, .isAcyclic_sup_fromEdgeSet_of_not_reachable hxy⟩

/-- Adding an edge results in an acyclic graph iff the original graph was acyclic and
the edge connects vertices that previously had no path between them. -/
```

-- snippet 38
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_of_path_unique (L214-L224)
theorem isAcyclic_of_path_unique (h : ∀ (v w : V) (p q : G.Path v w), p = q) : G.IsAcyclic := by
intro v c hc
  simp only [Walk.isCycle_def, Ne] at hc
  cases c with
  | nil => cases hc.2.1 rfl
  | cons ha c' =>
    simp only [Walk.isTrail_cons, Walk.support_cons, List.tail_cons] at hc
    specialize h _ _ ⟨c', by simp only [Walk.isPath_def, hc.2]⟩ (Path.singleton ha.symm)
    rw [Path.singleton, Subtype.mk.injEq] at h
    simp [h] at hc
```

-- snippet 39
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_iff_path_unique (L225-L227)
theorem isAcyclic_iff_path_unique : G.IsAcyclic ↔ ∀ ⦃v w : V⦄ (p q : G.Path v w), p = q :=
⟨IsAcyclic.path_unique, isAcyclic_of_path_unique⟩
```

-- snippet 40
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.maximal_isAcyclic_iff_isTree (L438-L443)
theorem maximal_isAcyclic_iff_isTree [Nonempty V] {T : SimpleGraph V} :
    Maximal IsAcyclic T ↔ T.IsTree := by
simp [← connected_top.maximal_le_isAcyclic_iff_isTree le_top]

/-- A maximally acyclic graph is a tree. This is similar to `maximal_isAcyclic_iff_isTree` except
with `Nonempty V` as part of the iff rather than an assumption. -/
```
[/INST]