hodge()
function in the
stokes
packagefunction (K, n = dovs(K), g, lose = TRUE)
{
if (missing(g)) {
g <- rep(1, n)
}
if (is.empty(K)) {
if (missing(n)) {
stop("'K' is zero but no value of 'n' is supplied")
}
else {
return(kform(spray(matrix(1, 0, n - arity(K)), 1)))
}
}
else if (is.volume(K, n)) {
return(scalar(coeffs(K), lose = lose))
}
else if (is.scalar(K)) {
if (missing(n)) {
stop("'K' is scalar but no value of 'n' is supplied")
}
else {
return(volume(n) * coeffs(K))
}
}
stopifnot(n >= dovs(K))
f1 <- function(o) {
seq_len(n)[!seq_len(n) %in% o]
}
f2 <- function(x) {
permutations::sgn(permutations::as.word(x))
}
f3 <- function(v) {
prod(g[v])
}
iK <- index(K)
jj <- apply(iK, 1, f1)
if (is.matrix(jj)) {
newindex <- t(jj)
}
else {
newindex <- as.matrix(jj)
}
x_coeffs <- elements(coeffs(K))
x_metric <- apply(iK, 1, f3)
x_sign <- apply(cbind(iK, newindex), 1, f2)
as.kform(newindex, x_metric * x_coeffs * x_sign)
}
To cite the stokes
package in publications, please use
Hankin (2022). Given a k-form β, function hodge()
returns its Hodge dual ⋆β.
Formally, if V = ℝn, and
Λk(V)
is the space of alternating linear maps from Vk to ℝ, then ⋆: Λk(V) → Λn − k(V).
To define the Hodge dual, we need an inner product ⟨⋅, ⋅⟩ [function kinner()
in the
package] and, given this and β ∈ Λk(V)
we define ⋆β to be the
(unique) n − k-form
satisfying the fundamental relation:
α ∧ (⋆β) = ⟨α, β⟩ω,
for every α ∈ Λk(V). Here ω = e1 ∧ e2 ∧ ⋯ ∧ en is the unit n-vector of Λn(V). Taking determinants of this relation shows the following. If we use multi-index notation so eI = ei1 ∧ ⋯ ∧ eik with I = {i1, ⋯, ik}, then
⋆eI = (−1)σ(I)eJ
where J = {ji, …, jk} = [n] \ {i1, …, ik}
is the complement of I, and
(−1)σ(I)
is the sign of the permutation σ(I) = i1⋯ikj1⋯jn − k.
We extend to the whole of Λk(V)
using linearity. Package idiom for calculating the Hodge dual is
straightforward, being simply hodge()
.
We start by demonstrating hodge()
on basis elements of
Λk(V).
Recall that if {e1, …, en}
is a basis of vector space V = ℝn, then
{ω1, …, ωk}
is a basis of Λ1(V), where
ωi(ej) = δij.
A basis of Λk(V)
is given by the set
$$ \bigcup_{1\leqslant i_1 < \cdots < i_k\leqslant n} \bigwedge_{j=1}^k\omega_{i_j} = \left\lbrace \left.\omega_{i_1}\wedge\cdots\wedge\omega_{i_k} \right|1\leqslant i_1 < \cdots < i_k\leqslant n \right\rbrace. $$
This means that basis elements are things like ω2 ∧ ω6 ∧ ω7. If V = ℝ9, what is ⋆ω2 ∧ ω6 ∧ ω7?
## An alternating linear map from V^3 to R with V=R^7:
## val
## 2 6 7 = 1
## An alternating linear map from V^6 to R with V=R^9:
## val
## 1 3 4 5 8 9 = -1
See how ⋆a has index
entries 1-9 except 2, 6, 7 (from a). The (numerical) sign is negative
because the permutation has negative (permutational) sign. We can verify
this using the permutations
package:
## [1] (1264)(375)
## [coerced from word form]
## 1 2 3 4 5 6 7 8 9
## [1] 2 6 7 1 3 4 5 . .
## [1] -1
Above we see the sign of the permutation is negative. More succinct idiom would be
## An alternating linear map from V^6 to R with V=R^9:
## val
## 1 3 4 5 8 9 = -1
The second argument to hodge()
is needed if the largest
index ik
of the first argument is less than n; the default value is indeed n. In the example above, this is
7:
## An alternating linear map from V^4 to R with V=R^5:
## val
## 1 3 4 5 = -1
Above we see the result if V = ℝ7.
The hodge operator is linear and it is interesting to verify this.
## An alternating linear map from V^3 to R with V=R^7:
## val
## 2 6 7 = 6
## 2 5 7 = 5
## 5 6 7 = -9
## 1 3 7 = 4
## 1 5 7 = 7
## 2 3 5 = -3
## 1 5 6 = -8
## 1 2 7 = 2
## 1 4 6 = 1
## An alternating linear map from V^4 to R with V=R^7:
## val
## 2 3 5 7 = -1
## 3 4 5 6 = 2
## 2 3 4 7 = -8
## 1 4 6 7 = -3
## 2 3 4 6 = -7
## 2 4 5 6 = -4
## 1 2 3 4 = -9
## 1 3 4 6 = 5
## 1 3 4 5 = -6
We verify that the fundamental relation holds by direct inspection:
## An alternating linear map from V^7 to R with V=R^7:
## val
## 1 2 3 4 5 6 7 = 285
## An alternating linear map from V^7 to R with V=R^7:
## val
## 1 2 3 4 5 6 7 = 285
showing agreement (above, we use function volume()
in
lieu of calculating the permutation’s sign explicitly. See the
volume
vignette for more details). We may work more
formally by defining a function that returns TRUE
if the
left and right hand sides match
and call it with random k-forms:
## [1] TRUE
Or even
## [1] TRUE
We can work in three dimensions in which case we have three linearly
independent 1-forms: dx, dy, and dz. To work in this system
it is better to use dx
print method:
## An alternating linear map from V^2 to R with V=R^3:
## + dy^dz
This is further discussed in the dovs
vignette.
The three dimensional vector cross product $\mathbf{u}\times\mathbf{v}=\det\begin{pmatrix} i & j & k \\ u_1&u_2&u_3\\ v_1&v_2&v_3 \end{pmatrix}$ is a standard part of elementary vector calculus. In the package the idiom is as follows:
## function (u, v)
## {
## hodge(as.1form(u)^as.1form(v))
## }
revealing the formal definition of cross product as u × v = ⋆(u ∧ v). There are several elementary identities that are satisfied by the cross product:
$$ \begin{aligned} \mathbf{u}\times(\mathbf{v}\times\mathbf{w}) &= \mathbf{v}(\mathbf{w}\cdot\mathbf{u})-\mathbf{w}(\mathbf{u}\cdot\mathbf{v})\\ (\mathbf{u}\times\mathbf{v})\times\mathbf{w} &= \mathbf{v}(\mathbf{w}\cdot\mathbf{u})-\mathbf{u}(\mathbf{v}\cdot\mathbf{w})\\ (\mathbf{u}\times\mathbf{v})\times(\mathbf{u}\times\mathbf{w}) &= (\mathbf{u}\cdot(\mathbf{v}\times\mathbf{w}))\mathbf{u} \\ (\mathbf{u}\times\mathbf{v})\cdot(\mathbf{w}\times\mathbf{x}) &= (\mathbf{u}\cdot\mathbf{w})(\mathbf{v}\cdot\mathbf{x}) - (\mathbf{u}\cdot\mathbf{x})(\mathbf{v}\cdot\mathbf{w}) \end{aligned} $$
We may verify all four together:
u <- c(1,4,2)
v <- c(2,1,5)
w <- c(1,-3,2)
x <- c(-6,5,7)
c(
hodge(as.1form(u) ^ vcp3(v,w)) == as.1form(v*sum(w*u) - w*sum(u*v)),
hodge(vcp3(u,v) ^ as.1form(w)) == as.1form(v*sum(w*u) - u*sum(v*w)),
as.1form(as.function(vcp3(v,w))(u)*u) == hodge(vcp3(u,v) ^ vcp3(u,w)) ,
hodge(hodge(vcp3(u,v)) ^ vcp3(w,x)) == sum(u*w)*sum(v*x) - sum(u*x)*sum(v*w)
)
## [1] TRUE TRUE TRUE TRUE
Above, note the use of the hodge operator to define triple vector cross products. For example we have u × (v × w) = ⋆(u ∧ ⋆(v ∧ w)).
The inner product ⟨α, β⟩ above may be generalized by defining it on decomposable vectors α = α1 ∧ ⋯ ∧ αk and β = β1 ∧ ⋯ ∧ βk as
⟨α, β⟩ = det (⟨αi, βj⟩i, j)
where ⟨αi, βj⟩ = ±δij
is an inner product on Λ1(V) [the inner
product is given by kinner()
]. The resulting Hodge star
operator is implemented in the package and one can specify the metric.
For example, if we consider the Minkowski metric this would be −1, 1, 1, 1.
The standard print method is not particularly suitable for working with the Minkowski metric:
## An alternating linear map from V^2 to R with V=R^4:
## val
## 3 4 = 6
## 2 4 = 5
## 1 4 = 4
## 2 3 = 3
## 1 3 = 2
## 1 2 = 1
Above we see an unhelpful representation. To work with 2-forms in relativistic physics, it is often
preferable to use bespoke print method usetxyz
:
## An alternating linear map from V^2 to R with V=R^4:
## +6 dy^dz +5 dx^dz +4 dt^dz +3 dx^dy +2 dt^dy + dt^dx
Function hodge()
takes a g
argument to
specify the metric:
## An alternating linear map from V^2 to R with V=R^4:
## + dy^dz -2 dx^dz +3 dt^dz +4 dx^dy -5 dt^dy +6 dt^dx
## An alternating linear map from V^2 to R with V=R^4:
## - dy^dz +2 dx^dz +3 dt^dz -4 dx^dy -5 dt^dy +6 dt^dx
## An alternating linear map from V^2 to R with V=R^4:
## +8 dx^dy -4 dx^dz +2 dy^dz