Skip to content

Commit e75bdf0

Browse files
committed
feat(Arctan): add more simp lemmas (#27719)
Also add some `positivity` extensions.
1 parent 40704ea commit e75bdf0

File tree

2 files changed

+134
-25
lines changed

2 files changed

+134
-25
lines changed

Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean

Lines changed: 125 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,27 @@ The result of `arctan x + arctan y` is given by `arctan_add`, `arctan_add_eq_add
2121

2222
noncomputable section
2323

24-
namespace Real
25-
2624
open Set Filter
25+
open scoped Topology
2726

28-
open scoped Topology Real
27+
namespace Real
2928

30-
theorem tan_add {x y : ℝ}
29+
variable {x y : ℝ}
30+
31+
theorem tan_add
3132
(h : ((∀ k : ℤ, x ≠ (2 * k + 1) * π / 2) ∧ ∀ l : ℤ, y ≠ (2 * l + 1) * π / 2) ∨
3233
(∃ k : ℤ, x = (2 * k + 1) * π / 2) ∧ ∃ l : ℤ, y = (2 * l + 1) * π / 2) :
3334
tan (x + y) = (tan x + tan y) / (1 - tan x * tan y) := by
3435
simpa only [← Complex.ofReal_inj, Complex.ofReal_sub, Complex.ofReal_add, Complex.ofReal_div,
3536
Complex.ofReal_mul, Complex.ofReal_tan] using
3637
@Complex.tan_add (x : ℂ) (y : ℂ) (by convert h <;> norm_cast)
3738

38-
theorem tan_add' {x y : ℝ}
39+
theorem tan_add'
3940
(h : (∀ k : ℤ, x ≠ (2 * k + 1) * π / 2) ∧ ∀ l : ℤ, y ≠ (2 * l + 1) * π / 2) :
4041
tan (x + y) = (tan x + tan y) / (1 - tan x * tan y) :=
4142
tan_add (Or.inl h)
4243

43-
theorem tan_two_mul {x : ℝ} : tan (2 * x) = 2 * tan x / (1 - tan x ^ 2) := by
44+
theorem tan_two_mul : tan (2 * x) = 2 * tan x / (1 - tan x ^ 2) := by
4445
have := @Complex.tan_two_mul x
4546
norm_cast at *
4647

@@ -110,7 +111,7 @@ theorem arctan_mem_Ioo (x : ℝ) : arctan x ∈ Ioo (-(π / 2)) (π / 2) :=
110111
theorem range_arctan : range arctan = Ioo (-(π / 2)) (π / 2) :=
111112
((EquivLike.surjective _).range_comp _).trans Subtype.range_coe
112113

113-
theorem arctan_tan {x : ℝ} (hx₁ : -(π / 2) < x) (hx₂ : x < π / 2) : arctan (tan x) = x :=
114+
theorem arctan_tan (hx₁ : -(π / 2) < x) (hx₂ : x < π / 2) : arctan (tan x) = x :=
114115
Subtype.ext_iff.1 <| tanOrderIso.symm_apply_apply ⟨x, hx₁, hx₂⟩
115116

116117
theorem cos_arctan_pos (x : ℝ) : 0 < cos (arctan x) :=
@@ -134,7 +135,7 @@ theorem neg_pi_div_two_lt_arctan (x : ℝ) : -(π / 2) < arctan x :=
134135
theorem arctan_eq_arcsin (x : ℝ) : arctan x = arcsin (x / √(1 + x ^ 2)) :=
135136
Eq.symm <| arcsin_eq_of_sin_eq (sin_arctan x) (mem_Icc_of_Ioo <| arctan_mem_Ioo x)
136137

137-
theorem arcsin_eq_arctan {x : ℝ} (h : x ∈ Ioo (-(1 : ℝ)) 1) :
138+
theorem arcsin_eq_arctan (h : x ∈ Ioo (-(1 : ℝ)) 1) :
138139
arcsin x = arctan (x / √(1 - x ^ 2)) := by
139140
rw_mod_cast [arctan_eq_arcsin, div_pow, sq_sqrt, one_add_div, div_div, ← sqrt_mul,
140141
mul_div_cancel₀, sub_add_cancel, sqrt_one, div_one] <;> simp at h <;> nlinarith [h.1, h.2]
@@ -145,17 +146,28 @@ theorem arctan_zero : arctan 0 = 0 := by simp [arctan_eq_arcsin]
145146
@[mono]
146147
theorem arctan_strictMono : StrictMono arctan := tanOrderIso.symm.strictMono
147148

149+
theorem arctan_mono : Monotone arctan := arctan_strictMono.monotone
150+
148151
@[gcongr]
149-
lemma arctan_lt_arctan {x y : ℝ} (hxy : x < y) : arctan x < arctan y := arctan_strictMono hxy
152+
lemma arctan_lt_arctan (hxy : x < y) : arctan x < arctan y := arctan_strictMono hxy
153+
154+
@[simp]
155+
theorem arctan_lt_arctan_iff : arctan x < arctan y ↔ x < y := arctan_strictMono.lt_iff_lt
150156

151157
@[gcongr]
152-
lemma arctan_le_arctan {x y : ℝ} (hxy : x ≤ y) : arctan x ≤ arctan y :=
158+
lemma arctan_le_arctan (hxy : x ≤ y) : arctan x ≤ arctan y :=
153159
arctan_strictMono.monotone hxy
154160

161+
@[simp]
162+
theorem arctan_le_arctan_iff : arctan x ≤ arctan y ↔ x ≤ y := arctan_strictMono.le_iff_le
163+
155164
theorem arctan_injective : arctan.Injective := arctan_strictMono.injective
156165

157166
@[simp]
158-
theorem arctan_eq_zero_iff {x : ℝ} : arctan x = 0 ↔ x = 0 :=
167+
theorem arctan_inj : arctan x = arctan y ↔ x = y := arctan_injective.eq_iff
168+
169+
@[simp]
170+
theorem arctan_eq_zero_iff : arctan x = 0 ↔ x = 0 :=
159171
.trans (by rw [arctan_zero]) arctan_injective.eq_iff
160172

161173
theorem tendsto_arctan_atTop : Tendsto arctan atTop (𝓝[<] (π / 2)) :=
@@ -164,62 +176,85 @@ theorem tendsto_arctan_atTop : Tendsto arctan atTop (𝓝[<] (π / 2)) :=
164176
theorem tendsto_arctan_atBot : Tendsto arctan atBot (𝓝[>] (-(π / 2))) :=
165177
tendsto_Ioo_atBot.mp tanOrderIso.symm.tendsto_atBot
166178

167-
theorem arctan_eq_of_tan_eq {x y : ℝ} (h : tan x = y) (hx : x ∈ Ioo (-(π / 2)) (π / 2)) :
179+
theorem arctan_eq_of_tan_eq (h : tan x = y) (hx : x ∈ Ioo (-(π / 2)) (π / 2)) :
168180
arctan y = x :=
169181
injOn_tan (arctan_mem_Ioo _) hx (by rw [tan_arctan, h])
170182

171183
@[simp]
172184
theorem arctan_one : arctan 1 = π / 4 :=
173185
arctan_eq_of_tan_eq tan_pi_div_four <| by constructor <;> linarith [pi_pos]
174186

187+
@[simp]
188+
theorem arctan_eq_pi_div_four : arctan x = π / 4 ↔ x = 1 := arctan_injective.eq_iff' arctan_one
189+
175190
@[simp]
176191
theorem arctan_neg (x : ℝ) : arctan (-x) = -arctan x := by simp [arctan_eq_arcsin, neg_div]
177192

178-
theorem arctan_eq_arccos {x : ℝ} (h : 0 ≤ x) : arctan x = arccos (√(1 + x ^ 2))⁻¹ := by
193+
@[simp]
194+
theorem arctan_eq_neg_pi_div_four : arctan x = -(π / 4) ↔ x = -1 :=
195+
arctan_injective.eq_iff' <| by rw [arctan_neg, arctan_one]
196+
197+
@[simp]
198+
theorem arctan_pos : 0 < arctan x ↔ 0 < x := by
199+
simpa only [arctan_zero] using arctan_lt_arctan_iff (x := 0)
200+
201+
@[simp]
202+
theorem arctan_lt_zero : arctan x < 0 ↔ x < 0 := by
203+
simpa only [arctan_zero] using arctan_lt_arctan_iff (y := 0)
204+
205+
@[simp]
206+
theorem arctan_nonneg : 0 ≤ arctan x ↔ 0 ≤ x := by
207+
simpa only [arctan_zero] using arctan_le_arctan_iff (x := 0)
208+
209+
@[simp]
210+
theorem arctan_le_zero : arctan x ≤ 0 ↔ x ≤ 0 := by
211+
simpa only [arctan_zero] using arctan_le_arctan_iff (y := 0)
212+
213+
theorem arctan_eq_arccos (h : 0 ≤ x) : arctan x = arccos (√(1 + x ^ 2))⁻¹ := by
179214
rw [arctan_eq_arcsin, arccos_eq_arcsin]; swap; · exact inv_nonneg.2 (sqrt_nonneg _)
180215
congr 1
181216
rw_mod_cast [← sqrt_inv, sq_sqrt, ← one_div, one_sub_div, add_sub_cancel_left, sqrt_div,
182217
sqrt_sq h]
183218
all_goals positivity
184219

185220
-- The junk values for `arccos` and `sqrt` make this true even for `1 < x`.
186-
theorem arccos_eq_arctan {x : ℝ} (h : 0 < x) : arccos x = arctan (√(1 - x ^ 2) / x) := by
221+
theorem arccos_eq_arctan (h : 0 < x) : arccos x = arctan (√(1 - x ^ 2) / x) := by
187222
rw [arccos, eq_comm]
188223
refine arctan_eq_of_tan_eq ?_ ⟨?_, ?_⟩
189224
· rw_mod_cast [tan_pi_div_two_sub, tan_arcsin, inv_div]
190225
· linarith only [arcsin_le_pi_div_two x, pi_pos]
191226
· linarith only [arcsin_pos.2 h]
192227

193-
theorem arctan_inv_of_pos {x : ℝ} (h : 0 < x) : arctan x⁻¹ = π / 2 - arctan x := by
228+
theorem arctan_inv_of_pos (h : 0 < x) : arctan x⁻¹ = π / 2 - arctan x := by
194229
rw [← arctan_tan (x := _ - _), tan_pi_div_two_sub, tan_arctan]
195230
· norm_num
196231
exact (arctan_lt_pi_div_two x).trans (half_lt_self_iff.mpr pi_pos)
197232
· rw [sub_lt_self_iff, ← arctan_zero]
198233
exact tanOrderIso.symm.strictMono h
199234

200-
theorem arctan_inv_of_neg {x : ℝ} (h : x < 0) : arctan x⁻¹ = -(π / 2) - arctan x := by
235+
theorem arctan_inv_of_neg (h : x < 0) : arctan x⁻¹ = -(π / 2) - arctan x := by
201236
have := arctan_inv_of_pos (neg_pos.mpr h)
202237
rwa [inv_neg, arctan_neg, neg_eq_iff_eq_neg, neg_sub', arctan_neg, neg_neg] at this
203238

204239
section ArctanAdd
205240

206-
lemma arctan_ne_mul_pi_div_two {x : ℝ} : ∀ (k : ℤ), arctan x ≠ (2 * k + 1) * π / 2 := by
241+
lemma arctan_ne_mul_pi_div_two : ∀ (k : ℤ), arctan x ≠ (2 * k + 1) * π / 2 := by
207242
by_contra!
208243
obtain ⟨k, h⟩ := this
209244
obtain ⟨lb, ub⟩ := arctan_mem_Ioo x
210245
rw [h, neg_eq_neg_one_mul, mul_div_assoc, mul_lt_mul_right (by positivity)] at lb
211246
rw [h, ← one_mul (π / 2), mul_div_assoc, mul_lt_mul_right (by positivity)] at ub
212247
norm_cast at lb ub; change -1 < _ at lb; omega
213248

214-
lemma arctan_add_arctan_lt_pi_div_two {x y : ℝ} (h : x * y < 1) : arctan x + arctan y < π / 2 := by
249+
lemma arctan_add_arctan_lt_pi_div_two (h : x * y < 1) : arctan x + arctan y < π / 2 := by
215250
rcases le_or_gt y 0 with hy | hy
216251
· rw [← add_zero (π / 2), ← arctan_zero]
217252
exact add_lt_add_of_lt_of_le (arctan_lt_pi_div_two _) (tanOrderIso.symm.monotone hy)
218253
· rw [← lt_div_iff₀ hy, ← inv_eq_one_div] at h
219254
replace h : arctan x < arctan y⁻¹ := tanOrderIso.symm.strictMono h
220255
rwa [arctan_inv_of_pos hy, lt_tsub_iff_right] at h
221256

222-
theorem arctan_add {x y : ℝ} (h : x * y < 1) :
257+
theorem arctan_add (h : x * y < 1) :
223258
arctan x + arctan y = arctan ((x + y) / (1 - x * y)) := by
224259
rw [← arctan_tan (x := _ + _)]
225260
· congr
@@ -230,7 +265,7 @@ theorem arctan_add {x y : ℝ} (h : x * y < 1) :
230265
exact arctan_add_arctan_lt_pi_div_two h
231266
· exact arctan_add_arctan_lt_pi_div_two h
232267

233-
theorem arctan_add_eq_add_pi {x y : ℝ} (h : 1 < x * y) (hx : 0 < x) :
268+
theorem arctan_add_eq_add_pi (h : 1 < x * y) (hx : 0 < x) :
234269
arctan x + arctan y = arctan ((x + y) / (1 - x * y)) + π := by
235270
have hy : 0 < y := by
236271
have := mul_pos_iff.mp (zero_lt_one.trans h)
@@ -242,23 +277,23 @@ theorem arctan_add_eq_add_pi {x y : ℝ} (h : 1 < x * y) (hx : 0 < x) :
242277
field_simp
243278
rw [show -x + -y = -(x + y) by ring, show x * y - 1 = -(1 - x * y) by ring, neg_div_neg_eq]
244279

245-
theorem arctan_add_eq_sub_pi {x y : ℝ} (h : 1 < x * y) (hx : x < 0) :
280+
theorem arctan_add_eq_sub_pi (h : 1 < x * y) (hx : x < 0) :
246281
arctan x + arctan y = arctan ((x + y) / (1 - x * y)) - π := by
247282
rw [← neg_mul_neg] at h
248283
have k := arctan_add_eq_add_pi h (neg_pos.mpr hx)
249284
rw [show _ / _ = -((x + y) / (1 - x * y)) by ring, ← neg_inj] at k
250285
simp only [arctan_neg, neg_add, neg_neg, ← sub_eq_add_neg _ π] at k
251286
exact k
252287

253-
theorem two_mul_arctan {x : ℝ} (h₁ : -1 < x) (h₂ : x < 1) :
288+
theorem two_mul_arctan (h₁ : -1 < x) (h₂ : x < 1) :
254289
2 * arctan x = arctan (2 * x / (1 - x ^ 2)) := by
255290
rw [two_mul, arctan_add (by nlinarith)]; congr 1; ring
256291

257-
theorem two_mul_arctan_add_pi {x : ℝ} (h : 1 < x) :
292+
theorem two_mul_arctan_add_pi (h : 1 < x) :
258293
2 * arctan x = arctan (2 * x / (1 - x ^ 2)) + π := by
259294
rw [two_mul, arctan_add_eq_add_pi (by nlinarith) (by linarith)]; congr 2; ring
260295

261-
theorem two_mul_arctan_sub_pi {x : ℝ} (h : x < -1) :
296+
theorem two_mul_arctan_sub_pi (h : x < -1) :
262297
2 * arctan x = arctan (2 * x / (1 - x ^ 2)) - π := by
263298
rw [two_mul, arctan_add_eq_sub_pi (by nlinarith) (by linarith)]; congr 2; ring
264299

@@ -278,11 +313,35 @@ theorem four_mul_arctan_inv_5_sub_arctan_inv_239 : 4 * arctan 5⁻¹ - arctan 23
278313

279314
end ArctanAdd
280315

316+
theorem sin_arctan_strictMono : StrictMono (sin <| arctan ·) := fun x y h ↦
317+
strictMonoOn_sin (Ioo_subset_Icc_self <| arctan_mem_Ioo x)
318+
(Ioo_subset_Icc_self <| arctan_mem_Ioo y) (arctan_strictMono h)
319+
320+
@[simp]
321+
theorem sin_arctan_pos : 0 < sin (arctan x) ↔ 0 < x := by
322+
simpa using sin_arctan_strictMono.lt_iff_lt (a := 0)
323+
324+
@[simp]
325+
theorem sin_arctan_lt_zero : sin (arctan x) < 0 ↔ x < 0 := by
326+
simpa using sin_arctan_strictMono.lt_iff_lt (b := 0)
327+
328+
@[simp]
329+
theorem sin_arctan_eq_zero : sin (arctan x) = 0 ↔ x = 0 :=
330+
sin_arctan_strictMono.injective.eq_iff' <| by simp
331+
332+
@[simp]
333+
theorem sin_arctan_nonneg : 0 ≤ sin (arctan x) ↔ 0 ≤ x := by
334+
simpa using sin_arctan_strictMono.le_iff_le (a := 0)
335+
336+
@[simp]
337+
theorem sin_arctan_le_zero : sin (arctan x) ≤ 0 ↔ x ≤ 0 := by
338+
simpa using sin_arctan_strictMono.le_iff_le (b := 0)
339+
281340
@[continuity]
282341
theorem continuous_arctan : Continuous arctan :=
283342
continuous_subtype_val.comp tanOrderIso.toHomeomorph.continuous_invFun
284343

285-
theorem continuousAt_arctan {x : ℝ} : ContinuousAt arctan x :=
344+
theorem continuousAt_arctan : ContinuousAt arctan x :=
286345
continuous_arctan.continuousAt
287346

288347
/-- `Real.tan` as a `PartialHomeomorph` between `(-(π / 2), π / 2)` and the whole line. -/
@@ -309,3 +368,44 @@ theorem coe_tanPartialHomeomorph_symm : ⇑tanPartialHomeomorph.symm = arctan :=
309368
rfl
310369

311370
end Real
371+
372+
namespace Mathlib.Meta.Positivity
373+
open Lean Meta Qq
374+
375+
/-- Extension for `Real.arctan`. -/
376+
@[positivity Real.arctan _]
377+
def evalRealArctan : PositivityExt where eval {u α} z p e := do
378+
match u, α, e with
379+
| 0, ~q(ℝ), ~q(Real.arctan $a) =>
380+
let ra ← core z p a
381+
assumeInstancesCommute
382+
match ra with
383+
| .positive pa => return .positive q(Real.arctan_pos.mpr $pa)
384+
| .nonnegative na => return .nonnegative q(Real.arctan_nonneg.mpr $na)
385+
| .nonzero na => return .nonzero q(mt Real.arctan_eq_zero_iff.mp $na)
386+
| .none => return .none
387+
| _ => throwError "not Real.arctan"
388+
389+
/-- Extension for `Real.cos (Real.arctan _)`. -/
390+
@[positivity Real.cos (Real.arctan _)]
391+
def evalRealCosArctan : PositivityExt where eval {u α} _ _ e := do
392+
match u, α, e with
393+
| 0, ~q(ℝ), ~q(Real.cos (Real.arctan $a)) =>
394+
assumeInstancesCommute
395+
return .positive q(Real.cos_arctan_pos _)
396+
| _ => throwError "not Real.cos (Real.arctan _)"
397+
398+
/-- Extension for `Real.sin (Real.arctan _)`. -/
399+
@[positivity Real.sin (Real.arctan _)]
400+
def evalRealSinArctan : PositivityExt where eval {u α} z p e := do
401+
match u, α, e with
402+
| 0, ~q(ℝ), ~q(Real.sin (Real.arctan $a)) =>
403+
assumeInstancesCommute
404+
match ← core z p a with
405+
| .positive pa => return .positive q(Real.sin_arctan_pos.mpr $pa)
406+
| .nonnegative na => return .nonnegative q(Real.sin_arctan_nonneg.mpr $na)
407+
| .nonzero na => return .nonzero q(mt Real.sin_arctan_eq_zero.mp $na)
408+
| .none => return .none
409+
| _ => throwError "not Real.sin (Real.arctan _)"
410+
411+
end Mathlib.Meta.Positivity

MathlibTest/positivity.lean

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Mathlib.Data.ENNReal.Basic
55
import Mathlib.Analysis.Normed.Group.Basic
66
import Mathlib.Analysis.SpecialFunctions.Pow.Real
77
import Mathlib.Analysis.SpecialFunctions.Log.Basic
8+
import Mathlib.Analysis.SpecialFunctions.Trigonometric.Arctan
89
import Mathlib.MeasureTheory.Integral.Bochner.Basic
910
import Mathlib.Topology.Algebra.InfiniteSum.Order
1011

@@ -419,6 +420,14 @@ example : 0 ≤ Real.log 1 := by positivity
419420
example : 0 ≤ Real.log 0 := by positivity
420421
example : 0 ≤ Real.log (-1) := by positivity
421422

423+
example : 0 < Real.arctan 1.1 := by positivity
424+
example {r : ℝ} (hr : 0 ≤ r) : 0 ≤ Real.arctan r := by positivity
425+
example {r : ℝ} (hr : r ≠ 0) : Real.arctan r ≠ 0 := by positivity
426+
example (r : ℝ) : 0 < Real.cos (Real.arctan r) := by positivity
427+
example {r : ℝ} (hr : 0 < r) : 0 < Real.sin (Real.arctan r) := by positivity
428+
example {r : ℝ} (hr : r ≠ 0) : Real.sin (Real.arctan r) ≠ 0 := by positivity
429+
example {r : ℝ} (hr : 0 ≤ r) : 0 ≤ Real.sin (Real.arctan r) := by positivity
430+
422431
end SpecialFunctions
423432

424433
/-! ### `sqrt` on `ℝ` and `ℝ≥0` -/

0 commit comments

Comments
 (0)