We express differential forms in terms of tensors and index notation. The
closest treatment seems to be Winitzki (2009), but we improve even upon that
in clarity, exact short definitions and explicit examples.
It seems the usual old-fashioned index-based tensor formalism described in
Čertík, O. et al. (2025) is all that is needed, and the differential forms
provide an equivalent and optional treatment for antisymmetric tensors, which
might be sometimes useful, but fundamentally does not bring any new feature or
machinery, exactly the same computations can be done using index-based tensors
also. We show how to equivalently rewrite any differential form formula or
computation using tensors.
This book uses the old-fashioned index notation typified by Lovelock and Rund (L&R). It is written entirely in terms of transformation rules between coordinate systems. This is refreshingly concrete for the physicist concerned with calculation. After all, we must have numbers and arrays to do calculations. The downside of this ancient notation is that it’s no help in understanding contemporary literature. We can’t have our cake—coordinate-free notation for concise theorizing—and eat it—concrete coordinates for practical calculation—too.
We also avoid Cartan’s exterior calculus, typified by the Grassmann wedge product, as in dx∧dy. While this is a beautiful and powerful formalism, it’s not usually taught at an undergraduate level, and we don’t want assume it of the reader. We also don’t want to take the time and space to develop it. We can do all the physics we want without it, for now.
In these notes, we do take the time and space to develop that bridge from modern notation to the classical index notation.
where the position vector r can be omitted, and the basis vector is
treated as an operator on any function on the manifold (we will not use this
notation).
As noted above, the one-form can act on a vector to produce a scalar, by
definition of the dual space of linear operators on vectors, where 1-forms
live, as follows using an inner (dot) product:
We will not use the p(u) notation, preferring the dot
product directly, or simply contracting indices as piui. All other forms
acting on vectors are defined in a similar way using a dot product. In index
notation, dot product becomes contraction.
We omit writing the basis vectors, so expressions from the previous sections
would be just ui, pi, Aij, Aijk, Aij, piui, etc. In
most cases that is enough to fully represent everything. When we want to
represent the tensor itself rather than just its components in the underlying
fields (usually R or C), we include the basis functions too.
Upper and lower indices are treated equally. They just denote contravariant
and covariant components of the same tensor.
Together these give the decomposition of any rank-2 tensor into its symmetric and
antisymmetric parts, Aij=A(ij)+A[ij].
Lean proof: symPart, antisymPart, and the decomposition symPart_add_antisymPart
Over R, define the symmetric and antisymmetric parts of a rank-2 tensor,
A(ij)=21(Aij+Aji) and A[ij]=21(Aij−Aji). The Lean checks confirm
that they are genuinely symmetric and antisymmetric and that they sum back to Aij.
DifferentialFormsFlow.lean
/-- The **symmetric part** `A_(ij) = ½(A i j + A j i)` of a rank-2 tensor over `ℝ`. -/
noncomputable def symPart (A : ι → ι → ℝ) : ι → ι → ℝ := fun i j => (A i j + A j i) / 2
/-- The **antisymmetric part** `A_[ij] = ½(A i j − A j i)` of a rank-2 tensor over `ℝ`; this is the
normalized antisymmetrization bracket used throughout `01-paper.md`. -/
noncomputable def antisymPart (A : ι → ι → ℝ) : ι → ι → ℝ := fun i j => (A i j - A j i) / 2
/-- The symmetric part really is symmetric: `A_(ij) = A_(ji)`. -/
theorem symPart_isSymm (A : ι → ι → ℝ) (i j : ι) : symPart A i j = symPart A j i := by
unfold symPart; ring
/-- The antisymmetric part really is antisymmetric: `A_[ij] = -A_[ji]`. -/
theorem antisymPart_isAntisymm (A : ι → ι → ℝ) (i j : ι) :
antisymPart A i j = - antisymPart A j i := by
unfold antisymPart; ring
/-- Every rank-2 tensor is the sum of its symmetric and antisymmetric parts:
`A i j = A_(ij) + A_[ij]`. -/
theorem symPart_add_antisymPart (A : ι → ι → ℝ) (i j : ι) :
symPart A i j + antisymPart A i j = A i j := by
unfold symPart antisymPart; ring
Writing the full contraction of two rank-2 covariant tensors as ∑i,jAijSij,
relabelling the summation indices i↔j and using antisymmetry Aij=−Aji
together with symmetry Sij=Sji shows that the contraction equals its own negation. Over
R this forces it to vanish.
DifferentialFormsFlow.lean
/-- The **full contraction** `∑_{i,j} A i j * S i j` of two rank-2 covariant tensors `A` and `S`,
each written as a function `ι → ι → R` of its two indices over a finite index set `ι`. -/
def contract [Fintype ι] [NonUnitalNonAssocSemiring R] (A S : ι → ι → R) : R :=
∑ i, ∑ j, A i j * S i j
/-- Contracting an **antisymmetric** tensor `A` (`A i j = -A j i`) with a **symmetric** tensor `S`
(`S i j = S j i`) yields a quantity equal to its own negation. Relabelling `i ↔ j` in the double
sum turns each term `A i j * S i j` into `A j i * S j i = (-A i j) * (S i j) = -(A i j * S i j)`. -/
theorem contract_antisymm_symm_eq_neg [Fintype ι] [Ring R] {A S : ι → ι → R}
(hA : ∀ i j, A i j = -A j i) (hS : ∀ i j, S i j = S j i) :
contract A S = - contract A S := by
have reindex : contract A S = ∑ i, ∑ j, A j i * S j i := by
rw [contract, Finset.sum_comm]
conv_lhs => rw [reindex]
rw [contract, ← Finset.sum_neg_distrib]
refine Finset.sum_congr rfl fun i _ => ?_
rw [← Finset.sum_neg_distrib]
refine Finset.sum_congr rfl fun j _ => ?_
rw [hA j i, hS j i, neg_mul]
/-- Over `ℝ` (any ring where `2` is cancellable) the contraction of an antisymmetric tensor with a
symmetric tensor is therefore exactly zero, as claimed in `01-paper.md`. -/
theorem contract_antisymm_symm [Fintype ι] {A S : ι → ι → ℝ}
(hA : ∀ i j, A i j = -A j i) (hS : ∀ i j, S i j = S j i) :
contract A S = 0 := by
have h := contract_antisymm_symm_eq_neg hA hS
linarith
In particular, applied to the symmetric and antisymmetric parts defined earlier, the antisymmetric
part of any tensor contracts to zero against the symmetric part of any tensor.
DifferentialFormsFlow.lean
/-- Combining the splitting with `contract_antisymm_symm`: over `ℝ`, the full contraction of the
antisymmetric part of any tensor with the symmetric part of any tensor vanishes. -/
theorem contract_antisymPart_symPart [Fintype ι] (A B : ι → ι → ℝ) :
contract (antisymPart A) (symPart B) = 0 :=
contract_antisymm_symm (antisymPart_isAntisymm A) (symPart_isSymm B)
This is the rank-3 analogue of the rank-2 identity (28); the 3!1 is the
generalized double counting, since each wedge e~i∧e~j∧e~k
expands into 3! signed tensor products.
Lean proof: otimesExpand_eq_smul_wedgeExpand
Model rank-3 covariant tensors over a finite index set as the free R-module on index
triples, with basis tensor e~p0⊗e~p1⊗e~p2 and wedge
e~p0∧e~p1∧e~p2=∑σsgn(σ)e~pσ(0)⊗e~pσ(1)⊗e~pσ(2).
DifferentialFormsFlow.lean
/-- Levi-Civita sign of a permutation of the three tensor slots, as a real scalar. -/
def signR (σ : Equiv.Perm (Fin 3)) : ℝ := ((Equiv.Perm.sign σ : ℤ) : ℝ)
/-- The basis tensor `ẽ^{p 0} ⊗ ẽ^{p 1} ⊗ ẽ^{p 2}` in the free `ℝ`-module on index triples. -/
def basisTensor [DecidableEq ι] (p : Fin 3 → ι) : (Fin 3 → ι) → ℝ := Pi.single p 1
/-- The `⊗`-expansion `∑_{i,j,k} A_{ijk} ẽⁱ⊗ẽʲ⊗ẽᵏ` of a rank-3 tensor with coefficients `A`. -/
def otimesExpand [Fintype ι] [DecidableEq ι] (A : (Fin 3 → ι) → ℝ) : (Fin 3 → ι) → ℝ :=
∑ p, A p • basisTensor p
/-- The wedge basis tensor `ẽ^{p 0} ∧ ẽ^{p 1} ∧ ẽ^{p 2}`: the signed sum over permutations of the
three slots, matching the note's definition of `u ∧ v ∧ w`. -/
def wedge [DecidableEq ι] (p : Fin 3 → ι) : (Fin 3 → ι) → ℝ :=
∑ σ : Equiv.Perm (Fin 3), signR σ • basisTensor (p ∘ ⇑σ)
/-- The `∧`-expansion `∑_{i,j,k} A_{ijk} ẽⁱ∧ẽʲ∧ẽᵏ`. -/
def wedgeExpand [Fintype ι] [DecidableEq ι] (A : (Fin 3 → ι) → ℝ) : (Fin 3 → ι) → ℝ :=
∑ p, A p • wedge p
For a fully antisymmetric Aijk (such as the determinant above), reindexing the double sum
∑p∑σ by p↦p∘σ and using antisymmetry turns each wedge term back
into the plain tensor term, so all 3! permutations contribute one copy each, canceling the
3!1.
DifferentialFormsFlow.lean
/-- **The rank-3 claim of `01-paper.md`.** For a fully antisymmetric rank-3 tensor `A`
(`A (p ∘ σ) = sign σ * A p`), the `⊗`-expansion equals `1/3!` times the `∧`-expansion:
`A_{ijk} ẽⁱ⊗ẽʲ⊗ẽᵏ = (1/3!) A_{ijk} ẽⁱ∧ẽʲ∧ẽᵏ`. -/
theorem otimesExpand_eq_smul_wedgeExpand [Fintype ι] [DecidableEq ι] (A : (Fin 3 → ι) → ℝ)
(hA : ∀ (p : Fin 3 → ι) (σ : Equiv.Perm (Fin 3)), A (p ∘ ⇑σ) = signR σ * A p) :
otimesExpand A = (1 / 6 : ℝ) • wedgeExpand A := by
have hcard : Fintype.card (Equiv.Perm (Fin 3)) = 6 := by
rw [Fintype.card_perm, Fintype.card_fin]; rfl
have h6 : wedgeExpand A = (6 : ℝ) • otimesExpand A := by
rw [wedgeExpand_eq_card_smul A hA, hcard, ← Nat.cast_smul_eq_nsmul ℝ]
norm_num
rw [h6, smul_smul]
norm_num
Higher-order products are defined in analogous manner (n wedge products is a rank n fully antisymmetric tensor). The exterior product can be defined for vectors as well. The components of these tensors are equal to:
The wedge product is equal to the tensor written using the tensor basis in
equations (28) and (30). The same tensor in index
notation is given by equations (32) and (33).
Via properties of a determinant, we can see that the wedge product is just a
fully antisymmetric tensor.
We can now use the definitions to compute various special cases. For example, if
we have the exterior product of two 1-forms dx and dz (with components
dxi=δ1i and dzi=δ3i):
When evaluating the form (composed of basis forms) on vectors u, v and w, we are computing the following dot product of the two rank-3 tensors (full contraction):
The exterior derivative d is defined via the following rules / definitions for differential forms:
0-form f: df≡∂xi∂fdxi=∂ifdxi
k-forms α and β, numbers a, b:
d(aα+bβ)=adα+bdβ
k-form α, 1-form β:
d(α∧β)=dα∧β+(−1)kα∧dβ
k-form α: d(dα)=0
It turns out that in terms of tensors, the exterior derivative is simply a regular derivative that is made antisymmetric:
0-form: ∂if
1-form: ∂[ifj]
2-form: ∂[iAjk]
3-form: ∂[iAjkl]=0 (in 3 dimensions, since a rank-4 fully antisymmetric tensor in 3D is identically 0)
One can use the formulas from the section “Antisymmetric Tensors” above to
evaluate these antisymmetric derivatives. We show examples of this below. We
first compute the exterior derivative using differential forms and the above
rules, and then we do exactly the same operations using tensors.
Take a 1-form fj, differentiate ∂ifj, to get a rank-2 tensor. Project it into the antisymmetric subspace dxi⊗dxj−dxj⊗dxi=21dxi∧dxj, canceling the symmetric part of the derivative. Only the antisymmetric part survives: ∂ifj−∂jfi. So we define the derivative to be Aij=∂ifj−∂jfi. We can define the derivative on antisymmetric tensors (exterior derivative) to be a regular derivative projected into the antisymmetric subset.
Let’s now do the same computation using regular tensors:
Taking Aij=∂ifj, the normalized bracket satisfies
2∂[ifj]=∂ifj−∂jfi with no leftover 21, which is
exactly the correction discussed above.
DifferentialFormsFlow.lean
/-- The factor of `2` in `01-paper.md`'s 1-form exterior derivative. With the *normalized* bracket
`∂_[i f_j] = ½(∂_i f_j − ∂_j f_i)`, twice the bracket has no residual `½`:
`2 ∂_[i f_j] = ∂_i f_j − ∂_j f_i`. Taking `A i j = ∂_i f_j` this is `2 * antisymPart A i j`. -/
theorem two_mul_antisymPart (A : ι → ι → ℝ) (i j : ι) :
2 * antisymPart A i j = A i j - A j i := by
unfold antisymPart; ring
The exterior derivative is simply a regular (not antisymmetric) derivative ∂ifj that is made antisymmetric: ∂[ifj]. The same applies to higher ranks.
We used the fact that the basis is antisymmetric, so only the antisymmetric part
of the derivative survives. The basis becomes antisymmetric due to the
incorporation of the dxk base via the wedge product, otherwise the derivative
is not fully antisymmetric.
The above is the correct result for differentiating any k-form in n-D space
where k=n−1.
Let’s now do the same computation using regular tensors: