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 XX, YY, ZZ be Banach spaces. Let the mapping f:X×YZf : X \times Y \to Z be continuously Fréchet differentiable. If (x0,y0)X×Y(x_0,y_0)\in X\times Y, f(x0,y0)=0f(x_0,y_0)=0, and yDf(x0,y0)(0,y)y\mapsto Df(x_0,y_0)(0,y) is a Banach space isomorphism from YY onto ZZ, then there exist neighbourhoods UU of x0x_0 and VV of y0y_0 and a Fréchet differentiable function g:UVg : U \to V such that f(x,g(x))=0f(x, g(x)) = 0 and f(x,y)=0f(x, y) = 0 if and only if y=g(x)y = g(x), for all (x,y)U×V(x,y)\in U\times V.

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 Rn\mathbb{R}^{n}.)

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):

#16743

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:


Last updated: May 02 2025 at 03:31 UTC