-
Notifications
You must be signed in to change notification settings - Fork 257
/
Comp.lean
269 lines (211 loc) · 13.1 KB
/
Comp.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/-
Copyright (c) 2019 Gabriel Ebner. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Gabriel Ebner, Sébastien Gouëzel, Yury Kudryashov, Yuyang Zhao
-/
import Mathlib.Analysis.Calculus.Deriv.Basic
import Mathlib.Analysis.Calculus.FDeriv.Comp
import Mathlib.Analysis.Calculus.FDeriv.RestrictScalars
#align_import analysis.calculus.deriv.comp from "leanprover-community/mathlib"@"3bce8d800a6f2b8f63fe1e588fd76a9ff4adcebe"
/-!
# One-dimensional derivatives of compositions of functions
In this file we prove the chain rule for the following cases:
* `HasDerivAt.comp` etc: `f : 𝕜' → 𝕜'` composed with `g : 𝕜 → 𝕜'`;
* `HasDerivAt.scomp` etc: `f : 𝕜' → E` composed with `g : 𝕜 → 𝕜'`;
* `HasFDerivAt.comp_hasDerivAt` etc: `f : E → F` composed with `g : 𝕜 → E`;
Here `𝕜` is the base normed field, `E` and `F` are normed spaces over `𝕜` and `𝕜'` is an algebra
over `𝕜` (e.g., `𝕜'=𝕜` or `𝕜=ℝ`, `𝕜'=ℂ`).
For a more detailed overview of one-dimensional derivatives in mathlib, see the module docstring of
`analysis/calculus/deriv/basic`.
## Keywords
derivative, chain rule
-/
universe u v w
open scoped Classical
open Topology BigOperators Filter ENNReal
open Filter Asymptotics Set
open ContinuousLinearMap (smulRight smulRight_one_eq_iff)
variable {𝕜 : Type u} [NontriviallyNormedField 𝕜]
variable {F : Type v} [NormedAddCommGroup F] [NormedSpace 𝕜 F]
variable {E : Type w} [NormedAddCommGroup E] [NormedSpace 𝕜 E]
variable {f f₀ f₁ g : 𝕜 → F}
variable {f' f₀' f₁' g' : F}
variable {x : 𝕜}
variable {s t : Set 𝕜}
variable {L L₁ L₂ : Filter 𝕜}
section Composition
/-!
### Derivative of the composition of a vector function and a scalar function
We use `scomp` in lemmas on composition of vector valued and scalar valued functions, and `comp`
in lemmas on composition of scalar valued functions, in analogy for `smul` and `mul` (and also
because the `comp` version with the shorter name will show up much more often in applications).
The formula for the derivative involves `smul` in `scomp` lemmas, which can be reduced to
usual multiplication in `comp` lemmas.
-/
/- For composition lemmas, we put x explicit to help the elaborator, as otherwise Lean tends to
get confused since there are too many possibilities for composition -/
variable {𝕜' : Type*} [NontriviallyNormedField 𝕜'] [NormedAlgebra 𝕜 𝕜'] [NormedSpace 𝕜' F]
[IsScalarTower 𝕜 𝕜' F] {s' t' : Set 𝕜'} {h : 𝕜 → 𝕜'} {h₁ : 𝕜 → 𝕜} {h₂ : 𝕜' → 𝕜'} {h' h₂' : 𝕜'}
{h₁' : 𝕜} {g₁ : 𝕜' → F} {g₁' : F} {L' : Filter 𝕜'} (x)
theorem HasDerivAtFilter.scomp (hg : HasDerivAtFilter g₁ g₁' (h x) L')
(hh : HasDerivAtFilter h h' x L) (hL : Tendsto h L L') :
HasDerivAtFilter (g₁ ∘ h) (h' • g₁') x L := by
simpa using ((hg.restrictScalars 𝕜).comp x hh hL).hasDerivAtFilter
#align has_deriv_at_filter.scomp HasDerivAtFilter.scomp
theorem HasDerivWithinAt.scomp_hasDerivAt (hg : HasDerivWithinAt g₁ g₁' s' (h x))
(hh : HasDerivAt h h' x) (hs : ∀ x, h x ∈ s') : HasDerivAt (g₁ ∘ h) (h' • g₁') x :=
hg.scomp x hh <| tendsto_inf.2 ⟨hh.continuousAt, tendsto_principal.2 <| eventually_of_forall hs⟩
#align has_deriv_within_at.scomp_has_deriv_at HasDerivWithinAt.scomp_hasDerivAt
nonrec theorem HasDerivWithinAt.scomp (hg : HasDerivWithinAt g₁ g₁' t' (h x))
(hh : HasDerivWithinAt h h' s x) (hst : MapsTo h s t') :
HasDerivWithinAt (g₁ ∘ h) (h' • g₁') s x :=
hg.scomp x hh <| hh.continuousWithinAt.tendsto_nhdsWithin hst
#align has_deriv_within_at.scomp HasDerivWithinAt.scomp
/-- The chain rule. -/
nonrec theorem HasDerivAt.scomp (hg : HasDerivAt g₁ g₁' (h x)) (hh : HasDerivAt h h' x) :
HasDerivAt (g₁ ∘ h) (h' • g₁') x :=
hg.scomp x hh hh.continuousAt
#align has_deriv_at.scomp HasDerivAt.scomp
theorem HasStrictDerivAt.scomp (hg : HasStrictDerivAt g₁ g₁' (h x)) (hh : HasStrictDerivAt h h' x) :
HasStrictDerivAt (g₁ ∘ h) (h' • g₁') x := by
simpa using ((hg.restrictScalars 𝕜).comp x hh).hasStrictDerivAt
#align has_strict_deriv_at.scomp HasStrictDerivAt.scomp
theorem HasDerivAt.scomp_hasDerivWithinAt (hg : HasDerivAt g₁ g₁' (h x))
(hh : HasDerivWithinAt h h' s x) : HasDerivWithinAt (g₁ ∘ h) (h' • g₁') s x :=
HasDerivWithinAt.scomp x hg.hasDerivWithinAt hh (mapsTo_univ _ _)
#align has_deriv_at.scomp_has_deriv_within_at HasDerivAt.scomp_hasDerivWithinAt
theorem derivWithin.scomp (hg : DifferentiableWithinAt 𝕜' g₁ t' (h x))
(hh : DifferentiableWithinAt 𝕜 h s x) (hs : MapsTo h s t') (hxs : UniqueDiffWithinAt 𝕜 s x) :
derivWithin (g₁ ∘ h) s x = derivWithin h s x • derivWithin g₁ t' (h x) :=
(HasDerivWithinAt.scomp x hg.hasDerivWithinAt hh.hasDerivWithinAt hs).derivWithin hxs
#align deriv_within.scomp derivWithin.scomp
theorem deriv.scomp (hg : DifferentiableAt 𝕜' g₁ (h x)) (hh : DifferentiableAt 𝕜 h x) :
deriv (g₁ ∘ h) x = deriv h x • deriv g₁ (h x) :=
(HasDerivAt.scomp x hg.hasDerivAt hh.hasDerivAt).deriv
#align deriv.scomp deriv.scomp
/-! ### Derivative of the composition of a scalar and vector functions -/
theorem HasDerivAtFilter.comp_hasFDerivAtFilter {f : E → 𝕜'} {f' : E →L[𝕜] 𝕜'} (x) {L'' : Filter E}
(hh₂ : HasDerivAtFilter h₂ h₂' (f x) L') (hf : HasFDerivAtFilter f f' x L'')
(hL : Tendsto f L'' L') : HasFDerivAtFilter (h₂ ∘ f) (h₂' • f') x L'' := by
convert (hh₂.restrictScalars 𝕜).comp x hf hL
ext x
simp [mul_comm]
#align has_deriv_at_filter.comp_has_fderiv_at_filter HasDerivAtFilter.comp_hasFDerivAtFilter
theorem HasStrictDerivAt.comp_hasStrictFDerivAt {f : E → 𝕜'} {f' : E →L[𝕜] 𝕜'} (x)
(hh : HasStrictDerivAt h₂ h₂' (f x)) (hf : HasStrictFDerivAt f f' x) :
HasStrictFDerivAt (h₂ ∘ f) (h₂' • f') x := by
rw [HasStrictDerivAt] at hh
convert (hh.restrictScalars 𝕜).comp x hf
ext x
simp [mul_comm]
#align has_strict_deriv_at.comp_has_strict_fderiv_at HasStrictDerivAt.comp_hasStrictFDerivAt
theorem HasDerivAt.comp_hasFDerivAt {f : E → 𝕜'} {f' : E →L[𝕜] 𝕜'} (x)
(hh : HasDerivAt h₂ h₂' (f x)) (hf : HasFDerivAt f f' x) : HasFDerivAt (h₂ ∘ f) (h₂' • f') x :=
hh.comp_hasFDerivAtFilter x hf hf.continuousAt
#align has_deriv_at.comp_has_fderiv_at HasDerivAt.comp_hasFDerivAt
theorem HasDerivAt.comp_hasFDerivWithinAt {f : E → 𝕜'} {f' : E →L[𝕜] 𝕜'} {s} (x)
(hh : HasDerivAt h₂ h₂' (f x)) (hf : HasFDerivWithinAt f f' s x) :
HasFDerivWithinAt (h₂ ∘ f) (h₂' • f') s x :=
hh.comp_hasFDerivAtFilter x hf hf.continuousWithinAt
#align has_deriv_at.comp_has_fderiv_within_at HasDerivAt.comp_hasFDerivWithinAt
theorem HasDerivWithinAt.comp_hasFDerivWithinAt {f : E → 𝕜'} {f' : E →L[𝕜] 𝕜'} {s t} (x)
(hh : HasDerivWithinAt h₂ h₂' t (f x)) (hf : HasFDerivWithinAt f f' s x) (hst : MapsTo f s t) :
HasFDerivWithinAt (h₂ ∘ f) (h₂' • f') s x :=
hh.comp_hasFDerivAtFilter x hf <| hf.continuousWithinAt.tendsto_nhdsWithin hst
#align has_deriv_within_at.comp_has_fderiv_within_at HasDerivWithinAt.comp_hasFDerivWithinAt
/-! ### Derivative of the composition of two scalar functions -/
theorem HasDerivAtFilter.comp (hh₂ : HasDerivAtFilter h₂ h₂' (h x) L')
(hh : HasDerivAtFilter h h' x L) (hL : Tendsto h L L') :
HasDerivAtFilter (h₂ ∘ h) (h₂' * h') x L := by
rw [mul_comm]
exact hh₂.scomp x hh hL
#align has_deriv_at_filter.comp HasDerivAtFilter.comp
theorem HasDerivWithinAt.comp (hh₂ : HasDerivWithinAt h₂ h₂' s' (h x))
(hh : HasDerivWithinAt h h' s x) (hst : MapsTo h s s') :
HasDerivWithinAt (h₂ ∘ h) (h₂' * h') s x := by
rw [mul_comm]
exact hh₂.scomp x hh hst
#align has_deriv_within_at.comp HasDerivWithinAt.comp
/-- The chain rule. -/
nonrec theorem HasDerivAt.comp (hh₂ : HasDerivAt h₂ h₂' (h x)) (hh : HasDerivAt h h' x) :
HasDerivAt (h₂ ∘ h) (h₂' * h') x :=
hh₂.comp x hh hh.continuousAt
#align has_deriv_at.comp HasDerivAt.comp
theorem HasStrictDerivAt.comp (hh₂ : HasStrictDerivAt h₂ h₂' (h x)) (hh : HasStrictDerivAt h h' x) :
HasStrictDerivAt (h₂ ∘ h) (h₂' * h') x := by
rw [mul_comm]
exact hh₂.scomp x hh
#align has_strict_deriv_at.comp HasStrictDerivAt.comp
theorem HasDerivAt.comp_hasDerivWithinAt (hh₂ : HasDerivAt h₂ h₂' (h x))
(hh : HasDerivWithinAt h h' s x) : HasDerivWithinAt (h₂ ∘ h) (h₂' * h') s x :=
hh₂.hasDerivWithinAt.comp x hh (mapsTo_univ _ _)
#align has_deriv_at.comp_has_deriv_within_at HasDerivAt.comp_hasDerivWithinAt
theorem derivWithin.comp (hh₂ : DifferentiableWithinAt 𝕜' h₂ s' (h x))
(hh : DifferentiableWithinAt 𝕜 h s x) (hs : MapsTo h s s') (hxs : UniqueDiffWithinAt 𝕜 s x) :
derivWithin (h₂ ∘ h) s x = derivWithin h₂ s' (h x) * derivWithin h s x :=
(hh₂.hasDerivWithinAt.comp x hh.hasDerivWithinAt hs).derivWithin hxs
#align deriv_within.comp derivWithin.comp
theorem deriv.comp (hh₂ : DifferentiableAt 𝕜' h₂ (h x)) (hh : DifferentiableAt 𝕜 h x) :
deriv (h₂ ∘ h) x = deriv h₂ (h x) * deriv h x :=
(hh₂.hasDerivAt.comp x hh.hasDerivAt).deriv
#align deriv.comp deriv.comp
protected nonrec theorem HasDerivAtFilter.iterate {f : 𝕜 → 𝕜} {f' : 𝕜}
(hf : HasDerivAtFilter f f' x L) (hL : Tendsto f L L) (hx : f x = x) (n : ℕ) :
HasDerivAtFilter f^[n] (f' ^ n) x L := by
have := hf.iterate hL hx n
rwa [ContinuousLinearMap.smulRight_one_pow] at this
#align has_deriv_at_filter.iterate HasDerivAtFilter.iterate
protected nonrec theorem HasDerivAt.iterate {f : 𝕜 → 𝕜} {f' : 𝕜} (hf : HasDerivAt f f' x)
(hx : f x = x) (n : ℕ) : HasDerivAt f^[n] (f' ^ n) x :=
hf.iterate _ (have := hf.tendsto_nhds le_rfl; by rwa [hx] at this) hx n
#align has_deriv_at.iterate HasDerivAt.iterate
protected theorem HasDerivWithinAt.iterate {f : 𝕜 → 𝕜} {f' : 𝕜} (hf : HasDerivWithinAt f f' s x)
(hx : f x = x) (hs : MapsTo f s s) (n : ℕ) : HasDerivWithinAt f^[n] (f' ^ n) s x := by
have := HasFDerivWithinAt.iterate hf hx hs n
rwa [ContinuousLinearMap.smulRight_one_pow] at this
#align has_deriv_within_at.iterate HasDerivWithinAt.iterate
protected nonrec theorem HasStrictDerivAt.iterate {f : 𝕜 → 𝕜} {f' : 𝕜}
(hf : HasStrictDerivAt f f' x) (hx : f x = x) (n : ℕ) :
HasStrictDerivAt f^[n] (f' ^ n) x := by
have := hf.iterate hx n
rwa [ContinuousLinearMap.smulRight_one_pow] at this
#align has_strict_deriv_at.iterate HasStrictDerivAt.iterate
end Composition
section CompositionVector
/-! ### Derivative of the composition of a function between vector spaces and a function on `𝕜` -/
open ContinuousLinearMap
variable {l : F → E} {l' : F →L[𝕜] E}
variable (x)
/-- The composition `l ∘ f` where `l : F → E` and `f : 𝕜 → F`, has a derivative within a set
equal to the Fréchet derivative of `l` applied to the derivative of `f`. -/
theorem HasFDerivWithinAt.comp_hasDerivWithinAt {t : Set F} (hl : HasFDerivWithinAt l l' t (f x))
(hf : HasDerivWithinAt f f' s x) (hst : MapsTo f s t) :
HasDerivWithinAt (l ∘ f) (l' f') s x := by
simpa only [one_apply, one_smul, smulRight_apply, coe_comp', (· ∘ ·)] using
(hl.comp x hf.hasFDerivWithinAt hst).hasDerivWithinAt
#align has_fderiv_within_at.comp_has_deriv_within_at HasFDerivWithinAt.comp_hasDerivWithinAt
theorem HasFDerivAt.comp_hasDerivWithinAt (hl : HasFDerivAt l l' (f x))
(hf : HasDerivWithinAt f f' s x) : HasDerivWithinAt (l ∘ f) (l' f') s x :=
hl.hasFDerivWithinAt.comp_hasDerivWithinAt x hf (mapsTo_univ _ _)
#align has_fderiv_at.comp_has_deriv_within_at HasFDerivAt.comp_hasDerivWithinAt
/-- The composition `l ∘ f` where `l : F → E` and `f : 𝕜 → F`, has a derivative equal to the
Fréchet derivative of `l` applied to the derivative of `f`. -/
theorem HasFDerivAt.comp_hasDerivAt (hl : HasFDerivAt l l' (f x)) (hf : HasDerivAt f f' x) :
HasDerivAt (l ∘ f) (l' f') x :=
hasDerivWithinAt_univ.mp <| hl.comp_hasDerivWithinAt x hf.hasDerivWithinAt
#align has_fderiv_at.comp_has_deriv_at HasFDerivAt.comp_hasDerivAt
theorem HasStrictFDerivAt.comp_hasStrictDerivAt (hl : HasStrictFDerivAt l l' (f x))
(hf : HasStrictDerivAt f f' x) : HasStrictDerivAt (l ∘ f) (l' f') x := by
simpa only [one_apply, one_smul, smulRight_apply, coe_comp', (· ∘ ·)] using
(hl.comp x hf.hasStrictFDerivAt).hasStrictDerivAt
#align has_strict_fderiv_at.comp_has_strict_deriv_at HasStrictFDerivAt.comp_hasStrictDerivAt
theorem fderivWithin.comp_derivWithin {t : Set F} (hl : DifferentiableWithinAt 𝕜 l t (f x))
(hf : DifferentiableWithinAt 𝕜 f s x) (hs : MapsTo f s t) (hxs : UniqueDiffWithinAt 𝕜 s x) :
derivWithin (l ∘ f) s x = (fderivWithin 𝕜 l t (f x) : F → E) (derivWithin f s x) :=
(hl.hasFDerivWithinAt.comp_hasDerivWithinAt x hf.hasDerivWithinAt hs).derivWithin hxs
#align fderiv_within.comp_deriv_within fderivWithin.comp_derivWithin
theorem fderiv.comp_deriv (hl : DifferentiableAt 𝕜 l (f x)) (hf : DifferentiableAt 𝕜 f x) :
deriv (l ∘ f) x = (fderiv 𝕜 l (f x) : F → E) (deriv f x) :=
(hl.hasFDerivAt.comp_hasDerivAt x hf.hasDerivAt).deriv
#align fderiv.comp_deriv fderiv.comp_deriv
end CompositionVector