Alt()
function in the
stokes
packagefunction (S, give_kform = FALSE)
{
if (is.kform(S)) {
return(S)
}
if (give_kform) {
return(kform(S)/factorial(arity(S)))
}
out <- kill_trivial_rows(S)
if (nrow(index(out)) == 0) {
return(S * 0)
}
ktensor(include_perms(consolidate(out))/factorial(ncol(index(out))))
}
To cite the stokes
package in publications, please use
Hankin (2022). Spivak (1965), in a memorable passage,
states:
A k-tensor Οβββπ₯(V) is called alternating if
Ο(v1,ββ¦,βvi,ββ¦,βvj,ββ¦,βvk)β=ββΟ(v1,ββ¦,βvj,ββ¦,βvi,ββ¦,βvk)βββfor all v1,ββ¦,βvkβββV.
β¦ The set of all alternating k-tensors is clearly a subspace Ξk(V) of π₯k(V). Since it requires considerable work to produce the determinant, it is not surprising that alternating k-tensors are difficult to write down. There is, however, a uniform way of expressing all of them. Recall that the sign of a permutation Ο, denoted sgnβΟ, is +1 if Ο is even and β1 if Ο is odd. If Tβββπ₯k(V), we define Altβ(T) by
$$ \operatorname{Alt}(T){\left(v_1,\ldots,v_k\right)}= \frac{1}{k!}\sum_{\sigma\in S_k}\mathrm{sgn}(\sigma)\cdot T{\left(v_{\sigma(1)},\ldots,v_{\sigma(k)}\right)} $$
where Sk is the set of all permutations of numbers 1 to k.
- Michael Spivak, 1969 (Calculus on Manifolds, Perseus books). Page 78
For example, if kβ=β3 we have
$$\operatorname{Alt}(T)\left(v_1,v_2,v_3\right)= \frac{1}{6}\left(\begin{array}{cc} +T{\left(v_1,v_2,v_3\right)}& -T{\left(v_1,v_3,v_2\right)}\cr -T{\left(v_2,v_1,v_3\right)}& +T{\left(v_2,v_3,v_1\right)}\cr +T{\left(v_3,v_1,v_2\right)}& -T{\left(v_3,v_2,v_1\right)} \end{array} \right) $$
In the stokes
package, function Alt()
performs this operation on a given k-tensor T. Idiom is straightforward:
## A linear map from V^3 to R with V=R^8:
## val
## 1 7 8 = 6
Above, object Sβ=β6Ο1β
ββ
Ο7β
ββ
Ο8,
where Οi:ββ8ββββ,
with Οi(ej)β=βΞ΄ij
[ej are
basis vectors in β8]. We may
calculate Altβ(S) in the
package using Alt()
:
## A linear map from V^3 to R with V=R^8:
## val
## 8 7 1 = -1
## 8 1 7 = 1
## 7 8 1 = 1
## 7 1 8 = -1
## 1 8 7 = -1
## 1 7 8 = 1
Above we see that Altβ(S)β=βΟ1β
ββ
Ο7β
ββ
Ο8β
ββ
Ο1β
ββ
Ο8β
ββ
Ο7β
Β±β
β―β
ββ
Ο8β
ββ
Ο7β
ββ
Ο1,
and we can see the pattern clearly, observing in passing that the order
of the rows in the R object is arbitrary (as per disordR
discipline). Now, Alt(S)
is an alternating form, which is
easy to verify, by making it act on an odd permutation of a set of
vectors:
## [1] -0.1645455 0.1645455
Observing that Altβ is linear, we might apply it to a more complicated tensor, here with two terms:
## A linear map from V^3 to R with V=R^4:
## val
## 2 2 3 = 1000
## 1 2 4 = 12
Above we have Sβ=β12Ο1β ββ Ο2β ββ Ο4β +β 1000Ο2β ββ Ο2β ββ Ο3. Calculating Altβ(S):
## A linear map from V^3 to R with V=R^4:
## val
## 2 2 3 = 1000
## 1 2 4 = 12
## A linear map from V^3 to R with V=R^4:
## val
## 4 2 1 = -2
## 4 1 2 = 2
## 2 4 1 = 2
## 2 1 4 = -2
## 1 4 2 = -2
## 1 2 4 = 2
Note that the 2 2 3
term (with coefficient 1000)
disappears in Alt(S)
: the even permutations (being
positive) cancel out the odd permutations (being negative) in pairs.
This must be the case for an alternating map by definition. We can see
why this cancellation occurs by considering Tβ=βΟ2β
ββ
Ο2β
ββ
Ο3,
a linear map corresponding to the [2 2 3]
row of
S
:
T(v1,βv2,βv3)β=β(v1β β β e2)(v2β β β e2)(v1β β β e3)x
(where xββββ is any real number and ββ β denotes the dot product), and so
T(v2,βv1,βv3)β=β(v2β β β e2)(v1β β β e2)(v3β β β e3)xβ=βT(v1,βv2,βv3).
Thus if we require T to be
alternating [that is, T(v2,βv1,βv3)β=ββT(v1,βv2,βv3)],
we must have xβ=β0, which is
why the [2 2 3]
term with coefficient 1000 vanishes (such
terms are killed in the function by applying
kill_trivial_rows()
). We can check that terms with repeated
entries are correctly discarded by taking the Altβ of a tensor all of whose entries include
at least one repeat:
## A linear map from V^4 to R with V=R^7:
## val
## 1 2 3 3 = 5
## 7 7 4 7 = 4
## 1 1 2 3 = 3
## 1 4 1 4 = 2
## 3 2 1 1 = 1
## The zero linear map from V^4 to R with V=R^n:
## empty sparse array with 4 columns
We should verify that Alt()
does indeed return an
alternating tensor for complicated tensors (this is trivial
algebraically because Altβ(β
) is
linear, but it is always good to check):
## A linear map from V^5 to R with V=R^9:
## val
## 6 1 1 1 2 = 9
## 8 6 7 6 6 = 8
## 7 6 8 7 3 = 7
## 8 2 7 7 7 = 5
## 9 8 6 9 9 = 4
## 6 6 8 9 1 = 3
## 9 2 6 4 7 = 6
## 7 3 3 8 6 = 2
## 9 7 3 4 5 = 1
Then we swap columns of V, using both even and odd permutations, to verify that Altβ(S) is in fact alternating:
V_even <- V[,c(1,2,5,3,4)] # an even permutation
V_odd <- V[,c(2,1,5,3,4)] # an odd permutation
V_rep <- V[,c(2,1,5,2,4)] # not a permutation
c(as.function(AS)(V),as.function(AS)(V_even)) # should be identical (even permutation)
## [1] 0.226959 0.226959
## [1] 0.226959 -0.226959
## [1] -1.01644e-20
Alt()
In his theorem 4.3, Spivak proves the following statements:
We have demonstrated the first point above. For the second, we need
to construct a tensor that is alternating, and then show that
Alt()
does not change it:
## A linear map from V^2 to R with V=R^2:
## val
## 1 2 = 7
## 2 1 = -7
## [1] TRUE
The third point, idempotence is also easy:
## [1] TRUE
(Main article: wedge product). Spivak defines the wedge product as follows. Given alternating forms ΟβββΞk(V) and Ξ·βββΞl(V) we have
$$ \omega\wedge\eta=\frac{(k+l)!}{k!l!}\operatorname{Alt}(\omega\otimes\eta) $$
So for example:
omega <- as.ktensor(2+diag(2),c(-7,7))
eta <- Alt(ktensor(6*spray(matrix(c(1,2,3,1,4,7,4,5,6),3,3,byrow=TRUE),1:3)))
omega
## A linear map from V^2 to R with V=R^3:
## val
## 2 3 = 7
## 3 2 = -7
## A linear map from V^3 to R with V=R^7:
## val
## 1 4 7 = 2
## 3 2 1 = -1
## 4 6 5 = -3
## 1 7 4 = -2
## 4 5 6 = 3
## 7 1 4 = 2
## 4 1 7 = -2
## 4 7 1 = 2
## 6 5 4 = -3
## 6 4 5 = 3
## 5 4 6 = -3
## 1 3 2 = -1
## 2 1 3 = -1
## 1 2 3 = 1
## 2 3 1 = 1
## 7 4 1 = -2
## 3 1 2 = 1
## 5 6 4 = 3
Above we see that omega
is alternating by construction,
and eta
is alternating by virtue of Alt()
.
Thus tensor Οβ
β§β
Ξ· is
defined as per Spivakβs definition, and we may calculate it
directly:
## An alternating linear map from V^5 to R with V=R^7:
## val
## 2 3 4 5 6 = 2.1
## 1 2 3 4 7 = 1.4
Observe that the tensor Οβ
ββ
Ξ· (which would be
returned if the default argument give_kform=FALSE
was sent
to Alt()
) is quite long, having 2β
β
β
5!β=β240 nonzero components, which is why
it is not printed in full. We may verify that f()
is
alternating by evaluating it on a randomly chosen point in (β7)5:
## [1] -0.852457 0.852457
Above we see a verification that f()
is fact
alternating: writing the matrix V
in terms of its five
vectors as Vβ=β[v1,βv2,βv3,βv4,βv5],
where viββββ7,
we see that f(v1,βv2,βv3,βv4,βv5)β=ββf(v2,βv1,βv3,βv4,βv5).
Alt()
Spivak goes on to prove the following three statements. If S,βT are tensors and Ο,βΞ·,βΞΈ are alternating tensors of arity k,βl,βm respectively, then
Taking the points in turn. Firstly Altβ(Sβ ββ T)β=βAltβ(Tβ ββ S)β=β0:
## A linear map from V^4 to R with V=R^3:
## val
## 1 1 2 3 = 1001
## 1 2 3 3 = 1000
## The zero linear map from V^4 to R with V=R^n:
## empty sparse array with 4 columns
## [1] TRUE TRUE
secondly, Altβ(Altβ(Οβ ββ Ξ·)β ββ ΞΈ)β=βAltβ(Οβ ββ Ξ·β ββ ΞΈ)β=βAltβ(Οβ ββ Altβ(Ξ·β ββ ΞΈ)):
omega <- Alt(as.ktensor(rbind(1:3),6))
eta <- Alt(as.ktensor(rbind(4:5),60))
theta <- Alt(as.ktensor(rbind(6:7),14))
omega
## A linear map from V^3 to R with V=R^3:
## val
## 3 2 1 = -1
## 3 1 2 = 1
## 2 3 1 = 1
## 2 1 3 = -1
## 1 3 2 = -1
## 1 2 3 = 1
## A linear map from V^2 to R with V=R^5:
## val
## 5 4 = -30
## 4 5 = 30
## A linear map from V^2 to R with V=R^7:
## val
## 7 6 = -7
## 6 7 = 7
f1 <- as.function(Alt(Alt(omega %X% eta) %X% theta))
f2 <- as.function(Alt(omega %X% eta %X% theta))
f3 <- as.function(Alt(omega %X% Alt(eta %X% theta)))
V <- matrix(rnorm(9*14),ncol=9)
c(f1(V),f2(V),f3(V))
## [1] -3.154794 -3.154794 -3.154794
Verifying the third identity $(\omega\wedge\eta)\wedge\theta = \omega\wedge(\eta\wedge\theta) = \frac{(k+l+m)!}{k!l!m!}\operatorname{Alt}(\omega\otimes\eta\otimes\theta)$ needs us to coerce from a k-form to a k-tensor:
omega <- rform(2,2,19)
eta <- rform(3,2,19)
theta <- rform(2,2,19)
a1 <- as.ktensor(omega ^ (eta ^ theta))
a2 <- as.ktensor((omega ^ eta) ^ theta)
a3 <- Alt(as.ktensor(omega) %X% as.ktensor(eta) %X% as.ktensor(theta))*90
c(is.zero(a1-a2),is.zero(a1-a3),is.zero(a2-a3))
## [1] TRUE TRUE TRUE
give_kform
Function Alt()
takes a Boolean argument
give_kform
. We have been using Alt()
with
give_kform
taking its default value of FALSE
,
which means that it returns an object of class ktensor
.
However, an alternating form can be much more efficiently represented as
an object of class kform
, and this is returned if
give_kform
is TRUE
. Here I verify that the two
options return identical objects:
## A linear map from V^5 to R with V=R^9:
## val
## 7 3 6 4 7 = 120
## 8 1 3 4 4 = 240
## 2 6 4 5 7 = 360
## 8 4 2 8 8 = 840
## 7 1 3 5 1 = 480
## 1 6 4 7 6 = 600
## 6 7 3 3 4 = 1080
## 9 2 3 5 3 = 720
## 6 5 6 5 4 = 960
## A ktensor object with 120 terms. Summary of coefficients:
##
## a disord object with hash 866c13390582e2f7e562be3e046abda44be30079
##
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -3 -3 0 0 3 3
##
##
## Representative selection of index and coefficients:
##
## A linear map from V^5 to R with V=R^7:
## val
## 7 6 5 4 2 = 3
## 2 6 4 7 5 = -3
## 7 4 2 6 5 = 3
## 2 7 6 4 5 = -3
## 4 6 2 5 7 = -3
## 6 5 2 4 7 = -3
Above, we see that S1
is a rather extensive object, with
120 terms. However, if argument give_kform = TRUE
is passed
to Alt()
we get a kform
object which is much
more succinct:
## An alternating linear map from V^5 to R with V=R^7:
## val
## 2 4 5 6 7 = 3
Verification that objects S1
and SA1
are
the same object:
V <- matrix(rnorm(45),ncol=5)
LHS <- as.function(S1)(V)
RHS <- as.function(SA1)(V)
c(LHS=LHS,RHS=RHS,diff=LHS-RHS)
## LHS RHS diff
## 2.386928e+01 2.386928e+01 -1.065814e-14
Above we see agreement to within numerical error.