tensorprod()
function
in the stokes
packagefunction (U, ...)
{
if (nargs() < 3) {
tensorprod2(U, ...)
}
else {
tensorprod2(U, Recall(...))
}
}
function (U1, U2)
{
if (is.empty(U1) | is.empty(U2)) {
return(as.ktensor(cbind(index(U1)[0, ], index(U2)[0,
])))
}
return(ktensor(spraycross(U1, U2)))
}
To cite the stokes
package in publications, please use
Hankin (2022b). Function
tensorprod()
returns the tensor cross product of any number
of ktensor
objects; tensorprod2()
is a
lower-level helper function that returns the product of two such
objects. These functions use spraycross()
from the
spray
package (Hankin 2022a).
In a memorable passage, Spivak (1965) states:
Integration on chains
If V is a vector space over ℝ, we denote the k-fold product V × ⋯ × V by Vk. A function T: Vk → ℝ is called multilinear if for each i with 1 ≤ i ≤ k we have
$$ T\left(v_1,\ldots, v_i + {v'}_i,\ldots, v_k\right)= T\left(v_1,\ldots,v_i,\ldots,v_k\right)+ T\left(v_1,\ldots,{v'}_i,\ldots,v_k\right),\\ T\left(v_1,\ldots,av_i,\ldots,v_k\right)=aT\left(v_1,\ldots,v_i,\ldots,v_k\right). $$
A multilinear function T: Vk → ℝ is called a k-tensor on V and the set of all k-tensors, denoted by 𝒥k(V), becomes a vector space (over ℝ) if for S, T ∈ 𝒥k(V) and a ∈ ℝ we define
$$ (S+T)(v_1,\ldots,v_k) = S(v_1,\ldots,v_k) + T(v_1,\ldots,v_k)\\ (aS)(v_1,\ldots,v_k) = a\cdot S(v_1,\ldots,v_k). $$
There is also an operation connecting the various spaces 𝒥(V). If S ∈ 𝒥k(V) and T ∈ 𝒥l(V), we define the tensor product S ⊗ T ∈ 𝒥k + l(V) by
S ⊗ T(v1, …, vk, vk + 1, …, vk + l) = S(v1, …, vk) ⋅ T(vk + 1, …, vk + l).
- Michael Spivak, 1969 (Calculus on Manifolds, Perseus books). Page 75
Spivak goes on to observe that the tensor product is distributive and associative but not commutative. He then proves that the set of all k-fold tensor products
ϕi1 ⊗ ⋯ ⊗ ϕik, 1 ≤ i1, …, ik ≤ n
[where ϕi(vj) = δij,v1, …, vk
being a basis for V] is a
basis for 𝒥k(V), which
therefore has dimension nk. Function
tensorprod()
evaluates the tensor product and I give
examples here.
## A linear map from V^2 to R with V=R^2:
## val
## 1 1 = 4
## 1 2 = 3
## A linear map from V^2 to R with V=R^7:
## val
## 4 4 = 8
## 7 3 = 9
## 3 5 = 7
Thus a = 4ϕ1 ⊗ ϕ1 + 3ϕ1 ⊗ ϕ2
and b = 7ϕ3 ⊗ ϕ5 + 8ϕ4 ⊗ ϕ4 + 9ϕ7 ⊗ ϕ3.
Now the cross product a ⊗ b is given by
tensorprod()
:
## A linear map from V^4 to R with V=R^7:
## val
## 1 2 3 5 = 21
## 1 2 7 3 = 27
## 1 1 7 3 = 36
## 1 1 3 5 = 28
## 1 2 4 4 = 24
## 1 1 4 4 = 32
We can see that the product includes the term 21ϕ1 ⊗ ϕ2 ⊗ ϕ3 ⊗ ϕ5 and five others.
Spivak proves that the tensor product is associative and distributive, which are demonstrated here.
S <- rtensor()
T <- rtensor()
U <- rtensor()
c( left_distributive = S %X% (T+U) == S*T + S*U,
right_distributive = (S+T) %X% U == S %X% U + T %X% U,
associative = S %X% (T %X% U) == (S %X% T) %X% U
)
## left_distributive right_distributive associative
## TRUE TRUE TRUE
It is interesting to note that, while the tensor product is associative, disord discipline obscures this fact. Consider the following:
x <- ktensor(spray(matrix(c(1,1,2,1),2,2),1:2))
y <- ktensor(spray(matrix(c(3,4,7,5,4,3),3,2),1:3))
z <- ktensor(spray(matrix(c(1,1,2,1),2,2),1:2))
tensorprod(x, tensorprod(y, z))
## A linear map from V^6 to R with V=R^7:
## val
## 1 1 4 4 1 1 = 8
## 1 2 3 5 1 1 = 2
## 1 1 7 3 1 1 = 12
## 1 1 3 5 1 1 = 4
## 1 2 4 4 1 2 = 2
## 1 1 4 4 1 2 = 4
## 1 2 7 3 1 2 = 3
## 1 2 7 3 1 1 = 6
## 1 1 7 3 1 2 = 6
## 1 2 4 4 1 1 = 4
## 1 2 3 5 1 2 = 1
## 1 1 3 5 1 2 = 2
## A linear map from V^6 to R with V=R^7:
## val
## 1 1 4 4 1 2 = 4
## 1 2 4 4 1 2 = 2
## 1 1 3 5 1 2 = 2
## 1 2 7 3 1 2 = 3
## 1 1 4 4 1 1 = 8
## 1 2 3 5 1 2 = 1
## 1 2 4 4 1 1 = 4
## 1 1 3 5 1 1 = 4
## 1 1 7 3 1 1 = 12
## 1 1 7 3 1 2 = 6
## 1 2 7 3 1 1 = 6
## 1 2 3 5 1 1 = 2
The two products are algebraically identical but the terms appear in a different order.
spray
Package.” https://arxiv.org/abs/2210.03856; arXiv. https://doi.org/10.48550/ARXIV.2210.10848.