wedge()
and
wedge2()
in the stokes
packagefunction (x, ...)
{
if (nargs() < 3) {
wedge2(x, ...)
}
else {
wedge2(x, Recall(...))
}
}
function (K1, K2)
{
if (missing(K2)) {
return(K1)
}
if (is.ktensor(K1) | is.ktensor(K2)) {
stop("wedge product only defined for kforms")
}
if (!is.kform(K1) | !is.kform(K2)) {
return(K1 * K2)
}
if (is.empty(K1) | is.empty(K2)) {
return(zeroform(arity(K1) + arity(K2)))
}
kform(spraycross(K1, K2))
}
To cite the stokes
package in publications, please use
Hankin (2022). In a memorable passage,
Spivak (1965) states:
… we would like a theorem analogous to 4.1 [the dimensionality of k-fold tensor products is nk]. Of course, if ω ∈ Λk(V) and η ∈ Λl(V), then ω ⊗ η is usually not in Λk + l(V). We will therefore define a new product, the wedge product ω ∧ η ∈ Λk + l(V) by
$$ \omega\wedge\eta=\frac{\left(k+l\right)!}{k!l!}\operatorname{Alt}(\omega\otimes\eta),\qquad\omega\in\Lambda^k(V),\eta\in\Lambda^l(V) $$
(The reason for the strange coefficient will appear later).- Michael Spivak, 1969 (Calculus on Manifolds, Perseus books). Page 79
Function wedge()
returns the wedge product of any number
of k-forms; function
wedge2()
returns the wedge product of two k-forms. The idiom of
wedge2()
is somewhat opaque, especially the “strange”
combinatorial coefficient (k + l)!/(k!l!),
which is discussed in detail below.
spraycross()
Function wedge()
is essentially a convenience wrapper
for spraycross()
; the meat of wedge2()
is the
last line: kform(spraycross(K1, K2))
. Function
spraycross()
is part of the spray
package and
gives a tensor product of sparse arrays, interpreted as multivariate
polynomials:
## val
## 2 4 = 5
## 1 3 = 2
## val
## 11 13 = 11
## 10 12 = 7
## val
## 1 3 10 12 = 14
## 1 3 11 13 = 22
## 2 4 10 12 = 35
## 2 4 11 13 = 55
## val
## 10 12 1 3 = 14
## 11 13 1 3 = 22
## 10 12 2 4 = 35
## 11 13 2 4 = 55
Observe that spraycross()
(and by association
wedge()
) is associative and distributive but not
commutative.
wedge2()
Function wedge2()
takes two kforms and we will start
with a very simple example:
## An alternating linear map from V^2 to R with V=R^2:
## val
## 1 2 = 5
## An alternating linear map from V^3 to R with V=R^7:
## val
## 3 4 7 = 7
## An alternating linear map from V^5 to R with V=R^7:
## val
## 1 2 3 4 7 = 35
It looks like the combinatorial term has not been included but it
has. We will express x
and y
as tensors
(objects of class ktensor
) and show how the combinatorial
term arises.
## A linear map from V^3 to R with V=R^7:
## val
## 7 4 3 = -7
## 7 3 4 = 7
## 4 7 3 = 7
## 4 3 7 = -7
## 3 7 4 = -7
## 3 4 7 = 7
As functions, y
and ty
are identical:
## [1] 15.23211 15.23211
Both are equivalent to
7*(
+M[3,1]*M[4,2]*M[7,3]
-M[3,1]*M[4,3]*M[7,2]
-M[3,2]*M[4,1]*M[7,3]
+M[3,2]*M[4,3]*M[7,1]
+M[3,3]*M[4,1]*M[7,2]
-M[3,3]*M[4,2]*M[7,1]
)
## [1] 15.23211
We can see that y
is a more compact and efficient
representation of ty
: both are alternating tensors but
y
has alternatingness built in to its evaluation, while
ty
is alternating by virtue of including all permutations
of its arguments, with the sign of the permutation.
We can evaluate Spivak’s formula (but without the combinatorial term)
for x ∧ y by coercing
to ktensors and using tensorprod()
:
## A linear map from V^5 to R with V=R^7:
## val
## 1 2 3 4 7 = 35
## 2 1 3 7 4 = 35
## 1 2 4 3 7 = -35
## 2 1 3 4 7 = -35
## 1 2 4 7 3 = 35
## 2 1 4 3 7 = 35
## 2 1 4 7 3 = -35
## 1 2 7 3 4 = 35
## 2 1 7 3 4 = -35
## 1 2 3 7 4 = -35
## 1 2 7 4 3 = -35
## 2 1 7 4 3 = 35
Above, each coefficient is equal to ±35 (the sign coming from the sign of the permutation), and we have 2!3! = 12 rows. We can now calculate Alt (z), which would have 5! = 120 rows, one per permutation of [5], each with coefficient $\pm\frac{12\times 35}{5!}=\pm 3.5$.
We define x ∧ y to
be $\frac{5!}{3!2!}\operatorname{Alt}(z)$, so
each coefficient would be $\pm\frac{5!}{3!2!}\cdot\frac{12\times
35}{5!}=35$. We know that x ∧ y is an alternating
form. So to represent it as an object of class kform
, we
need a kform
object with single index entry
1 2 3 4 7
. This would need coefficient 35, on the grounds
that it is linear, alternating, and maps $\begin{pmatrix}
1&0&0&0&0\\
0&1&0&0&0\\
0&0&1&0&0\\
0&0&0&1&0\\
0&0&0&0&0\\
0&0&0&0&0\\
0&0&0&0&1
\end{pmatrix}$ to 35; and indeed
this is what we see:
## An alternating linear map from V^5 to R with V=R^7:
## val
## 1 2 3 4 7 = 35
So to conclude, the combinatorial term is present in the R idiom, it is just difficult to see at first glance.
First of all we should note that Λk(V)
is a vector space (this is considered in the kform
vignette). If ω, ωi ∈ Λk(V)
and η, ηi ∈ Λl(V)
then
(that is, the wedge product is left- and right- distributive); if a ∈ ℝ then
and
These rules make expansion of wedge products possible by expressing a general kform in terms of a basis for Λk(V). Spivak (1965) tells us that, if v1, …, vk is a basis for V, then the set of all
is a basis for Λk(V) where ϕi(vj) = δij. The package expresses a k-form in terms of this basis as in the following example:
## An alternating linear map from V^3 to R with V=R^8:
## val
## 1 3 7 = 6
## 1 2 8 = 5
In algebraic notation, omega
(or ω) would be 5ϕ1 ∧ ϕ2 ∧ ϕ8 + 6ϕ1 ∧ ϕ3 ∧ ϕ7
and we may write this as ω = 5ϕ128 + 6ϕ137.
To take a wedge product of this with η = 2ϕ235 + 3ϕ356
we would write
where we have used the rules repeatedly (especially the fact that ω ∧ ω = 0 for any alternating form). Package idiom would be:
## An alternating linear map from V^6 to R with V=R^8:
## val
## 1 2 3 5 6 8 = -15
See how function wedge()
does the legwork.