Imports
/- Copyright (c) 2026 Bjørn Kjos-Hanssen. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Bjørn Kjos-Hanssen -/ module public import Mathlib.Analysis.Calculus.Gradient.Basic public import Mathlib.Analysis.Calculus.ContDiff.FTaylorSeries public import Mathlib.LinearAlgebra.QuadraticForm.Basic public import Mathlib.Analysis.Calculus.FDeriv.Analytic public import Mathlib.Analysis.Analytic.IteratedFDeriv public import Mathlib.Analysis.Calculus.FDeriv.Symmetric public import Mathlib.Analysis.InnerProductSpace.PiL2 public import PhyslibAlpha.Mathematics.PartialDerivativeTest

Coupled spring potential

As a proof of concept, we use the second derivative test in PhyslibAlpha.Mathematics.PartialDerivativeTest to prove that the coupled spring potential U := fun x : EuclideanSpace ℝ (Fin 2) => (x 0)^2 + x 0 * x 1 + (x 1)^2 has a local minimum at zero.

@[expose] public section/- The coupling potential is analytic everywhere (it is a polynomial). -/ lemma couplingPotential_analyticAt (z : EuclideanSpace ℝ (Fin 2)) : AnalyticAt ℝ couplingPotential z := z:EuclideanSpace ℝ (Fin 2)⊢ AnalyticAt ℝ couplingPotential z z:EuclideanSpace ℝ (Fin 2)h0:AnalyticAt ℝ (fun x => x.ofLp 0) z⊢ AnalyticAt ℝ couplingPotential z z:EuclideanSpace ℝ (Fin 2)h0:AnalyticAt ℝ (fun x => x.ofLp 0) zh1:AnalyticAt ℝ (fun x => x.ofLp 1) z⊢ AnalyticAt ℝ couplingPotential z z:EuclideanSpace ℝ (Fin 2)h0:AnalyticAt ℝ (fun x => x.ofLp 0) zh1:AnalyticAt ℝ (fun x => x.ofLp 1) z⊢ AnalyticAt ℝ (fun x => x.ofLp 0 ^ 2 + x.ofLp 0 * x.ofLp 1 + x.ofLp 1 ^ 2) z All goals completed! 🐙x:EuclideanSpace ℝ (Fin 2)h0:HasFDerivAt (fun x => x.ofLp 0) (EuclideanSpace.proj 0) xh1:HasFDerivAt (fun x => x.ofLp 1) (EuclideanSpace.proj 1) x⊢ HasFDerivAt couplingPotential ((2 * x.ofLp 0 + x.ofLp 1) • EuclideanSpace.proj 0 + (x.ofLp 0 + 2 * x.ofLp 1) • EuclideanSpace.proj 1) x x:EuclideanSpace ℝ (Fin 2)h0:HasFDerivAt (fun x => x.ofLp 0) (EuclideanSpace.proj 0) xh1:HasFDerivAt (fun x => x.ofLp 1) (EuclideanSpace.proj 1) xe_4✝:WithLp.instAddCommGroup 2 ((i : Fin 2) → (fun x => ℝ) i) = (PiLp.normedAddCommGroup 2 fun x => ℝ).toAddCommGrouphe✝¹:WithLp.instModule 2 ℝ ((i : Fin 2) → (fun x => ℝ) i) = (PiLp.normedSpace 2 ℝ fun x => ℝ).toModulee_6✝:(PiLp.topologicalSpace 2 fun x => ℝ) = PseudoMetricSpace.toUniformSpace.toTopologicalSpacee_8✝:Real.instAddCommGroup = Real.normedAddCommGroup.toAddCommGrouphe✝:Semiring.toModule = RCLike.toInnerProductSpaceReal.toModule⊢ (2 * x.ofLp 0 + x.ofLp 1) • EuclideanSpace.proj 0 + (x.ofLp 0 + 2 * x.ofLp 1) • EuclideanSpace.proj 1 = (2 • x.ofLp 0 ^ (2 - 1)) • EuclideanSpace.proj 0 + (x.ofLp 0 • EuclideanSpace.proj 1 + x.ofLp 1 • EuclideanSpace.proj 0) + (2 • x.ofLp 1 ^ (2 - 1)) • EuclideanSpace.proj 1 x:EuclideanSpace ℝ (Fin 2)h0:HasFDerivAt (fun x => x.ofLp 0) (EuclideanSpace.proj 0) xh1:HasFDerivAt (fun x => x.ofLp 1) (EuclideanSpace.proj 1) xe_4✝:WithLp.instAddCommGroup 2 ((i : Fin 2) → (fun x => ℝ) i) = (PiLp.normedAddCommGroup 2 fun x => ℝ).toAddCommGrouphe✝¹:WithLp.instModule 2 ℝ ((i : Fin 2) → (fun x => ℝ) i) = (PiLp.normedSpace 2 ℝ fun x => ℝ).toModulee_6✝:(PiLp.topologicalSpace 2 fun x => ℝ) = PseudoMetricSpace.toUniformSpace.toTopologicalSpacee_8✝:Real.instAddCommGroup = Real.normedAddCommGroup.toAddCommGrouphe✝:Semiring.toModule = RCLike.toInnerProductSpaceReal.toModulex✝:EuclideanSpace ℝ (Fin 2)⊢ ((2 * x.ofLp 0 + x.ofLp 1) • EuclideanSpace.proj 0 + (x.ofLp 0 + 2 * x.ofLp 1) • EuclideanSpace.proj 1) x✝ = ((2 • x.ofLp 0 ^ (2 - 1)) • EuclideanSpace.proj 0 + (x.ofLp 0 • EuclideanSpace.proj 1 + x.ofLp 1 • EuclideanSpace.proj 0) + (2 • x.ofLp 1 ^ (2 - 1)) • EuclideanSpace.proj 1) x✝; x:EuclideanSpace ℝ (Fin 2)h0:HasFDerivAt (fun x => x.ofLp 0) (EuclideanSpace.proj 0) xh1:HasFDerivAt (fun x => x.ofLp 1) (EuclideanSpace.proj 1) xe_4✝:WithLp.instAddCommGroup 2 ((i : Fin 2) → (fun x => ℝ) i) = (PiLp.normedAddCommGroup 2 fun x => ℝ).toAddCommGrouphe✝¹:WithLp.instModule 2 ℝ ((i : Fin 2) → (fun x => ℝ) i) = (PiLp.normedSpace 2 ℝ fun x => ℝ).toModulee_6✝:(PiLp.topologicalSpace 2 fun x => ℝ) = PseudoMetricSpace.toUniformSpace.toTopologicalSpacee_8✝:Real.instAddCommGroup = Real.normedAddCommGroup.toAddCommGrouphe✝:Semiring.toModule = RCLike.toInnerProductSpaceReal.toModulex✝:EuclideanSpace ℝ (Fin 2)⊢ (2 * x.ofLp 0 + x.ofLp 1) * x✝.ofLp 0 + (x.ofLp 0 + 2 * x.ofLp 1) * x✝.ofLp 1 = 2 * x.ofLp 0 * x✝.ofLp 0 + (x.ofLp 0 * x✝.ofLp 1 + x.ofLp 1 * x✝.ofLp 0) + 2 * x.ofLp 1 * x✝.ofLp 1; All goals completed! 🐙/- The gradient of the coupling potential vanishes at the origin. -/ lemma couplingPotential_gradient_zero : gradient couplingPotential (!2[0, 0] : EuclideanSpace ℝ (Fin 2)) = 0 := ⊢ gradient couplingPotential !₂[0, 0] = 0 ⊢ fderiv ℝ couplingPotential !₂[0, 0] = (InnerProductSpace.toDual ℝ (EuclideanSpace ℝ (Fin 2))).toLinearEquiv 0; ⊢ (InnerProductSpace.toDual ℝ (EuclideanSpace ℝ (Fin 2))).toLinearEquiv 0 = (2 * !₂[0, 0].ofLp 0 + !₂[0, 0].ofLp 1) • EuclideanSpace.proj 0 + (!₂[0, 0].ofLp 0 + 2 * !₂[0, 0].ofLp 1) • EuclideanSpace.proj 1 All goals completed! 🐙z:EuclideanSpace ℝ (Fin 2)a:EuclideanSpace ℝ (Fin 2)b:EuclideanSpace ℝ (Fin 2)h_second_deriv:fderiv ℝ (fderiv ℝ couplingPotential) z = 2 • ContinuousLinearMap.smulRight (EuclideanSpace.proj 0) (EuclideanSpace.proj 0) + ContinuousLinearMap.smulRight (EuclideanSpace.proj 0) (EuclideanSpace.proj 1) + ContinuousLinearMap.smulRight (EuclideanSpace.proj 1) (EuclideanSpace.proj 0) + 2 • ContinuousLinearMap.smulRight (EuclideanSpace.proj 1) (EuclideanSpace.proj 1)⊢ ((iteratedFDeriv ℝ 1 (fun y => fderiv ℝ couplingPotential y) z) (Fin.init ![a, b])) (![a, b] (Fin.last 1)) = 2 * a.ofLp 0 * b.ofLp 0 + a.ofLp 0 * b.ofLp 1 + a.ofLp 1 * b.ofLp 0 + 2 * a.ofLp 1 * b.ofLp 1; z:EuclideanSpace ℝ (Fin 2)a:EuclideanSpace ℝ (Fin 2)b:EuclideanSpace ℝ (Fin 2)h_second_deriv:fderiv ℝ (fderiv ℝ couplingPotential) z = 2 • ContinuousLinearMap.smulRight (EuclideanSpace.proj 0) (EuclideanSpace.proj 0) + ContinuousLinearMap.smulRight (EuclideanSpace.proj 0) (EuclideanSpace.proj 1) + ContinuousLinearMap.smulRight (EuclideanSpace.proj 1) (EuclideanSpace.proj 0) + 2 • ContinuousLinearMap.smulRight (EuclideanSpace.proj 1) (EuclideanSpace.proj 1)⊢ 2 * ((Fin.init ![a, b] 0).ofLp 0 * b.ofLp 0) + (Fin.init ![a, b] 0).ofLp 0 * b.ofLp 1 + (Fin.init ![a, b] 0).ofLp 1 * b.ofLp 0 + 2 * ((Fin.init ![a, b] 0).ofLp 1 * b.ofLp 1) = 2 * a.ofLp 0 * b.ofLp 0 + a.ofLp 0 * b.ofLp 1 + a.ofLp 1 * b.ofLp 0 + 2 * a.ofLp 1 * b.ofLp 1; All goals completed! 🐙;/- The second derivative quadratic map of the coupling potential is positive definite at the origin. -/ lemma couplingPotential_posDef : (iteratedFDerivQuadraticMap couplingPotential (!2[0, 0] : EuclideanSpace ℝ (Fin 2))).PosDef := ⊢ (iteratedFDerivQuadraticMap couplingPotential !₂[0, 0]).PosDef y:EuclideanSpace ℝ (Fin 2)hy:y ≠ 0⊢ 0 < (iteratedFDerivQuadraticMap couplingPotential !₂[0, 0]) y; convert! (show 0 < 2 * y 0 ^ 2 + 2 * y 0 * y 1 + 2 * y 1 ^ 2 ⊢ (iteratedFDerivQuadraticMap couplingPotential !₂[0, 0]).PosDef exact not_le.mp fun h => hy <| y:EuclideanSpace ℝ (Fin 2)hy:y ≠ 0h:2 * y.ofLp 0 ^ 2 + 2 * y.ofLp 0 * y.ofLp 1 + 2 * y.ofLp 1 ^ 2 ≤ 0⊢ y = 0 y:EuclideanSpace ℝ (Fin 2)hy:y ≠ 0h:2 * y.ofLp 0 ^ 2 + 2 * y.ofLp 0 * y.ofLp 1 + 2 * y.ofLp 1 ^ 2 ≤ 0i:Fin 2⊢ y.ofLp i = WithLp.ofLp 0 i y:EuclideanSpace ℝ (Fin 2)hy:y ≠ 0h:2 * y.ofLp 0 ^ 2 + 2 * y.ofLp 0 * y.ofLp 1 + 2 * y.ofLp 1 ^ 2 ≤ 0⊢ y.ofLp ((fun i => i) ⟨0, ⋯⟩) = WithLp.ofLp 0 ((fun i => i) ⟨0, ⋯⟩)y:EuclideanSpace ℝ (Fin 2)hy:y ≠ 0h:2 * y.ofLp 0 ^ 2 + 2 * y.ofLp 0 * y.ofLp 1 + 2 * y.ofLp 1 ^ 2 ≤ 0⊢ y.ofLp ((fun i => i) ⟨1, ⋯⟩) = WithLp.ofLp 0 ((fun i => i) ⟨1, ⋯⟩) y:EuclideanSpace ℝ (Fin 2)hy:y ≠ 0h:2 * y.ofLp 0 ^ 2 + 2 * y.ofLp 0 * y.ofLp 1 + 2 * y.ofLp 1 ^ 2 ≤ 0⊢ y.ofLp ((fun i => i) ⟨0, ⋯⟩) = WithLp.ofLp 0 ((fun i => i) ⟨0, ⋯⟩)y:EuclideanSpace ℝ (Fin 2)hy:y ≠ 0h:2 * y.ofLp 0 ^ 2 + 2 * y.ofLp 0 * y.ofLp 1 + 2 * y.ofLp 1 ^ 2 ≤ 0⊢ y.ofLp ((fun i => i) ⟨1, ⋯⟩) = WithLp.ofLp 0 ((fun i => i) ⟨1, ⋯⟩) y:EuclideanSpace ℝ (Fin 2)hy:y ≠ 0h:2 * y.ofLp 0 ^ 2 + 2 * y.ofLp 0 * y.ofLp 1 + 2 * y.ofLp 1 ^ 2 ≤ 0⊢ y.ofLp 1 = 0 y:EuclideanSpace ℝ (Fin 2)hy:y ≠ 0h:2 * y.ofLp 0 ^ 2 + 2 * y.ofLp 0 * y.ofLp 1 + 2 * y.ofLp 1 ^ 2 ≤ 0⊢ y.ofLp 0 = 0y:EuclideanSpace ℝ (Fin 2)hy:y ≠ 0h:2 * y.ofLp 0 ^ 2 + 2 * y.ofLp 0 * y.ofLp 1 + 2 * y.ofLp 1 ^ 2 ≤ 0⊢ y.ofLp 1 = 0 All goals completed! 🐙) using 1 y:EuclideanSpace ℝ (Fin 2)hy:y ≠ 0pf✝¹:Nat.AtLeastTwo 2pf✝:NeZero 2⊢ (iteratedFDerivQuadraticMap couplingPotential !₂[0, 0]) y = 2 * y.ofLp 0 ^ 2 + 2 * y.ofLp 0 * y.ofLp 1 + 2 * y.ofLp 1 ^ 2; y:EuclideanSpace ℝ (Fin 2)hy:y ≠ 0pf✝¹:Nat.AtLeastTwo 2pf✝:NeZero 2⊢ 2 * y.ofLp 0 ^ 2 + 2 * y.ofLp 0 * y.ofLp 1 + 2 * y.ofLp 1 ^ 2 = 2 * y.ofLp 0 * y.ofLp 0 + y.ofLp 0 * y.ofLp 1 + y.ofLp 1 * y.ofLp 0 + 2 * y.ofLp 1 * y.ofLp 1; All goals completed! 🐙lemma coupled_spring_potential : let U := fun x : EuclideanSpace ℝ (Fin 2) => (x 0)^2 + x 0 * x 1 + (x 1)^2 IsLocalMin U { ofLp := ![0,0] } := ⊢ let U := fun x => x.ofLp 0 ^ 2 + x.ofLp 0 * x.ofLp 1 + x.ofLp 1 ^ 2; IsLocalMin U !₂[0, 0] ⊢ IsLocalMin couplingPotential !₂[0, 0] All goals completed! 🐙