---
title: "Function `tensorprod()` function in the `stokes` package"
author: "Robin K. S. Hankin"
output: html_vignette
bibliography: stokes.bib
link-citations: true
vignette: >
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteIndexEntry{tensorprod}
  %\usepackage[utf8]{inputenc}
---

```{r setup, include=FALSE}
set.seed(0)
library("spray")
library("stokes")
options(rmarkdown.html_vignette.check_title = FALSE)
knitr::opts_chunk$set(echo = TRUE)
knit_print.function <- function(x, ...){dput(x)}
registerS3method(
  "knit_print", "function", knit_print.function,
  envir = asNamespace("knitr")
)
```

```{r out.width='20%', out.extra='style="float:right; padding:10px"',echo=FALSE}
knitr::include_graphics(system.file("help/figures/stokes.png", package = "stokes"))
```

```{r, label=showAlt,comment=""}
tensorprod
tensorprod2
```

To cite the `stokes` package in publications, please use
@hankin2022_stokes.  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
[@hankin2022_spray].

### The tensor cross product

In a memorable passage, @spivak1965 states:

<div class="warning" style='padding:0.1em; background-color:#E9D8FD; color:#69337A'>
<span>
<p style='margin-top:1em; text-align:center'>
<b>Integration on chains</b></p>
<p style='margin-left:1em;'>

If $V$ is a vector space over $\mathbb{R}$, we denote the $k$-fold
product $V\times\cdots\times V$ by $V^k$.  A function $T\colon
V^k\longrightarrow\mathbb{R}$ is called *multilinear* if for each $i$
with $1\leqslant i\leqslant 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\colon V^k\longrightarrow\mathbb{R}$ is
called a *$k$-tensor* on $V$ and the set of all $k$-tensors, denoted
by $\mathcal{J}^k(V)$, becomes a vector space (over $\mathbb{R}$) if
for $S,T\in\mathcal{J}^k(V)$ and $a\in\mathbb{R}$ 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
$\mathcal{J}(V)$.  If $S\in\mathcal{J}^k(V)$ and
$T\in\mathcal{J}^l(V)$, we define the *tensor product* $S\otimes
T\in\mathcal{J}^{k+l}(V)$ by

$$
S\otimes T(v_1,\ldots,v_k,v_{k+1},\ldots,v_{k+l})=
S(v_1,\ldots,v_k)\cdot T(v_{k+1},\ldots,v_{k+l}).
$$


</p>
<p style='margin-bottom:1em; margin-right:1em; text-align:right; font-family:Georgia'> <b>- Michael Spivak, 1969</b> <i>(Calculus on Manifolds, Perseus books).  Page 75</i>
</p></span>
</div>

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

$$
\phi_{i_1}\otimes\cdots\otimes\phi_{i_k},\qquad 1\leqslant
i_1,\ldots,i_k\leqslant n
$$

[where $\phi_i(v_j)=\delta_{ij}$,$v_1,\ldots,v_k$ being a basis for
$V$] is a basis for $\mathcal{J}^k(V)$, which therefore has dimension
$n^k$.  Function `tensorprod()` evaluates the tensor product and I
give examples here.

```{r}
(a <- ktensor(spray(matrix(c(1,1,2,1),2,2),3:4)))
(b <- ktensor(spray(matrix(c(3,4,7,5,4,3),3,2),7:9)))
```

Thus $a=4\phi_1\otimes\phi_1+3\phi_1\otimes\phi_2$ and
$b=7\phi_3\otimes\phi_5+8\phi_4\otimes\phi_4+9\phi_7\otimes\phi_3$.
Now the cross product $a\otimes b$ is given by `tensorprod()`:

```{r}
tensorprod(a,b)
```

We can see that the product includes the term
$21\phi_1\otimes\phi_2\otimes\phi_3\otimes\phi_5$ and five others.

## Verification

Spivak proves that the tensor product is associative and distributive,
which are demonstrated here.

```{r}
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
  )
```

### Note on associativity

It is interesting to note that, while the tensor product is
associative, disord discipline obscures this fact.  Consider the
following:


```{r}
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))
tensorprod(tensorprod(x, y), z)
```

The two products are algebraically identical but the terms appear in a
different order.

```{r echo=FALSE}
rm(T)  # tidyup
```


# References