Skip to content

Commit 846cbab

Browse files
committed
feat(analysis/calculus): let simp compute derivatives (leanprover-community#2422)
After this PR: ```lean example (x : ℝ) : deriv (λ x, cos (sin x) * exp x) x = (cos(sin(x))-sin(sin(x))*cos(x))*exp(x) := by { simp, ring } ``` Excerpts from the docstrings: The simplifier is set up to prove automatically that some functions are differentiable, or differentiable at a point (but not differentiable on a set or within a set at a point, as checking automatically that the good domains are mapped one to the other when using composition is not something the simplifier can easily do). This means that one can write `example (x : ℝ) : differentiable ℝ (λ x, sin (exp (3 + x^2)) - 5 * cos x) := by simp`. If there are divisions, one needs to supply to the simplifier proofs that the denominators do not vanish, as in ```lean example (x : ℝ) (h : 1 + sin x ≠ 0) : differentiable_at ℝ (λ x, exp x / (1 + sin x)) x := by simp [h] ``` The simplifier is not set up to compute the Fréchet derivative of maps (as these are in general complicated multidimensional linear maps), but it will compute one-dimensional derivatives. To make sure that the simplifier can prove automatically that functions are differentiable, we tag many lemmas with the `simp` attribute, for instance those saying that the sum of differentiable functions is differentiable, as well as their product, their cartesian product, and so on. A notable exception is the chain rule: we do not mark as a simp lemma the fact that, if `f` and `g` are differentiable, then their composition also is: `simp` would always be able to match this lemma, by taking `f` or `g` to be the identity. Instead, for every reasonable function (say, `exp`), we add a lemma that if `f` is differentiable then so is `(λ x, exp (f x))`. This means adding some boilerplate lemmas, but these can also be useful in their own right. Tests for this ability of the simplifier (with more examples) are provided in `tests/differentiable.lean`.
1 parent ec80061 commit 846cbab

File tree

5 files changed

+622
-35
lines changed

5 files changed

+622
-35
lines changed

src/analysis/calculus/deriv.lean

+97-7
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,20 @@ For most binary operations we also define `const_op` and `op_const` theorems for
5757
the first or second argument is a constant. This makes writing chains of `has_deriv_at`'s easier,
5858
and they more frequently lead to the desired result.
5959
60+
We set up the simplifier so that it can compute the derivative of simple functions. For instance,
61+
```lean
62+
example (x : ℝ) : deriv (λ x, cos (sin x) * exp x) x = (cos(sin(x))-sin(sin(x))*cos(x))*exp(x) :=
63+
by { simp, ring }
64+
```
65+
6066
## Implementation notes
6167
6268
Most of the theorems are direct restatements of the corresponding theorems
6369
for Fréchet derivatives.
6470
71+
The strategy to construct simp lemmas that give the simplifier the possibility to compute
72+
derivatives is the same as the one for differentiability statements, as explained in `fderiv.lean`.
73+
See the explanations there.
6574
-/
6675

6776
universes u v w
@@ -374,12 +383,18 @@ has_deriv_at_filter_id _ _
374383
theorem has_deriv_at_id : has_deriv_at id 1 x :=
375384
has_deriv_at_filter_id _ _
376385

386+
theorem has_deriv_at_id' : has_deriv_at (λ (x : 𝕜), x) 1 x :=
387+
has_deriv_at_filter_id _ _
388+
377389
lemma deriv_id : deriv id x = 1 :=
378390
has_deriv_at.deriv (has_deriv_at_id x)
379391

380392
@[simp] lemma deriv_id' : deriv (@id 𝕜) = λ _, 1 :=
381393
funext deriv_id
382394

395+
@[simp] lemma deriv_id'' : deriv (λ x : 𝕜, x) x = 1 :=
396+
deriv_id x
397+
383398
lemma deriv_within_id (hxs : unique_diff_within_at 𝕜 s x) : deriv_within id s x = 1 :=
384399
by { unfold deriv_within, rw fderiv_within_id, simp, assumption }
385400

@@ -476,7 +491,7 @@ lemma deriv_within_add (hxs : unique_diff_within_at 𝕜 s x)
476491
deriv_within (λy, f y + g y) s x = deriv_within f s x + deriv_within g s x :=
477492
(hf.has_deriv_within_at.add hg.has_deriv_within_at).deriv_within hxs
478493

479-
lemma deriv_add
494+
@[simp] lemma deriv_add
480495
(hf : differentiable_at 𝕜 f x) (hg : differentiable_at 𝕜 g x) :
481496
deriv (λy, f y + g y) x = deriv f x + deriv g x :=
482497
(hf.has_deriv_at.add hg.has_deriv_at).deriv
@@ -663,7 +678,7 @@ lemma deriv_within_sub (hxs : unique_diff_within_at 𝕜 s x)
663678
deriv_within (λy, f y - g y) s x = deriv_within f s x - deriv_within g s x :=
664679
(hf.has_deriv_within_at.sub hg.has_deriv_within_at).deriv_within hxs
665680

666-
lemma deriv_sub
681+
@[simp] lemma deriv_sub
667682
(hf : differentiable_at 𝕜 f x) (hg : differentiable_at 𝕜 g x) :
668683
deriv (λ y, f y - g y) x = deriv f x - deriv g x :=
669684
(hf.has_deriv_at.sub hg.has_deriv_at).deriv
@@ -958,7 +973,7 @@ lemma deriv_within_mul (hxs : unique_diff_within_at 𝕜 s x)
958973
deriv_within (λ y, c y * d y) s x = deriv_within c s x * d x + c x * deriv_within d s x :=
959974
(hc.has_deriv_within_at.mul hd.has_deriv_within_at).deriv_within hxs
960975

961-
lemma deriv_mul (hc : differentiable_at 𝕜 c x) (hd : differentiable_at 𝕜 d x) :
976+
@[simp] lemma deriv_mul (hc : differentiable_at 𝕜 c x) (hd : differentiable_at 𝕜 d x) :
962977
deriv (λ y, c y * d y) x = deriv c x * d x + c x * deriv d x :=
963978
(hc.has_deriv_at.mul hd.has_deriv_at).deriv
964979

@@ -1099,6 +1114,48 @@ begin
10991114
exact fderiv_inv x_ne_zero
11001115
end
11011116

1117+
variables {c : 𝕜 → 𝕜} {c' : 𝕜}
1118+
1119+
lemma has_deriv_within_at.inv
1120+
(hc : has_deriv_within_at c c' s x) (hx : c x ≠ 0) :
1121+
has_deriv_within_at (λ y, (c y)⁻¹) (- c' / (c x)^2) s x :=
1122+
begin
1123+
convert (has_deriv_at_inv hx).comp_has_deriv_within_at x hc,
1124+
field_simp
1125+
end
1126+
1127+
lemma has_deriv_at.inv (hc : has_deriv_at c c' x) (hx : c x ≠ 0) :
1128+
has_deriv_at (λ y, (c y)⁻¹) (- c' / (c x)^2) x :=
1129+
begin
1130+
rw ← has_deriv_within_at_univ at *,
1131+
exact hc.inv hx
1132+
end
1133+
1134+
lemma differentiable_within_at.inv (hc : differentiable_within_at 𝕜 c s x) (hx : c x ≠ 0) :
1135+
differentiable_within_at 𝕜 (λx, (c x)⁻¹) s x :=
1136+
(hc.has_deriv_within_at.inv hx).differentiable_within_at
1137+
1138+
@[simp] lemma differentiable_at.inv (hc : differentiable_at 𝕜 c x) (hx : c x ≠ 0) :
1139+
differentiable_at 𝕜 (λx, (c x)⁻¹) x :=
1140+
(hc.has_deriv_at.inv hx).differentiable_at
1141+
1142+
lemma differentiable_on.inv (hc : differentiable_on 𝕜 c s) (hx : ∀ x ∈ s, c x ≠ 0) :
1143+
differentiable_on 𝕜 (λx, (c x)⁻¹) s :=
1144+
λx h, (hc x h).inv (hx x h)
1145+
1146+
@[simp] lemma differentiable.inv (hc : differentiable 𝕜 c) (hx : ∀ x, c x ≠ 0) :
1147+
differentiable 𝕜 (λx, (c x)⁻¹) :=
1148+
λx, (hc x).inv (hx x)
1149+
1150+
lemma deriv_within_inv' (hc : differentiable_within_at 𝕜 c s x) (hx : c x ≠ 0)
1151+
(hxs : unique_diff_within_at 𝕜 s x) :
1152+
deriv_within (λx, (c x)⁻¹) s x = - (deriv_within c s x) / (c x)^2 :=
1153+
(hc.has_deriv_within_at.inv hx).deriv_within hxs
1154+
1155+
@[simp] lemma deriv_inv' (hc : differentiable_at 𝕜 c x) (hx : c x ≠ 0) :
1156+
deriv (λx, (c x)⁻¹) x = - (deriv c x) / (c x)^2 :=
1157+
(hc.has_deriv_at.inv hx).deriv
1158+
11021159
end inverse
11031160

11041161
section division
@@ -1129,7 +1186,7 @@ lemma differentiable_within_at.div
11291186
differentiable_within_at 𝕜 (λx, c x / d x) s x :=
11301187
((hc.has_deriv_within_at).div (hd.has_deriv_within_at) hx).differentiable_within_at
11311188

1132-
lemma differentiable_at.div
1189+
@[simp] lemma differentiable_at.div
11331190
(hc : differentiable_at 𝕜 c x) (hd : differentiable_at 𝕜 d x) (hx : d x ≠ 0) :
11341191
differentiable_at 𝕜 (λx, c x / d x) x :=
11351192
((hc.has_deriv_at).div (hd.has_deriv_at) hx).differentiable_at
@@ -1139,7 +1196,7 @@ lemma differentiable_on.div
11391196
differentiable_on 𝕜 (λx, c x / d x) s :=
11401197
λx h, (hc x h).div (hd x h) (hx x h)
11411198

1142-
lemma differentiable.div
1199+
@[simp] lemma differentiable.div
11431200
(hc : differentiable 𝕜 c) (hd : differentiable 𝕜 d) (hx : ∀ x, d x ≠ 0) :
11441201
differentiable 𝕜 (λx, c x / d x) :=
11451202
λx, (hc x).div (hd x) (hx x)
@@ -1151,7 +1208,7 @@ lemma deriv_within_div
11511208
= ((deriv_within c s x) * d x - c x * (deriv_within d s x)) / (d x)^2 :=
11521209
((hc.has_deriv_within_at).div (hd.has_deriv_within_at) hx).deriv_within hxs
11531210

1154-
lemma deriv_div
1211+
@[simp] lemma deriv_div
11551212
(hc : differentiable_at 𝕜 c x) (hd : differentiable_at 𝕜 d x) (hx : d x ≠ 0) :
11561213
deriv (λx, c x / d x) x = ((deriv c x) * d x - c x * (deriv d x)) / (d x)^2 :=
11571214
((hc.has_deriv_at).div (hd.has_deriv_at) hx).deriv
@@ -1239,7 +1296,7 @@ end polynomial
12391296

12401297
section pow
12411298
/-! ### Derivative of `x ↦ x^n` for `n : ℕ` -/
1242-
variables {x : 𝕜} {s : set 𝕜}
1299+
variables {x : 𝕜} {s : set 𝕜} {c : 𝕜 → 𝕜} {c' : 𝕜}
12431300
variable {n : ℕ }
12441301

12451302
lemma has_deriv_at_pow (n : ℕ) (x : 𝕜) : has_deriv_at (λx, x^n) ((n : 𝕜) * x^(n-1)) x :=
@@ -1290,6 +1347,39 @@ lemma iter_deriv_pow {k : ℕ} :
12901347
deriv^[k] (λx:𝕜, x^n) x = ((finset.range k).prod (λ i, n - i):ℕ) * x^(n-k) :=
12911348
congr_fun iter_deriv_pow' x
12921349

1350+
lemma has_deriv_within_at.pow (hc : has_deriv_within_at c c' s x) :
1351+
has_deriv_within_at (λ y, (c y)^n) ((n : 𝕜) * (c x)^(n-1) * c') s x :=
1352+
(has_deriv_at_pow n (c x)).comp_has_deriv_within_at x hc
1353+
1354+
lemma has_deriv_at.pow (hc : has_deriv_at c c' x) :
1355+
has_deriv_at (λ y, (c y)^n) ((n : 𝕜) * (c x)^(n-1) * c') x :=
1356+
by { rw ← has_deriv_within_at_univ at *, exact hc.pow }
1357+
1358+
lemma differentiable_within_at.pow (hc : differentiable_within_at 𝕜 c s x) :
1359+
differentiable_within_at 𝕜 (λx, (c x)^n) s x :=
1360+
hc.has_deriv_within_at.pow.differentiable_within_at
1361+
1362+
@[simp] lemma differentiable_at.pow (hc : differentiable_at 𝕜 c x) :
1363+
differentiable_at 𝕜 (λx, (c x)^n) x :=
1364+
hc.has_deriv_at.pow.differentiable_at
1365+
1366+
lemma differentiable_on.pow (hc : differentiable_on 𝕜 c s) :
1367+
differentiable_on 𝕜 (λx, (c x)^n) s :=
1368+
λx h, (hc x h).pow
1369+
1370+
@[simp] lemma differentiable.pow (hc : differentiable 𝕜 c) :
1371+
differentiable 𝕜 (λx, (c x)^n) :=
1372+
λx, (hc x).pow
1373+
1374+
lemma deriv_within_pow' (hc : differentiable_within_at 𝕜 c s x)
1375+
(hxs : unique_diff_within_at 𝕜 s x) :
1376+
deriv_within (λx, (c x)^n) s x = (n : 𝕜) * (c x)^(n-1) * (deriv_within c s x) :=
1377+
hc.has_deriv_within_at.pow.deriv_within hxs
1378+
1379+
@[simp] lemma deriv_pow'' (hc : differentiable_at 𝕜 c x) :
1380+
deriv (λx, (c x)^n) x = (n : 𝕜) * (c x)^(n-1) * (deriv c x) :=
1381+
hc.has_deriv_at.pow.deriv
1382+
12931383
end pow
12941384

12951385
section fpow

0 commit comments

Comments
 (0)