l3lab/ntp-mathlib huggingface dataset:
/-- In the unit group of an integral domain, a unit is its own inverse iff the unit is one or
  one's additive inverse. -/
theorem inv_eq_self_iff [Ring R] [NoZeroDivisors R] (u : Rˣ) : u⁻¹ = u ↔ u = 1 ∨ u = -1 := by
  rw [inv_eq_iff_mul_eq_one]
  simp only [ext_iff]
  push_cast
  

Proof state:
α : Type u
β : Type v
γ : Type w
R : Type x
inst✝¹ : Ring R
inst✝ : NoZeroDivisors R
u : Rˣ
⊢ ↑u * ↑u = 1 ↔ ↑u = 1 ∨ ↑u = -1

Next tactic:
exact mul_self_eq_one_iff
lemma continuous_mul_log : Continuous fun x ↦ x * log x := by
  

Proof state:
⊢ Continuous fun x => x * log x

Next tactic:
rw [continuous_iff_continuousAt]
lemma continuous_mul_log : Continuous fun x ↦ x * log x := by
  rw [continuous_iff_continuousAt]
  

Proof state:
⊢ ∀ (x : ℝ), ContinuousAt (fun x => x * log x) x

Next tactic:
intro x
lemma continuous_mul_log : Continuous fun x ↦ x * log x := by
  rw [continuous_iff_continuousAt]
  intro x
  

Proof state:
x : ℝ
⊢ ContinuousAt (fun x => x * log x) x

Next tactic:
obtain hx | rfl := ne_or_eq x 0
lemma continuous_mul_log : Continuous fun x ↦ x * log x := by
  rw [continuous_iff_continuousAt]
  intro x
  obtain hx | rfl := ne_or_eq x 0
  · 

Proof state:
case inl
x : ℝ
hx : x ≠ 0
⊢ ContinuousAt (fun x => x * log x) x

Next tactic:
exact (continuous_id'.continuousAt).mul (continuousAt_log hx)
lemma continuous_mul_log : Continuous fun x ↦ x * log x := by
  rw [continuous_iff_continuousAt]
  intro x
  obtain hx | rfl := ne_or_eq x 0
  · exact (continuous_id'.continuousAt).mul (continuousAt_log hx)
  

Proof state:
case inr
⊢ ContinuousAt (fun x => x * log x) 0

Next tactic:
rw [ContinuousAt, zero_mul]
lemma continuous_mul_log : Continuous fun x ↦ x * log x := by
  rw [continuous_iff_continuousAt]
  intro x
  obtain hx | rfl := ne_or_eq x 0
  · exact (continuous_id'.continuousAt).mul (continuousAt_log hx)
  rw [ContinuousAt, zero_mul]
  

Proof state:
case inr
⊢ Filter.Tendsto (fun x => x * log x) (𝓝 0) (𝓝 0)

Next tactic:
simp_rw [mul_comm _ (log _)]
lemma continuous_mul_log : Continuous fun x ↦ x * log x := by
  rw [continuous_iff_continuousAt]
  intro x
  obtain hx | rfl := ne_or_eq x 0
  · exact (continuous_id'.continuousAt).mul (continuousAt_log hx)
  rw [ContinuousAt, zero_mul]
  simp_rw [mul_comm _ (log _)]
  

Proof state:
case inr
⊢ Filter.Tendsto (fun x => log x * x) (𝓝 0) (𝓝 0)

Next tactic:
nth_rewrite 1 [← nhdsWithin_univ]
lemma continuous_mul_log : Continuous fun x ↦ x * log x := by
  rw [continuous_iff_continuousAt]
  intro x
  obtain hx | rfl := ne_or_eq x 0
  · exact (continuous_id'.continuousAt).mul (continuousAt_log hx)
  rw [ContinuousAt, zero_mul]
  simp_rw [mul_comm _ (log _)]
  nth_rewrite 1 [← nhdsWithin_univ]
  

Proof state:
case inr
⊢ Filter.Tendsto (fun x => log x * x) (𝓝[Set.univ] 0) (𝓝 0)

Next tactic:
have : (Set.univ : Set ℝ) = Set.Iio 0 ∪ Set.Ioi 0 ∪ {0} := by ext; simp [em]
lemma continuous_mul_log : Continuous fun x ↦ x * log x := by
  rw [continuous_iff_continuousAt]
  intro x
  obtain hx | rfl := ne_or_eq x 0
  · exact (continuous_id'.continuousAt).mul (continuousAt_log hx)
  rw [ContinuousAt, zero_mul]
  simp_rw [mul_comm _ (log _)]
  nth_rewrite 1 [← nhdsWithin_univ]
  have : (Set.univ : Set ℝ) = Set.Iio 0 ∪ Set.Ioi 0 ∪ {0} := by 

Proof state:
⊢ Set.univ = Set.Iio 0 ∪ Set.Ioi 0 ∪ {0}

Next tactic:
ext
lemma continuous_mul_log : Continuous fun x ↦ x * log x := by
  rw [continuous_iff_continuousAt]
  intro x
  obtain hx | rfl := ne_or_eq x 0
  · exact (continuous_id'.continuousAt).mul (continuousAt_log hx)
  rw [ContinuousAt, zero_mul]
  simp_rw [mul_comm _ (log _)]
  nth_rewrite 1 [← nhdsWithin_univ]
  have : (Set.univ : Set ℝ) = Set.Iio 0 ∪ Set.Ioi 0 ∪ {0} := by ext; 

Proof state:
case h
x✝ : ℝ
⊢ x✝ ∈ Set.univ ↔ x✝ ∈ Set.Iio 0 ∪ Set.Ioi 0 ∪ {0}

Next tactic:
simp [em]
lemma continuous_mul_log : Continuous fun x ↦ x * log x := by
  rw [continuous_iff_continuousAt]
  intro x
  obtain hx | rfl := ne_or_eq x 0
  · exact (continuous_id'.continuousAt).mul (continuousAt_log hx)
  rw [ContinuousAt, zero_mul]
  simp_rw [mul_comm _ (log _)]
  nth_rewrite 1 [← nhdsWithin_univ]
  have : (Set.univ : Set ℝ) = Set.Iio 0 ∪ Set.Ioi 0 ∪ {0} := by ext; simp [em]
  

Proof state:
case inr
this : Set.univ = Set.Iio 0 ∪ Set.Ioi 0 ∪ {0}
⊢ Filter.Tendsto (fun x => log x * x) (𝓝[Set.univ] 0) (𝓝 0)

Next tactic:
rw [this, nhdsWithin_union, nhdsWithin_union]
lemma continuous_mul_log : Continuous fun x ↦ x * log x := by
  rw [continuous_iff_continuousAt]
  intro x
  obtain hx | rfl := ne_or_eq x 0
  · exact (continuous_id'.continuousAt).mul (continuousAt_log hx)
  rw [ContinuousAt, zero_mul]
  simp_rw [mul_comm _ (log _)]
  nth_rewrite 1 [← nhdsWithin_univ]
  have : (Set.univ : Set ℝ) = Set.Iio 0 ∪ Set.Ioi 0 ∪ {0} := by ext; simp [em]
  rw [this, nhdsWithin_union, nhdsWithin_union]
  

Proof state:
case inr
this : Set.univ = Set.Iio 0 ∪ Set.Ioi 0 ∪ {0}
⊢ Filter.Tendsto (fun x => log x * x) (𝓝[<] 0 ⊔ 𝓝[>] 0 ⊔ 𝓝[{0}] 0) (𝓝 0)

Next tactic:
simp only [nhdsWithin_singleton, sup_le_iff, Filter.nonpos_iff, Filter.tendsto_sup]
lemma continuous_mul_log : Continuous fun x ↦ x * log x := by
  rw [continuous_iff_continuousAt]
  intro x
  obtain hx | rfl := ne_or_eq x 0
  · exact (continuous_id'.continuousAt).mul (continuousAt_log hx)
  rw [ContinuousAt, zero_mul]
  simp_rw [mul_comm _ (log _)]
  nth_rewrite 1 [← nhdsWithin_univ]
  have : (Set.univ : Set ℝ) = Set.Iio 0 ∪ Set.Ioi 0 ∪ {0} := by ext; simp [em]
  rw [this, nhdsWithin_union, nhdsWithin_union]
  simp only [nhdsWithin_singleton, sup_le_iff, Filter.nonpos_iff, Filter.tendsto_sup]
  

Proof state:
case inr
this : Set.univ = Set.Iio 0 ∪ Set.Ioi 0 ∪ {0}
⊢ (Filter.Tendsto (fun x => log x * x) (𝓝[<] 0) (𝓝 0) ∧ Filter.Tendsto (fun x => log x * x) (𝓝[>] 0) (𝓝 0)) ∧
    Filter.Tendsto (fun x => log x * x) (pure 0) (𝓝 0)

Next tactic:
refine ⟨⟨tendsto_log_mul_self_nhds_zero_left, ?_⟩, ?_⟩
lemma continuous_mul_log : Continuous fun x ↦ x * log x := by
  rw [continuous_iff_continuousAt]
  intro x
  obtain hx | rfl := ne_or_eq x 0
  · exact (continuous_id'.continuousAt).mul (continuousAt_log hx)
  rw [ContinuousAt, zero_mul]
  simp_rw [mul_comm _ (log _)]
  nth_rewrite 1 [← nhdsWithin_univ]
  have : (Set.univ : Set ℝ) = Set.Iio 0 ∪ Set.Ioi 0 ∪ {0} := by ext; simp [em]
  rw [this, nhdsWithin_union, nhdsWithin_union]
  simp only [nhdsWithin_singleton, sup_le_iff, Filter.nonpos_iff, Filter.tendsto_sup]
  refine ⟨⟨tendsto_log_mul_self_nhds_zero_left, ?_⟩, ?_⟩
  · 

Proof state:
case inr.refine_1
this : Set.univ = Set.Iio 0 ∪ Set.Ioi 0 ∪ {0}
⊢ Filter.Tendsto (fun x => log x * x) (𝓝[>] 0) (𝓝 0)

Next tactic:
simpa only [rpow_one] using tendsto_log_mul_rpow_nhds_zero zero_lt_one
lemma continuous_mul_log : Continuous fun x ↦ x * log x := by
  rw [continuous_iff_continuousAt]
  intro x
  obtain hx | rfl := ne_or_eq x 0
  · exact (continuous_id'.continuousAt).mul (continuousAt_log hx)
  rw [ContinuousAt, zero_mul]
  simp_rw [mul_comm _ (log _)]
  nth_rewrite 1 [← nhdsWithin_univ]
  have : (Set.univ : Set ℝ) = Set.Iio 0 ∪ Set.Ioi 0 ∪ {0} := by ext; simp [em]
  rw [this, nhdsWithin_union, nhdsWithin_union]
  simp only [nhdsWithin_singleton, sup_le_iff, Filter.nonpos_iff, Filter.tendsto_sup]
  refine ⟨⟨tendsto_log_mul_self_nhds_zero_left, ?_⟩, ?_⟩
  · simpa only [rpow_one] using tendsto_log_mul_rpow_nhds_zero zero_lt_one
  · 

Proof state:
case inr.refine_2
this : Set.univ = Set.Iio 0 ∪ Set.Ioi 0 ∪ {0}
⊢ Filter.Tendsto (fun x => log x * x) (pure 0) (𝓝 0)

Next tactic:
convert tendsto_pure_nhds (fun x ↦ log x * x) 0
lemma continuous_mul_log : Continuous fun x ↦ x * log x := by
  rw [continuous_iff_continuousAt]
  intro x
  obtain hx | rfl := ne_or_eq x 0
  · exact (continuous_id'.continuousAt).mul (continuousAt_log hx)
  rw [ContinuousAt, zero_mul]
  simp_rw [mul_comm _ (log _)]
  nth_rewrite 1 [← nhdsWithin_univ]
  have : (Set.univ : Set ℝ) = Set.Iio 0 ∪ Set.Ioi 0 ∪ {0} := by ext; simp [em]
  rw [this, nhdsWithin_union, nhdsWithin_union]
  simp only [nhdsWithin_singleton, sup_le_iff, Filter.nonpos_iff, Filter.tendsto_sup]
  refine ⟨⟨tendsto_log_mul_self_nhds_zero_left, ?_⟩, ?_⟩
  · simpa only [rpow_one] using tendsto_log_mul_rpow_nhds_zero zero_lt_one
  · convert tendsto_pure_nhds (fun x ↦ log x * x) 0
    

Proof state:
case h.e'_5.h.e'_3
this : Set.univ = Set.Iio 0 ∪ Set.Ioi 0 ∪ {0}
⊢ 0 = log 0 * 0

Next tactic:
simp
lemma deriv_mul_log {x : ℝ} (hx : x ≠ 0) : deriv (fun x ↦ x * log x) x = log x + 1 := by
  

Proof state:
x : ℝ
hx : x ≠ 0
⊢ deriv (fun x => x * log x) x = log x + 1

Next tactic:
rw [deriv_mul differentiableAt_id' (differentiableAt_log hx)]
lemma deriv_mul_log {x : ℝ} (hx : x ≠ 0) : deriv (fun x ↦ x * log x) x = log x + 1 := by
  rw [deriv_mul differentiableAt_id' (differentiableAt_log hx)]
  

Proof state:
x : ℝ
hx : x ≠ 0
⊢ deriv (fun x => x) x * log x + x * deriv log x = log x + 1

Next tactic:
simp only [deriv_id'', one_mul, deriv_log', ne_eq, add_right_inj]
lemma deriv_mul_log {x : ℝ} (hx : x ≠ 0) : deriv (fun x ↦ x * log x) x = log x + 1 := by
  rw [deriv_mul differentiableAt_id' (differentiableAt_log hx)]
  simp only [deriv_id'', one_mul, deriv_log', ne_eq, add_right_inj]
  

Proof state:
x : ℝ
hx : x ≠ 0
⊢ x * x⁻¹ = 1

Next tactic:
exact mul_inv_cancel hx
lemma hasDerivAt_mul_log {x : ℝ} (hx : x ≠ 0) : HasDerivAt (fun x ↦ x * log x) (log x + 1) x := by
  

Proof state:
x : ℝ
hx : x ≠ 0
⊢ HasDerivAt (fun x => x * log x) (log x + 1) x

Next tactic:
rw [← deriv_mul_log hx, hasDerivAt_deriv_iff]
lemma hasDerivAt_mul_log {x : ℝ} (hx : x ≠ 0) : HasDerivAt (fun x ↦ x * log x) (log x + 1) x := by
  rw [← deriv_mul_log hx, hasDerivAt_deriv_iff]
  

Proof state:
x : ℝ
hx : x ≠ 0
⊢ DifferentiableAt ℝ (fun x => x * log x) x

Next tactic:
refine DifferentiableOn.differentiableAt differentiableOn_mul_log ?_
lemma hasDerivAt_mul_log {x : ℝ} (hx : x ≠ 0) : HasDerivAt (fun x ↦ x * log x) (log x + 1) x := by
  rw [← deriv_mul_log hx, hasDerivAt_deriv_iff]
  refine DifferentiableOn.differentiableAt differentiableOn_mul_log ?_
  

Proof state:
x : ℝ
hx : x ≠ 0
⊢ {0}ᶜ ∈ 𝓝 x

Next tactic:
simp [hx]
lemma deriv2_mul_log {x : ℝ} (hx : x ≠ 0) : deriv^[2] (fun x ↦ x * log x) x = x⁻¹ := by
  

Proof state:
x : ℝ
hx : x ≠ 0
⊢ deriv^[2] (fun x => x * log x) x = x⁻¹

Next tactic:
simp only [Function.iterate_succ, Function.iterate_zero, Function.comp.left_id,
    Function.comp_apply]
lemma deriv2_mul_log {x : ℝ} (hx : x ≠ 0) : deriv^[2] (fun x ↦ x * log x) x = x⁻¹ := by
  simp only [Function.iterate_succ, Function.iterate_zero, Function.comp.left_id,
    Function.comp_apply]
  

Proof state:
x : ℝ
hx : x ≠ 0
⊢ deriv (deriv fun x => x * log x) x = x⁻¹

Next tactic:
suffices ∀ᶠ y in (𝓝 x), deriv (fun x ↦ x * log x) y = log y + 1 by
    refine (Filter.EventuallyEq.deriv_eq this).trans ?_
    rw [deriv_add_const, deriv_log x]
lemma deriv2_mul_log {x : ℝ} (hx : x ≠ 0) : deriv^[2] (fun x ↦ x * log x) x = x⁻¹ := by
  simp only [Function.iterate_succ, Function.iterate_zero, Function.comp.left_id,
    Function.comp_apply]
  suffices ∀ᶠ y in (𝓝 x), deriv (fun x ↦ x * log x) y = log y + 1 by
    

Proof state:
x : ℝ
hx : x ≠ 0
this : ∀ᶠ (y : ℝ) in 𝓝 x, deriv (fun x => x * log x) y = log y + 1
⊢ deriv (deriv fun x => x * log x) x = x⁻¹

Next tactic:
refine (Filter.EventuallyEq.deriv_eq this).trans ?_
lemma deriv2_mul_log {x : ℝ} (hx : x ≠ 0) : deriv^[2] (fun x ↦ x * log x) x = x⁻¹ := by
  simp only [Function.iterate_succ, Function.iterate_zero, Function.comp.left_id,
    Function.comp_apply]
  suffices ∀ᶠ y in (𝓝 x), deriv (fun x ↦ x * log x) y = log y + 1 by
    refine (Filter.EventuallyEq.deriv_eq this).trans ?_
    

Proof state:
x : ℝ
hx : x ≠ 0
this : ∀ᶠ (y : ℝ) in 𝓝 x, deriv (fun x => x * log x) y = log y + 1
⊢ deriv (fun x => log x + 1) x = x⁻¹

Next tactic:
rw [deriv_add_const, deriv_log x]
lemma deriv2_mul_log {x : ℝ} (hx : x ≠ 0) : deriv^[2] (fun x ↦ x * log x) x = x⁻¹ := by
  simp only [Function.iterate_succ, Function.iterate_zero, Function.comp.left_id,
    Function.comp_apply]
  suffices ∀ᶠ y in (𝓝 x), deriv (fun x ↦ x * log x) y = log y + 1 by
    refine (Filter.EventuallyEq.deriv_eq this).trans ?_
    rw [deriv_add_const, deriv_log x]
  

Proof state:
x : ℝ
hx : x ≠ 0
⊢ ∀ᶠ (y : ℝ) in 𝓝 x, deriv (fun x => x * log x) y = log y + 1

Next tactic:
filter_upwards [eventually_ne_nhds hx] with y hy using deriv_mul_log hy
lemma strictConvexOn_mul_log : StrictConvexOn ℝ (Set.Ici (0 : ℝ)) (fun x ↦ x * log x) := by
  

Proof state:
⊢ StrictConvexOn ℝ (Set.Ici 0) fun x => x * log x

Next tactic:
refine strictConvexOn_of_deriv2_pos (convex_Ici 0) (continuous_mul_log.continuousOn) ?_
lemma strictConvexOn_mul_log : StrictConvexOn ℝ (Set.Ici (0 : ℝ)) (fun x ↦ x * log x) := by
  refine strictConvexOn_of_deriv2_pos (convex_Ici 0) (continuous_mul_log.continuousOn) ?_
  

Proof state:
⊢ ∀ x ∈ interior (Set.Ici 0), 0 < deriv^[2] (fun x => x * log x) x

Next tactic:
intro x hx
lemma strictConvexOn_mul_log : StrictConvexOn ℝ (Set.Ici (0 : ℝ)) (fun x ↦ x * log x) := by
  refine strictConvexOn_of_deriv2_pos (convex_Ici 0) (continuous_mul_log.continuousOn) ?_
  intro x hx
  

Proof state:
x : ℝ
hx : x ∈ interior (Set.Ici 0)
⊢ 0 < deriv^[2] (fun x => x * log x) x

Next tactic:
simp only [Set.nonempty_Iio, interior_Ici', Set.mem_Ioi] at hx
lemma strictConvexOn_mul_log : StrictConvexOn ℝ (Set.Ici (0 : ℝ)) (fun x ↦ x * log x) := by
  refine strictConvexOn_of_deriv2_pos (convex_Ici 0) (continuous_mul_log.continuousOn) ?_
  intro x hx
  simp only [Set.nonempty_Iio, interior_Ici', Set.mem_Ioi] at hx
  

Proof state:
x : ℝ
hx : 0 < x
⊢ 0 < deriv^[2] (fun x => x * log x) x

Next tactic:
rw [deriv2_mul_log hx.ne']
lemma strictConvexOn_mul_log : StrictConvexOn ℝ (Set.Ici (0 : ℝ)) (fun x ↦ x * log x) := by
  refine strictConvexOn_of_deriv2_pos (convex_Ici 0) (continuous_mul_log.continuousOn) ?_
  intro x hx
  simp only [Set.nonempty_Iio, interior_Ici', Set.mem_Ioi] at hx
  rw [deriv2_mul_log hx.ne']
  

Proof state:
x : ℝ
hx : 0 < x
⊢ 0 < x⁻¹

Next tactic:
positivity
lemma negMulLog_eq_neg : negMulLog = fun x ↦ - (x * log x) := by 

Proof state:
⊢ negMulLog = fun x => -(x * log x)

Next tactic:
simp [negMulLog_def]
@[simp] lemma negMulLog_zero : negMulLog (0 : ℝ) = 0 := by 

Proof state:
⊢ negMulLog 0 = 0

Next tactic:
simp [negMulLog]
@[simp] lemma negMulLog_one : negMulLog (1 : ℝ) = 0 := by 

Proof state:
⊢ negMulLog 1 = 0

Next tactic:
simp [negMulLog]
lemma negMulLog_nonneg {x : ℝ} (h1 : 0 ≤ x) (h2 : x ≤ 1) : 0 ≤ negMulLog x := by
  

Proof state:
x : ℝ
h1 : 0 ≤ x
h2 : x ≤ 1
⊢ 0 ≤ negMulLog x

Next tactic:
simpa only [negMulLog_eq_neg, neg_nonneg] using mul_log_nonpos h1 h2
lemma negMulLog_mul (x y : ℝ) : negMulLog (x * y) = y * negMulLog x + x * negMulLog y := by
  

Proof state:
x y : ℝ
⊢ negMulLog (x * y) = y * negMulLog x + x * negMulLog y

Next tactic:
simp only [negMulLog, neg_mul, neg_add_rev]
lemma negMulLog_mul (x y : ℝ) : negMulLog (x * y) = y * negMulLog x + x * negMulLog y := by
  simp only [negMulLog, neg_mul, neg_add_rev]
  

Proof state:
x y : ℝ
⊢ -(x * y * log (x * y)) = y * -(x * log x) + x * -(y * log y)

Next tactic:
by_cases hx : x = 0
lemma negMulLog_mul (x y : ℝ) : negMulLog (x * y) = y * negMulLog x + x * negMulLog y := by
  simp only [negMulLog, neg_mul, neg_add_rev]
  by_cases hx : x = 0
  · 

Proof state:
case pos
x y : ℝ
hx : x = 0
⊢ -(x * y * log (x * y)) = y * -(x * log x) + x * -(y * log y)

Next tactic:
simp [hx]
lemma negMulLog_mul (x y : ℝ) : negMulLog (x * y) = y * negMulLog x + x * negMulLog y := by
  simp only [negMulLog, neg_mul, neg_add_rev]
  by_cases hx : x = 0
  · simp [hx]
  

Proof state:
case neg
x y : ℝ
hx : ¬x = 0
⊢ -(x * y * log (x * y)) = y * -(x * log x) + x * -(y * log y)

Next tactic:
by_cases hy : y = 0
lemma negMulLog_mul (x y : ℝ) : negMulLog (x * y) = y * negMulLog x + x * negMulLog y := by
  simp only [negMulLog, neg_mul, neg_add_rev]
  by_cases hx : x = 0
  · simp [hx]
  by_cases hy : y = 0
  · 

Proof state:
case pos
x y : ℝ
hx : ¬x = 0
hy : y = 0
⊢ -(x * y * log (x * y)) = y * -(x * log x) + x * -(y * log y)

Next tactic:
simp [hy]
lemma negMulLog_mul (x y : ℝ) : negMulLog (x * y) = y * negMulLog x + x * negMulLog y := by
  simp only [negMulLog, neg_mul, neg_add_rev]
  by_cases hx : x = 0
  · simp [hx]
  by_cases hy : y = 0
  · simp [hy]
  

Proof state:
case neg
x y : ℝ
hx : ¬x = 0
hy : ¬y = 0
⊢ -(x * y * log (x * y)) = y * -(x * log x) + x * -(y * log y)

Next tactic:
rw [log_mul hx hy]
lemma negMulLog_mul (x y : ℝ) : negMulLog (x * y) = y * negMulLog x + x * negMulLog y := by
  simp only [negMulLog, neg_mul, neg_add_rev]
  by_cases hx : x = 0
  · simp [hx]
  by_cases hy : y = 0
  · simp [hy]
  rw [log_mul hx hy]
  

Proof state:
case neg
x y : ℝ
hx : ¬x = 0
hy : ¬y = 0
⊢ -(x * y * (log x + log y)) = y * -(x * log x) + x * -(y * log y)

Next tactic:
ring
lemma continuous_negMulLog : Continuous negMulLog := by
  

Proof state:
⊢ Continuous negMulLog

Next tactic:
simpa only [negMulLog_eq_neg] using continuous_mul_log.neg
lemma differentiableOn_negMulLog : DifferentiableOn ℝ negMulLog {0}ᶜ := by
  

Proof state:
⊢ DifferentiableOn ℝ negMulLog {0}ᶜ

Next tactic:
simpa only [negMulLog_eq_neg] using differentiableOn_mul_log.neg
lemma deriv_negMulLog {x : ℝ} (hx : x ≠ 0) : deriv negMulLog x = - log x - 1 := by
  

Proof state:
x : ℝ
hx : x ≠ 0
⊢ deriv negMulLog x = -log x - 1

Next tactic:
rw [negMulLog_eq_neg, deriv.neg, deriv_mul_log hx]
lemma deriv_negMulLog {x : ℝ} (hx : x ≠ 0) : deriv negMulLog x = - log x - 1 := by
  rw [negMulLog_eq_neg, deriv.neg, deriv_mul_log hx]
  

Proof state:
x : ℝ
hx : x ≠ 0
⊢ -(log x + 1) = -log x - 1

Next tactic:
ring
lemma hasDerivAt_negMulLog {x : ℝ} (hx : x ≠ 0) : HasDerivAt negMulLog (- log x - 1) x := by
  

Proof state:
x : ℝ
hx : x ≠ 0
⊢ HasDerivAt negMulLog (-log x - 1) x

Next tactic:
rw [← deriv_negMulLog hx, hasDerivAt_deriv_iff]
lemma hasDerivAt_negMulLog {x : ℝ} (hx : x ≠ 0) : HasDerivAt negMulLog (- log x - 1) x := by
  rw [← deriv_negMulLog hx, hasDerivAt_deriv_iff]
  

Proof state:
x : ℝ
hx : x ≠ 0
⊢ DifferentiableAt ℝ negMulLog x

Next tactic:
refine DifferentiableOn.differentiableAt differentiableOn_negMulLog ?_
lemma hasDerivAt_negMulLog {x : ℝ} (hx : x ≠ 0) : HasDerivAt negMulLog (- log x - 1) x := by
  rw [← deriv_negMulLog hx, hasDerivAt_deriv_iff]
  refine DifferentiableOn.differentiableAt differentiableOn_negMulLog ?_
  

Proof state:
x : ℝ
hx : x ≠ 0
⊢ {0}ᶜ ∈ 𝓝 x

Next tactic:
simp [hx]
lemma deriv2_negMulLog {x : ℝ} (hx : x ≠ 0) : deriv^[2] negMulLog x = - x⁻¹ := by
  

Proof state:
x : ℝ
hx : x ≠ 0
⊢ deriv^[2] negMulLog x = -x⁻¹

Next tactic:
rw [negMulLog_eq_neg]
lemma deriv2_negMulLog {x : ℝ} (hx : x ≠ 0) : deriv^[2] negMulLog x = - x⁻¹ := by
  rw [negMulLog_eq_neg]
  

Proof state:
x : ℝ
hx : x ≠ 0
⊢ deriv^[2] (fun x => -(x * log x)) x = -x⁻¹

Next tactic:
have h := deriv2_mul_log hx
lemma deriv2_negMulLog {x : ℝ} (hx : x ≠ 0) : deriv^[2] negMulLog x = - x⁻¹ := by
  rw [negMulLog_eq_neg]
  have h := deriv2_mul_log hx
  

Proof state:
x : ℝ
hx : x ≠ 0
h : deriv^[2] (fun x => x * log x) x = x⁻¹
⊢ deriv^[2] (fun x => -(x * log x)) x = -x⁻¹

Next tactic:
simp only [Function.iterate_succ, Function.iterate_zero, Function.comp.left_id,
    Function.comp_apply, deriv.neg', differentiableAt_id', differentiableAt_log_iff, ne_eq] at h ⊢
lemma deriv2_negMulLog {x : ℝ} (hx : x ≠ 0) : deriv^[2] negMulLog x = - x⁻¹ := by
  rw [negMulLog_eq_neg]
  have h := deriv2_mul_log hx
  simp only [Function.iterate_succ, Function.iterate_zero, Function.comp.left_id,
    Function.comp_apply, deriv.neg', differentiableAt_id', differentiableAt_log_iff, ne_eq] at h ⊢
  

Proof state:
x : ℝ
hx : x ≠ 0
h : deriv (deriv fun x => x * log x) x = x⁻¹
⊢ -deriv (fun y => deriv (fun y => y * log y) y) x = -x⁻¹

Next tactic:
rw [h]
lemma strictConcaveOn_negMulLog : StrictConcaveOn ℝ (Set.Ici (0 : ℝ)) negMulLog := by
  

Proof state:
⊢ StrictConcaveOn ℝ (Set.Ici 0) negMulLog

Next tactic:
simpa only [negMulLog_eq_neg] using strictConvexOn_mul_log.neg
/-- We show that the presheaf of functions to a type `T`
(no continuity assumptions, just plain functions)
form a sheaf.

In fact, the proof is identical when we do this for dependent functions to a type family `T`,
so we do the more general case.
-/
theorem toTypes_isSheaf (T : X → Type u) : (presheafToTypes X T).IsSheaf :=
  isSheaf_of_isSheafUniqueGluing_types.{u} _ fun ι U sf hsf => by
  -- We use the sheaf condition in terms of unique gluing
  -- U is a family of open sets, indexed by `ι` and `sf` is a compatible family of sections.
  -- In the informal comments below, I'll just write `U` to represent the union.
    -- Our first goal is to define a function "lifted" to all of `U`.
    -- We do this one point at a time. Using the axiom of choice, we can pick for each
    -- `x : ↑(iSup U)` an index `i : ι` such that `x` lies in `U i`
    

Proof state:
X : TopCat
T : ↑X → Type u
ι : Type u
U : ι → Opens ↑X
sf : (i : ι) → (forget (Type u)).obj ((presheafToTypes X T).obj (Opposite.op (U i)))
hsf : IsCompatible (presheafToTypes X T) U sf
⊢ ∃! s, IsGluing (presheafToTypes X T) U sf s

Next tactic:
choose index index_spec using fun x : ↑(iSup U) => Opens.mem_iSup.mp x.2
/-- We show that the presheaf of functions to a type `T`
(no continuity assumptions, just plain functions)
form a sheaf.

In fact, the proof is identical when we do this for dependent functions to a type family `T`,
so we do the more general case.
-/
theorem toTypes_isSheaf (T : X → Type u) : (presheafToTypes X T).IsSheaf :=
  isSheaf_of_isSheafUniqueGluing_types.{u} _ fun ι U sf hsf => by
  -- We use the sheaf condition in terms of unique gluing
  -- U is a family of open sets, indexed by `ι` and `sf` is a compatible family of sections.
  -- In the informal comments below, I'll just write `U` to represent the union.
    -- Our first goal is to define a function "lifted" to all of `U`.
    -- We do this one point at a time. Using the axiom of choice, we can pick for each
    -- `x : ↑(iSup U)` an index `i : ι` such that `x` lies in `U i`
    choose index index_spec using fun x : ↑(iSup U) => Opens.mem_iSup.mp x.2
    -- Using this data, we can glue our functions together to a single section
    

Proof state:
X : TopCat
T : ↑X → Type u
ι : Type u
U : ι → Opens ↑X
sf : (i : ι) → (forget (Type u)).obj ((presheafToTypes X T).obj (Opposite.op (U i)))
hsf : IsCompatible (presheafToTypes X T) U sf
index : ↥(iSup U) → ι
index_spec : ∀ (x : ↥(iSup U)), ↑x ∈ U (index x)
⊢ ∃! s, IsGluing (presheafToTypes X T) U sf s

Next tactic:
let s : ∀ x : ↑(iSup U), T x := fun x => sf (index x) ⟨x.1, index_spec x⟩
/-- We show that the presheaf of functions to a type `T`
(no continuity assumptions, just plain functions)
form a sheaf.

In fact, the proof is identical when we do this for dependent functions to a type family `T`,
so we do the more general case.
-/
theorem toTypes_isSheaf (T : X → Type u) : (presheafToTypes X T).IsSheaf :=
  isSheaf_of_isSheafUniqueGluing_types.{u} _ fun ι U sf hsf => by
  -- We use the sheaf condition in terms of unique gluing
  -- U is a family of open sets, indexed by `ι` and `sf` is a compatible family of sections.
  -- In the informal comments below, I'll just write `U` to represent the union.
    -- Our first goal is to define a function "lifted" to all of `U`.
    -- We do this one point at a time. Using the axiom of choice, we can pick for each
    -- `x : ↑(iSup U)` an index `i : ι` such that `x` lies in `U i`
    choose index index_spec using fun x : ↑(iSup U) => Opens.mem_iSup.mp x.2
    -- Using this data, we can glue our functions together to a single section
    let s : ∀ x : ↑(iSup U), T x := fun x => sf (index x) ⟨x.1, index_spec x⟩
    

Proof state:
X : TopCat
T : ↑X → Type u
ι : Type u
U : ι → Opens ↑X
sf : (i : ι) → (forget (Type u)).obj ((presheafToTypes X T).obj (Opposite.op (U i)))
hsf : IsCompatible (presheafToTypes X T) U sf
index : ↥(iSup U) → ι
index_spec : ∀ (x : ↥(iSup U)), ↑x ∈ U (index x)
s : (x : ↥(iSup U)) → T ↑x := fun x => sf (index x) { val := ↑x, property := (_ : ↑x ∈ U (index x)) }
⊢ ∃! s, IsGluing (presheafToTypes X T) U sf s

Next tactic:
refine' ⟨s, _, _⟩