Skip to content

Commit 0749ef1

Browse files
committed
feat(push): push annotations for Real.log (leanprover-community#30039)
This PR adds `push` annotations, and tests for `Real.log`. It also updates the `#push` and `#pull` commands so that they can take a discharger, and can take any head.
1 parent ae8e527 commit 0749ef1

4 files changed

Lines changed: 57 additions & 19 deletions

File tree

Mathlib/Analysis/SpecialFunctions/Log/Basic.lean

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ theorem le_exp_log (x : ℝ) : x ≤ exp (log x) := by
7070
· rw [exp_log_eq_abs h_zero]
7171
exact le_abs_self _
7272

73-
@[simp]
73+
@[simp, push]
7474
theorem log_exp (x : ℝ) : log (exp x) = x :=
7575
exp_injective <| exp_log (exp_pos x)
7676

@@ -96,25 +96,25 @@ theorem log_surjective : Surjective log := fun x => ⟨exp x, log_exp x⟩
9696
theorem range_log : range log = univ :=
9797
log_surjective.range_eq
9898

99-
@[simp]
99+
@[simp, push]
100100
theorem log_zero : log 0 = 0 :=
101101
dif_pos rfl
102102

103-
@[simp]
103+
@[simp, push]
104104
theorem log_one : log 1 = 0 :=
105105
exp_injective <| by rw [exp_log zero_lt_one, exp_zero]
106106

107107
/-- This holds true for all `x : ℝ` because of the junk values `0 / 0 = 0` and `log 0 = 0`. -/
108108
@[simp] lemma log_div_self (x : ℝ) : log (x / x) = 0 := by
109109
obtain rfl | hx := eq_or_ne x 0 <;> simp [*]
110110

111-
@[simp]
111+
@[simp, push]
112112
theorem log_abs (x : ℝ) : log |x| = log x := by
113113
by_cases h : x = 0
114114
· simp [h]
115115
· rw [← exp_eq_exp, exp_log_eq_abs h, exp_log_eq_abs (abs_pos.2 h).ne', abs_abs]
116116

117-
@[simp]
117+
@[simp, push]
118118
theorem log_neg_eq_log (x : ℝ) : log (-x) = log x := by rw [← log_abs x, ← log_abs (-x), abs_neg]
119119

120120
theorem sinh_log {x : ℝ} (hx : 0 < x) : sinh (log x) = (x - x⁻¹) / 2 := by
@@ -126,15 +126,17 @@ theorem cosh_log {x : ℝ} (hx : 0 < x) : cosh (log x) = (x + x⁻¹) / 2 := by
126126
theorem surjOn_log' : SurjOn log (Iio 0) univ := fun x _ =>
127127
⟨-exp x, neg_lt_zero.2 <| exp_pos x, by rw [log_neg_eq_log, log_exp]⟩
128128

129+
@[push]
129130
theorem log_mul (hx : x ≠ 0) (hy : y ≠ 0) : log (x * y) = log x + log y :=
130131
exp_injective <| by
131132
rw [exp_log_eq_abs (mul_ne_zero hx hy), exp_add, exp_log_eq_abs hx, exp_log_eq_abs hy, abs_mul]
132133

134+
@[push]
133135
theorem log_div (hx : x ≠ 0) (hy : y ≠ 0) : log (x / y) = log x - log y :=
134136
exp_injective <| by
135137
rw [exp_log_eq_abs (div_ne_zero hx hy), exp_sub, exp_log_eq_abs hx, exp_log_eq_abs hy, abs_div]
136138

137-
@[simp]
139+
@[simp, push]
138140
theorem log_inv (x : ℝ) : log x⁻¹ = -log x := by
139141
by_cases hx : x = 0; · simp [hx]
140142
rw [← exp_eq_exp, exp_log_eq_abs (inv_ne_zero hx), exp_neg, exp_log_eq_abs hx, abs_inv]
@@ -267,7 +269,7 @@ theorem log_eq_zero {x : ℝ} : log x = 0 ↔ x = 0 ∨ x = 1 ∨ x = -1 := by
267269
theorem log_ne_zero {x : ℝ} : log x ≠ 0 ↔ x ≠ 0 ∧ x ≠ 1 ∧ x ≠ -1 := by
268270
simpa only [not_or] using log_eq_zero.not
269271

270-
@[simp]
272+
@[simp, push]
271273
theorem log_pow (x : ℝ) (n : ℕ) : log (x ^ n) = n * log x := by
272274
induction n with
273275
| zero => simp
@@ -276,12 +278,13 @@ theorem log_pow (x : ℝ) (n : ℕ) : log (x ^ n) = n * log x := by
276278
· simp
277279
· rw [pow_succ, log_mul (pow_ne_zero _ hx) hx, ih, Nat.cast_succ, add_mul, one_mul]
278280

279-
@[simp]
281+
@[simp, push]
280282
theorem log_zpow (x : ℝ) (n : ℤ) : log (x ^ n) = n * log x := by
281283
cases n
282284
· rw [Int.ofNat_eq_natCast, zpow_natCast, log_pow, Int.cast_natCast]
283285
· rw [zpow_negSucc, log_inv, log_pow, Int.cast_negSucc, Nat.cast_add_one, neg_mul_eq_neg_mul]
284286

287+
@[push]
285288
theorem log_sqrt {x : ℝ} (hx : 0 ≤ x) : log (√x) = log x / 2 := by
286289
rw [eq_div_iff, mul_comm, ← Nat.cast_two, ← log_pow, sq_sqrt hx]
287290
exact two_ne_zero
@@ -375,11 +378,13 @@ lemma log_multiset_prod {s : Multiset ℝ} (h : ∀ x ∈ s, x ≠ 0) :
375378
rw [← prod_toList, log_list_prod (by simp_all), sum_map_toList]
376379

377380
open Finset in
381+
@[push]
378382
theorem log_prod {α : Type*} {s : Finset α} {f : α → ℝ} (hf : ∀ x ∈ s, f x ≠ 0) :
379383
log (∏ i ∈ s, f i) = ∑ i ∈ s, log (f i) := by
380384
rw [← prod_map_toList, log_list_prod (by simp_all)]
381385
simp
382386

387+
@[push]
383388
protected theorem _root_.Finsupp.log_prod {α β : Type*} [Zero β] (f : α →₀ β) (g : α → β → ℝ)
384389
(hg : ∀ a, g a (f a) = 0 → f a = 0) : log (f.prod g) = f.sum fun a b ↦ log (g a b) :=
385390
log_prod fun _x hx h₀ ↦ Finsupp.mem_support_iff.1 hx <| hg _ h₀

Mathlib/Analysis/SpecialFunctions/Pow/Real.lean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,9 @@ theorem inv_rpow (hx : 0 ≤ x) (y : ℝ) : x⁻¹ ^ y = (x ^ y)⁻¹ := by
477477
theorem div_rpow (hx : 0 ≤ x) (hy : 0 ≤ y) (z : ℝ) : (x / y) ^ z = x ^ z / y ^ z := by
478478
simp only [div_eq_mul_inv, mul_rpow hx (inv_nonneg.2 hy), inv_rpow hy]
479479

480+
@[push low] /- Lower priority than `log_pow` and `log_zpow`.
481+
This is because otherwise the `pull` tactic will use `log_rpow` in places where it should
482+
use `log_pow` or `log_zpow`. -/
480483
theorem log_rpow {x : ℝ} (hx : 0 < x) (y : ℝ) : log (x ^ y) = y * log x := by
481484
apply exp_injective
482485
rw [exp_log (rpow_pos_of_pos hx y), ← exp_log hx, mul_comm, rpow_def_of_pos (exp_pos (log x)) y]

Mathlib/Tactic/Push.lean

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -317,17 +317,18 @@ which will print the `push head` form of `e`.
317317
318318
`#push` understands local variables, so you can use them to introduce parameters.
319319
-/
320-
macro (name := pushCommand) tk:"#push " cfg:optConfig head:ident ppSpace e:term : command =>
321-
`(command| #conv%$tk push $cfg $head:ident => $e)
320+
macro (name := pushCommand) tk:"#push" cfg:optConfig disch?:(discharger)? ppSpace head:term " => "
321+
e:term : command =>
322+
`(command| #conv%$tk push $cfg $[$disch?:discharger]? $head:term => $e)
322323

323324
/--
324325
The syntax is `#push_neg e`, where `e` is an expression,
325326
which will print the `push_neg` form of `e`.
326327
327328
`#push_neg` understands local variables, so you can use them to introduce parameters.
328329
-/
329-
macro (name := pushNegCommand) tk:"#push_neg " cfg:optConfig e:term : command =>
330-
`(command| #push%$tk $cfg Not $e)
330+
macro (name := pushNegCommand) tk:"#push_neg" cfg:optConfig ppSpace e:term : command =>
331+
`(command| #push%$tk $cfg Not => $e)
331332

332333
@[inherit_doc pull]
333334
elab "pull" disch?:(discharger)? head:(ppSpace colGt term) : conv => withMainContext do
@@ -341,8 +342,9 @@ which will print the `pull head` form of `e`.
341342
342343
`#pull` understands local variables, so you can use them to introduce parameters.
343344
-/
344-
macro (name := pullCommand) tk:"#pull " head:ident ppSpace e:term : command =>
345-
`(command| #conv%$tk pull $head:ident => $e)
345+
macro (name := pullCommand) tk:"#pull" disch?:(discharger)? ppSpace head:term " => " e:term :
346+
command =>
347+
`(command| #conv%$tk pull $[$disch?:discharger]? $head:term => $e)
346348

347349
end Conv
348350

MathlibTest/push.lean

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Mathlib.Tactic.Push
22
import Mathlib.Data.Nat.Cast.Basic
33
import Mathlib.Data.Set.Basic
44
import Mathlib.Data.Set.Insert
5-
import Mathlib.Analysis.SpecialFunctions.Log.Basic
5+
import Mathlib.Analysis.SpecialFunctions.Pow.Real
66

77
private axiom test_sorry : ∀ {α}, α
88

@@ -12,15 +12,15 @@ variable {p q r : Prop}
1212

1313
/-- info: (q ∧ (p ∨ q)) ∧ r ∧ (p ∨ r) -/
1414
#guard_msgs in
15-
#push Or False ∧ p ∨ q ∧ r
15+
#push _ ∨ _ => False ∧ p ∨ q ∧ r
1616

1717
/-- info: (p ∨ q) ∧ (p ∨ r) -/
1818
#guard_msgs in
19-
#push Or (p ∨ q) ∧ (p ∨ r)
19+
#push _ ∨ _ => (p ∨ q) ∧ (p ∨ r)
2020

2121
/-- info: (p ∧ q ∨ q) ∨ p ∧ r ∨ r -/
2222
#guard_msgs in
23-
#push And (p ∨ True) ∧ (q ∨ r)
23+
#push _ ∧ _ => (p ∨ True) ∧ (q ∨ r)
2424

2525
example {r : ℕ → Prop} : ∀ n : ℕ, p ∨ r n ∧ q ∧ n = 1 := by
2626
push ∀ n, _
@@ -38,7 +38,7 @@ example {r : ℕ → Prop} : ∃ n : ℕ, p ∨ r n ∨ q ∧ n = 1 := by
3838

3939
/-- info: p ∨ ∃ x, q ∧ x = 1 -/
4040
#guard_msgs in
41-
#pull Exists p ∨ q ∧ ∃ n : ℕ, n = 1
41+
#pull ∃ _, _ => p ∨ q ∧ ∃ n : ℕ, n = 1
4242

4343
/--
4444
info: DiscrTree branch for Or:
@@ -73,3 +73,31 @@ example : (fun x : ℕ ↦ x ^ 2 + 1 * 0 - 5 • 6) = id ^ 2 + 1 * 0 - 5 • 6 :
7373
simp only [pullFun]
7474

7575
end lambda
76+
77+
section log
78+
79+
example (a b : ℝ) (ha : 0 < a) (hb : 0 < b) : Real.log (a * b) = Real.log a + Real.log b := by
80+
pull (disch := positivity) Real.log
81+
rfl
82+
83+
variable (a b c : Real) (ha : 0 < a) (hc : 0 < c)
84+
85+
/-- info: ↑4 * Real.log a + -Real.log c - b * Real.log a + b -/
86+
#guard_msgs in
87+
#push (disch := positivity) Real.log => Real.log (a ^ 4 * c⁻¹ / a ^ b * Real.exp b)
88+
89+
/-- info: ∑ i ∈ Finset.Ioo 0 5, Real.log ↑i -/
90+
#guard_msgs in
91+
#push (disch := simp <;> grind) Real.log => Real.log (∏ i ∈ Finset.Ioo 0 5, (i : Nat))
92+
93+
set_option pp.numericTypes true in
94+
/-- info: Real.log (a ^ (4 : ℝ) * c⁻¹ / a ^ b) + b -/
95+
#guard_msgs in
96+
#pull (disch := positivity) Real.log => 4 * Real.log a + -Real.log c - b * Real.log a + b
97+
98+
set_option pp.numericTypes true in
99+
/-- info: Real.log (a ^ (4 : ℕ) * c⁻¹ / a ^ b) + b -/
100+
#guard_msgs in
101+
#pull (disch := positivity) Real.log => (4 : Nat) * Real.log a + -Real.log c - b * Real.log a + b
102+
103+
end log

0 commit comments

Comments
 (0)