Function phi() function in the stokes package
Author: Robin K. S. Hankin

# Function `phi()` function in the `stokes` package

#### Robin K. S. Hankin

    phi

    function (n)
    {
        ktensor(spray(n, 1))
    }

To cite the `stokes` package in publications, please use Hankin (2022b). Function `phi()` returns a tensor dual to the standard basis of \(V=\mathbb{R}^n\). Here I discuss `phi()` but there is some overlap between this vignette and the `tensorprod` vignette.

In a memorable passage, Spivak (1965) states (theorem 4.1):

Integration on chains

Let \(v_1,\ldots,v_n\) be a basis for \(V\), and let \(\phi_1,\ldots,\phi_n\) be the dual basis, \(\phi_i(v_j)=\delta_{ij}\). Then 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 \]

is a basis for \(\mathcal{J}(V)\), which therefore has dimension \(n^k\).

- Michael Spivak, 1969 (Calculus on Manifolds, Perseus books). Page 75

Function `phi()` returns a very simple tensor:

    phi(4)

    ## A linear map from V^1 to R with V=R^4:
    ##        val
    ##  4  =    1

First we will verify the properties of `phi()`, using \(V=\mathbb{R}^5\), specifically

\[ \phi_i(e_j) = \delta_{ij} = \begin{cases} 1, & i=j\\ 0 & i\neq j. \end{cases} \]

(package idiom is to use `e()` for basis vectors as opposed to Spivak’s \(v\)). As numerical verification, we will check that \(\phi_3(e_2)=0\), \(\phi_3(e_3)=1\), \(\phi_3(e_4)=0\):

    f <- as.function(phi(3))
    c(f(as.matrix(e(2,5))), f(as.matrix(e(3,5))), f(as.matrix(e(4,5))))

    ## [1] 0 1 0

A more severe test might be

    aa <- function(n){
       outer(seq_len(n), seq_len(n),
       Vectorize(function(i, j){as.function(phi(i))(as.matrix(e(j, n)))}))
    }

    aa(5)

    ##      [,1] [,2] [,3] [,4] [,5]
    ## [1,]    1    0    0    0    0
    ## [2,]    0    1    0    0    0
    ## [3,]    0    0    1    0    0
    ## [4,]    0    0    0    1    0
    ## [5,]    0    0    0    0    1

Above, we see that the matrix is \(I_5\), as expected. Further:

    all(aa(9) == diag(9))

    ## [1] TRUE

The objects created by `phi()` may be multiplied together using `tensorprod()` or its binary operator `%X%`:

    phi(4) %X% phi(3) %X% phi(5)

    ## A linear map from V^3 to R with V=R^5:
    ##            val
    ##  4 3 5  =    1

If we want to create arbitrary tensor products of \(\phi\) objects the most natural way would be to use `tensorprod()` repeatedly:

    Reduce(`%X%`,sapply(4:8,phi))

    ## A linear map from V^5 to R with V=R^8:
    ##                val
    ##  4 5 6 7 8  =    1

However, function `phi()` simply takes a vector:

    phi(c(2,5,1))

    ## A linear map from V^3 to R with V=R^5:
    ##            val
    ##  2 5 1  =    1

This creates an element of the basis set, in this case \(\phi_2\otimes\phi_5\otimes\phi_1\). Verification is straightforward:

    (v <- sample(9))

    ## [1] 9 4 7 1 2 6 3 8 5

    phi(v) == Reduce(`%X%`,sapply(v,phi))

    ## [1] TRUE

We will consider an element \(X\) of \(\mathcal{J}^{2}(V)\) where \(V=\mathbb{R}^3\) and construct an explicit basis for it along the lines of Spivak’s observation above.

    (X <- ktensor(spray(matrix(c(1,2,3,2,1,1),3,2),1:3)))

    ## A linear map from V^2 to R with V=R^3:
    ##          val
    ##  3 1  =    3
    ##  2 1  =    2
    ##  1 2  =    1

Thus \(X=\phi_1\otimes\phi_2 +2\phi_2\otimes\phi_1 +3\phi_3\otimes\phi_1\). Spivak asserts that \(\mathcal{J}^{2}(V)\) has dimension \(n^k=3^2=9\).

    1*phi(c(1,2)) + 2*phi(c(2,1)) + 3*phi(c(3,1))

    ## A linear map from V^2 to R with V=R^3:
    ##          val
    ##  2 1  =    2
    ##  1 2  =    1
    ##  3 1  =    3

With a little effort, we can create all \(3^2=9\) elements of a basis as follows:

    apply(expand.grid(rep(list(seq_len(3)),2)),1,phi)

    ## [[1]]
    ## A linear map from V^2 to R with V=R^1:
    ##          val
    ##  1 1  =    1
    ##
    ## [[2]]
    ## A linear map from V^2 to R with V=R^2:
    ##          val
    ##  2 1  =    1
    ##
    ## [[3]]
    ## A linear map from V^2 to R with V=R^3:
    ##          val
    ##  3 1  =    1
    ##
    ## [[4]]
    ## A linear map from V^2 to R with V=R^2:
    ##          val
    ##  1 2  =    1
    ##
    ## [[5]]
    ## A linear map from V^2 to R with V=R^2:
    ##          val
    ##  2 2  =    1
    ##
    ## [[6]]
    ## A linear map from V^2 to R with V=R^3:
    ##          val
    ##  3 2  =    1
    ##
    ## [[7]]
    ## A linear map from V^2 to R with V=R^3:
    ##          val
    ##  1 3  =    1
    ##
    ## [[8]]
    ## A linear map from V^2 to R with V=R^3:
    ##          val
    ##  2 3  =    1
    ##
    ## [[9]]
    ## A linear map from V^2 to R with V=R^3:
    ##          val
    ##  3 3  =    1

Or it might be logically better to use ellipsis constructs to pass multiple arguments:

    s <- function(...){phi(unlist(list(...)))}
    s(3,4,6)

    ## A linear map from V^3 to R with V=R^6:
    ##            val
    ##  3 4 6  =    1

Then we could have

    1*s(1,2) + 2*s(2,1) + 3*s(3,1)

    ## A linear map from V^2 to R with V=R^3:
    ##          val
    ##  2 1  =    2
    ##  1 2  =    1
    ##  3 1  =    3

    1*s(1,2) + 2*s(2,1) + 3*s(3,1) == X

    ## [1] TRUE

## Distributivity

The tensor product is left- and right distributive. To illustrate this we can use the package to calculate, say, \((2\phi_1+3\phi_2)\otimes(5\phi_3+7\phi_4)\):

    (2*phi(1) + 3*phi(2)) %X% (5*phi(3) + 7*phi(4) )

    ## A linear map from V^2 to R with V=R^4:
    ##          val
    ##  2 4  =   21
    ##  1 4  =   14
    ##  2 3  =   15
    ##  1 3  =   10

Above we see package form for the result which is \(10\phi_1\phi_3 + 14\phi_1\phi_4 + 15\phi_2\phi_3 + 21\phi_2\phi_4\) in algebraic notation.

## Reconstruction of a given tensor

Consider the following tensor

    (b <- ktensor(spray(matrix(c(3,4,7,5,4,3),3,2),7:9)))

    ## A linear map from V^2 to R with V=R^7:
    ##          val
    ##  4 4  =    8
    ##  7 3  =    9
    ##  3 5  =    7

We may express \(b\) as the sum of its three terms, each with a coefficient:

    7*phi(c(3,5)) + 8*phi(c(4,4)) + 9*phi(c(7,3))

    ## A linear map from V^2 to R with V=R^7:
    ##          val
    ##  4 4  =    8
    ##  3 5  =    7
    ##  7 3  =    9

Above, observe that the order of the terms may differ between the two methods, as per `disordR` discipline (Hankin 2022a), but they are algebraically identical:

    b == 7*phi(c(3,5)) + 8*phi(c(4,4)) + 9*phi(c(7,3))

    ## [1] TRUE

## Function `Alt()`

Function `Alt()` returns an alternating tensor as documented in the `Alt` vignette in the package. It works nicely with `phi()`:

    phi(1:3)

    ## A linear map from V^3 to R with V=R^3:
    ##            val
    ##  1 2 3  =    1

    Alt(6*phi(1:3))

    ## 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

# References

Hankin, R. K. S. 2022a. “Disordered Vectors in R: Introducing the `disordR` Package.” https://arxiv.org/abs/2210.03856; arXiv. https://doi.org/10.48550/ARXIV.2210.03856.
———. 2022b. “Stokes’s Theorem in R.” arXiv. https://doi.org/10.48550/ARXIV.2210.17008.
Spivak, M. 1965. Calculus on Manifolds. Addison-Wesley.