Component-wise Vector Calculus Proofs
The Problem
Vector calculus identities like div(curl F) = 0 or curl(curl F) = grad(div F) - nabla^2 F cannot be proved abstractly — they require expanding each component into sums of partial derivatives, splitting compound fderiv expressions, and using algebraic cancellation (often via symmetry of mixed partials).
Strategy Overview
- •Define a local shorthand for mixed second partial derivatives
- •Prove differentiability of partial derivative expressions (reusable helper)
- •Prove symmetry of mixed partials via
fderiv_apply_comm(reusable helper) - •Prove a
fderiv_subpointwise helper for extracting scalar values - •Expand each component using the helpers
- •Combine and cancel using
ringand symmetry
The d Shorthand Pattern
Define a local function for second mixed partials:
let d : Fin 3 -> Fin 3 -> Fin 3 -> R := fun i k j => fderiv R (fun y => partialDerivComp F i j y) x (basisVec k)
Here d i k j means "differentiate (partial_i F_j) in direction k", i.e., partial_k partial_i F_j.
Reusable Helpers (define once per proof)
Differentiability of partial derivative expressions
have hpdiff (i j : Fin 3) : DifferentiableAt R (fun y => partialDerivComp F i j y) x := by
dsimp [partialDerivComp]
have hfderiv_c1 : ContDiff R 1 (fderiv R (fun z => F z j)) :=
(hF j).fderiv_right (by norm_num)
have hdf : DifferentiableAt R (fderiv R (fun z => F z j)) x :=
(hfderiv_c1.differentiable (by simp)).differentiableAt
simpa using hdf.clm_apply (differentiableAt_const (basisVec i))
Symmetry of mixed partials
have hcomm (i k j : Fin 3) : d i k j = d k i j := by
simpa [d, partialDerivComp] using
(fderiv_apply_comm (fun y => F y j) (hF j) x (basisVec i) (basisVec k))
Pointwise fderiv_sub
have hsubApply (f g : Vec3 -> R) (hf : DifferentiableAt R f x)
(hg : DifferentiableAt R g x) (v : Vec3) :
fderiv R (fun y => f y - g y) x v = fderiv R f x v - fderiv R g x v :=
congrArg (fun L => L v) (fderiv_sub hf hg)
Example: div(curl F) = 0
After setting up helpers, expand each diagonal component of divergence (curl F):
-- Component 0: partial_0 of (curl F)_0 = partial_0 of (partial_1 F_2 - partial_2 F_1)
have h0 : partialDerivComp (curl F) 0 0 x = d 1 0 2 - d 2 0 1 := by
simpa [d, curl, partialDerivComp, Fin.isValue] using
hsubApply (fun y => partialDerivComp F 1 2 y) (fun y => partialDerivComp F 2 1 y)
(hpdiff 1 2) (hpdiff 2 1) (basisVec 0)
-- Similar for h1, h2...
Then combine:
calc divergence (curl F) x
= partialDerivComp (curl F) 0 0 x + partialDerivComp (curl F) 1 1 x +
partialDerivComp (curl F) 2 2 x := by simp [divergence, Fin.sum_univ_three]
_ = (d 1 0 2 - d 2 0 1) + (d 2 1 0 - d 0 1 2) + (d 0 2 1 - d 1 2 0) := by rw [h0, h1, h2]
_ = 0 := by rw [hcomm 1 0 2, hcomm 2 1 0, hcomm 0 2 1]; ring
Example: curl(curl F) = grad(div F) - nabla^2 F
This requires funext j then fin_cases j to handle each of the 3 components. For each component:
- •Expand LHS: The curl-of-curl component involves two
partialDerivComp (curl F)terms, each of which is a difference that must be split withhsubApply - •Expand RHS:
partialDeriv (divergence F) jrequiresfderiv_sumto distribute over the sum, andvectorLaplacianunfolds directly - •Match using
hcomm: Rewrite certaind i k jterms tod k i jto make both sides match - •Close with
ring
Key helper for the RHS gradient-of-divergence expansion:
have hgraddiv (j : Fin 3) :
partialDeriv (divergence F) j x = sum i : Fin 3, d i j i := by
-- Use fderiv_sum to distribute fderiv over the Finset.sum in divergence
have hsum := fderiv_sum (fun i _ => hpdiff i i)
...
Useful simp Lemmas
- •
Fin.sum_univ_three— expandssum i : Fin 3, f itof 0 + f 1 + f 2 - •
Fin.isValue— normalizesFin.valapplications - •
divergence,curl,partialDerivComp,partialDeriv— unfold definitions
Critical Pitfalls
- •
simpavssimp: Usesimpa [d, curl, partialDerivComp] using hsubApply ...rather than rewriting manually. Thesimpabridges definitional gaps between the goal and the applied lemma. - •
Explicit
Fin 3indices: Afterfin_cases, you get concrete values0,1,2. The match arms incurlneedFin.isValuein simp to reduce. - •
Don't try
omegaordecidefor Fin arithmetic: These often don't work. Usesimp [Fin.isValue]or explicitnorm_num. - •
Fin.sum_univ_threeis essential: Without it,divergencestays as an opaqueFinset.sumand nothing simplifies. - •
The proof is unavoidably long:
curl(curl F) = grad(div F) - nabla^2 Fneeds ~100 lines because each of 3 components requires ~4 intermediatehavestatements. Don't try to golf it — clarity wins.