Zulip Chat Archive
Stream: maths
Topic: Implicit function theorem in familiar form
Miyahara Kō (Jul 03 2024 at 15:01):
Hi.
As we all know, Mathlib does not contain the implicit function theorem in the familiar form.
According to Wikipedia, the implicit function theorem is written in the following form:
Let , , be Banach spaces. Let the mapping be continuously Fréchet differentiable. If , , and is a Banach space isomorphism from onto , then there exist neighbourhoods of and of and a Fréchet differentiable function such that and if and only if , for all .
So, in my spare time, I formalized it in the above form.
I do not intend to make this PR as it is tedious, but I hope it helps!
import Mathlib
open scoped Topology
variable {X : Type*} [NormedAddCommGroup X] [NormedSpace ℝ X] [CompleteSpace X]
variable {Y : Type*} [NormedAddCommGroup Y] [NormedSpace ℝ Y] [CompleteSpace Y]
variable {Z : Type*} [NormedAddCommGroup Z] [NormedSpace ℝ Z] [CompleteSpace Z]
example
{f : X × Y → Z} {x₀ : X} {y₀ : Y} {dfx : X →L[ℝ] Z} {dfy : Y ≃L[ℝ] Z}
(hdf : HasStrictFDerivAt f (dfx.coprod ↑dfy) (x₀, y₀)) (hf : f (x₀, y₀) = 0) :
∃ g : X → Y, (∃ dg : X →L[ℝ] Y, HasStrictFDerivAt g dg x₀) ∧
∀ᶠ p in 𝓝 (x₀, y₀), f p = 0 ↔ p.2 = g p.1 := by
let d : ImplicitFunctionData ℝ (X × Y) Z X :=
{ leftFun := f
rightFun := Prod.fst
pt := (x₀, y₀)
leftDeriv := dfx.coprod ↑dfy
left_has_deriv := hdf
rightDeriv := ContinuousLinearMap.fst ℝ X Y
right_has_deriv := hasStrictFDerivAt_fst
left_range := by
change LinearMap.range (↑(dfx.coprod ↑dfy : X × Y →L[ℝ] Z) : X × Y →ₗ[ℝ] Z) = ⊤
rw [ContinuousLinearMap.coe_coprod, LinearMap.range_coprod]
conv_lhs => arg 2; arg 1; change (↑(↑dfy : Y ≃ₗ[ℝ] Z) : Y →ₗ[ℝ] Z)
simp
right_range := Submodule.range_fst
isCompl_ker := by
change IsCompl
(LinearMap.ker (↑(dfx.coprod ↑dfy : X × Y →L[ℝ] Z) : X × Y →ₗ[ℝ] Z))
(LinearMap.ker (LinearMap.fst ℝ X Y))
rw [ContinuousLinearMap.coe_coprod]
conv => arg 1; arg 1; arg 2; change (↑(↑dfy : Y ≃ₗ[ℝ] Z) : Y →ₗ[ℝ] Z)
constructor
· rw [disjoint_iff]; ext ⟨x, y⟩
simp only [Submodule.mem_inf, LinearMap.mem_ker, LinearMap.coprod_apply,
ContinuousLinearMap.coe_coe, LinearEquiv.coe_coe, LinearMap.fst_apply,
and_comm (b := x = 0), Submodule.mem_bot, Prod.mk_eq_zero, and_congr_right_iff]
rintro rfl; simp
· rw [codisjoint_iff]; ext ⟨x, y⟩
simp only [Submodule.mem_sup, LinearMap.mem_ker, LinearMap.coprod_apply,
ContinuousLinearMap.coe_coe, LinearEquiv.coe_coe, LinearMap.fst_apply, Prod.exists,
exists_and_left, exists_eq_left, Prod.mk_add_mk, add_zero, Prod.mk.injEq,
Submodule.mem_top, iff_true]
use x, dfy.symm (dfx (-x))
refine ⟨?_, rfl, ?_⟩
· change dfx x + dfy (dfy.symm (dfx (-x))) = 0
simp
use dfy.symm (dfx x) + y
simp }
use fun x => (d.implicitFunction 0 x).2
constructor
· use -(↑dfy.symm ∘L dfx)
have hd :=
d.implicitFunction_hasStrictFDerivAt
((ContinuousLinearMap.id ℝ X).prod (-(↑dfy.symm ∘L dfx))) ?_ ?_
· replace hd := hasStrictFDerivAt_snd.comp x₀ hd
simp only [hf, ContinuousLinearMap.snd_comp_prod] at hd
exact hd
· simp
· ext x; simp
· have hd₁ := d.left_map_implicitFunction; simp only [ImplicitFunctionData.prodFun, hf] at hd₁
replace hd₁ := hd₁.curry_nhds.self_of_nhds.prod_inl_nhds y₀
have hd₂ := d.right_map_implicitFunction; simp only [ImplicitFunctionData.prodFun, hf] at hd₂
replace hd₂ := hd₂.curry_nhds.self_of_nhds.prod_inl_nhds y₀
filter_upwards [hd₁, hd₂, d.implicitFunction_apply_image] with ⟨x, y⟩ hxy₁ hxy₂ hxy₃
simp only at hxy₁ hxy₂ hxy₃ ⊢
constructor
· intro hxy₄
replace hxy₄ := congr_arg (fun z => (d.implicitFunction z x).2) hxy₄
beta_reduce at hxy₄; rwa [hxy₃] at hxy₄
· rintro rfl
convert hxy₁
exact hxy₂.symm
Kim Morrison (Jul 03 2024 at 21:17):
Why not PR it? Nothing wrong with tedious!
Ruben Van de Velde (Jul 03 2024 at 21:31):
Tedious proof or tedious PR process?
Miyahara Kō (Jul 04 2024 at 03:01):
PR process. I wrote a whack-a-mole proof so should be golfed, but I can't afford to do that because I am in the middle of the project.
A. (Jul 04 2024 at 06:00):
Would you like me to help out by putting a PR together?
Miyahara Kō (Jul 04 2024 at 06:00):
@A. Yes, thank you very much!
Kim Morrison (Jul 04 2024 at 21:30):
Just a general remark --- mathematically contentful proofs shouldn't be "golfed", they should be made more readable and more structured! Golfing is only for proofs that no one will ever want to read (including someone in the far future needing to do maintenance for a breakage).
Richard Osborn (Jul 05 2024 at 14:09):
It really surprises me that this community created a positive connotation with the word "golf" when basically every other programming community uses it as a negative term.
Johan Commelin (Jul 05 2024 at 14:11):
Aren't there entire subreddits and stackexchanges dedicated to this positive activity :rofl: ?
Richard Osborn (Jul 05 2024 at 14:13):
There's also the International Obfuscated C Code Contest, but I don't think we should use it for inspiration :laughing:
Yury G. Kudryashov (Jul 08 2024 at 02:21):
When I was formalizing the implicit function theorem, I decided to prove a very general version and leave formalizing specialized versions for future, because there are tons of special cases we may need, and it's hard to guess which ones will be useful in practice.
Yury G. Kudryashov (Jul 08 2024 at 02:23):
The only question I have about "golfing" or not this proof is "are there parts of the proof that can be moved to reusable lemmas?"
A. (Jul 08 2024 at 19:53):
Thanks Yury. I do have a specific use case in mind and something like the above should work for it. (I want to talk about the evolution of the fixed point of a function defined on .)
I was thinking of
noncomputable def prodImplicitFunction {f : X × Y → Z} {x₀ : X} {y₀ : Y}
{dfx : X →L[𝕜] Z} {dfy : Y ≃L[𝕜] Z} (df₀ : HasStrictFDerivAt f (dfx.coprod dfy) (x₀, y₀)) :
X → Y := …
or possibly
noncomputable def prodImplicitFunction {f : X → Y → Z} {x₀ : X} {y₀ : Y}
{dfx : X →L[𝕜] Z} (dfx₀ : HasStrictFDerivAt (f · y₀) dfx x₀)
{dfy : Y ≃L[𝕜] Z} (dfy₀ : HasStrictFDerivAt (f x₀) (dfy : Y →L[𝕜] Z) y₀) :
X → Y := …
(or both) along with
example {f : X × Y → Z} {x₀ : X} {y₀ : Y}
{dfx : X →L[𝕜] Z} {dfy : Y ≃L[𝕜] Z} (df₀ : HasStrictFDerivAt f (dfx.coprod dfy) (x₀, y₀)) :
∀ᶠ (x, y) in 𝓝 (x₀, y₀), f (x, y) = f (x₀, y₀) ↔ y = df₀.prodImplicitFunction x := ...
example {f : X × Y → Z} {x₀ : X} {y₀ : Y}
{dfx : X →L[𝕜] Z} {dfy : Y ≃L[𝕜] Z} (df₀ : HasStrictFDerivAt f (dfx.coprod dfy) (x₀, y₀)) :
HasStrictFDerivAt df₀.prodImplicitFunction (-dfy.symm ∘L dfx) x₀ := ...
etc.
A. (Jul 08 2024 at 19:54):
I also want something on the second derivative.
A. (Sep 12 2024 at 21:10):
Violeta Hernández (Sep 13 2024 at 00:53):
Kim Morrison said:
Just a general remark --- mathematically contentful proofs shouldn't be "golfed", they should be made more readable and more structured!
It really does say something about Mathlib (about all formal math in general?) that 99% of our theorems still classify as golf-worthy :stuck_out_tongue:
A. (Nov 27 2025 at 15:28):
@Winston Yin (尹維晨) I guess this stuff will be fresh in your mind since your PR #30595 merged yesterday was only written last month. Does it subsume mine?
A. (Nov 27 2025 at 15:32):
Oh mine has a different number since the migration-to-fork thing. It's now #26985. It finally got the thumbs-up literally hours before yours went through!
A. (Nov 27 2025 at 15:40):
There's also this dependent PR #30077 for the curried function.
Winston Yin (尹維晨) (Nov 27 2025 at 18:02):
Thanks for pinging me on this. I'm sorry that I was not aware of this thread before starting my work in July. Let me ping @Michael Rothgang and @Sébastien Gouëzel who reviewed my PR to see how we may proceed.
Winston Yin (尹維晨) (Nov 27 2025 at 18:16):
Having one's hard work subsumed by someone else's PR is a very disappointing experience, and I apologise for this. However, I believe there are parts that can be extracted from your PRs (e.g. curried version). My PR was meant to show C^n for the implicit function, so that's different from yours. I'll also mention my dependent PR #31988, which shows the local uniqueness of the implicit function. Does that overlap with anything in your PRs?
A. (Nov 27 2025 at 18:46):
Don't worry, of my many disappointments this is among the smallest! I've only brought it up here because I'm lazy. It's been such a long time since I wrote mine that it will be an effort for me to work out the relationships myself.
A. (Nov 27 2025 at 18:50):
No I didn't attempt anything on $C^n$. IIRC I had developed the idea that the best thing to do there would be to extend the Faa di Bruno stuff that exists elsewhere.
Winston Yin (尹維晨) (Nov 27 2025 at 18:52):
My C^n stuff is whatever works minimally, and some generalisation is likely possible. I'm also happy to schedule a video call where we disentangle all this. We may be able to use some of the type signature of your bivariate implicit function in the curried form, reducing them to the IsContDiffImplicitAt in my PR.
Jireh Loreaux (Nov 27 2025 at 19:09):
@Winston Yin (尹維晨) and @A., yes, I still think the curried version in #26985 is worthwhile, unless I'm missing somethinb obvious, but I'm sorry that also only saw this thread for the first time today.
Jireh Loreaux (Dec 02 2025 at 19:44):
@Winston Yin (尹維晨) would you mind reviewing #26895 ? I would like to see it merged, and I had already delegated before this came up. Since you are so familiar with the material and its current state in Mathlib, I think you would be ideal to review it.
Winston Yin (尹維晨) (Dec 09 2025 at 11:46):
Yes, I'm happy to. I like that #26985 (btw @Jireh Loreaux you mislabelled the PR in your second message) is more general than my mathlib#IsContDiffImplicitAt.implicitFunctionData in that it doesn't assume ContDiff, and I also like its hypotheses {f₁ : E₁ →L[𝕜] F} {f₂ : E₂ ≃L[𝕜] F}. I would like to state the latter in terms of the former. @A. : Feel free to do this yourself before I attempt it myself.
A. (Dec 09 2025 at 20:58):
Great :grinning: In a week or two I should have the time to look through it myself
Last updated: Dec 20 2025 at 21:32 UTC