--- title: "Functions `wedge()` and `wedge2()` in the `stokes` package" author: "Robin K. S. Hankin" output: html_vignette bibliography: stokes.bib vignette: > %\VignetteEngine{knitr::rmarkdown} %\VignetteIndexEntry{wedge} %\usepackage[utf8]{inputenc} --- ```{r setup, include=FALSE} set.seed(0) library("stokes") library("spray") # needed for spraycross() 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=showwedge,comment=""} wedge wedge2 ``` To cite the `stokes` package in publications, please use @hankin2022_stokes. In a memorable passage, @spivak1965 states:
$\ldots$ we would like a theorem analogous to 4.1 [the dimensionality of $k$-fold tensor products is $n^k$]. Of course, if $\omega\in\Lambda^k(V)$ and $\eta\in\Lambda^l(V)$, then $\omega\otimes\eta$ is usually not in $\Lambda^{k+l}(V)$. We will therefore define a new product, the wedge product $\omega\wedge\eta\in\Lambda^{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. ## Digression: function `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: ```{r} (a <- spray(matrix(1:4,2,2),c(2,5))) (b <- spray(matrix(c(10,11,12,13),2,2),c(7,11))) spraycross(a,b) spraycross(b,a) ``` Observe that `spraycross()` (and by association `wedge()`) is associative and distributive but not commutative. ### Cut to the chase: `wedge2()` Function `wedge2()` takes two kforms and we will start with a very simple example: ```{r} (x <- as.kform(cbind(1,2),5)) (y <- as.kform(cbind(3,4,7),7)) wedge2(x,y) ``` 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. ```{r} tx <- as.ktensor(x) # "tx" = tensor 'x' (ty <- as.ktensor(y)) # "ty" = tensor 'y' ``` As functions, `y` and `ty` are identical: ```{r} M <- matrix(round(rnorm(21),2),7,3) # member of (R^7)^3 c(as.function(y)(M),as.function(ty)(M)) ``` Both are equivalent to ```{r} 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] ) ``` 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\wedge y$ by coercing to ktensors and using `tensorprod()`: ```{r} (z <- tensorprod(as.ktensor(x),as.ktensor(y))) ``` Above, each coefficient is equal to $\pm 35$ (the sign coming from the sign of the permutation), and we have $2!3!=12$ rows. We can now calculate $\operatorname{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\wedge 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\wedge 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: ```{r} wedge(x,y) ``` So to conclude, the combinatorial term is present in the R idiom, it is just difficult to see at first glance. # Algebraic properties First of all we should note that $\Lambda^k(V)$ is a vector space (this is considered in the `kform` vignette). If $\omega,\omega_i\in\Lambda^k(V)$ and $\eta,\eta_i\in\Lambda^l(V)$ then \begin{eqnarray} (\omega_1+\omega_2)\wedge\eta &=& \omega_1\wedge\eta+\omega_2\wedge\eta\\ \omega\wedge(\eta_1+\eta_2) &=&\omega\wedge\eta_1 + \omega\wedge\eta_2\\ \end{eqnarray} (that is, the wedge product is left- and right- distributive); if $a\in\mathbb{R}$ then \begin{equation} a\omega\wedge\eta = \omega\wedge a\eta=a(\omega\wedge\eta) \end{equation} and \begin{equation} \omega\wedge\eta = (-1)^{kl}\eta\wedge\omega. \end{equation} These rules make expansion of wedge products possible by expressing a general kform in terms of a basis for $\Lambda^k(V)$. @spivak1965 tells us that, if $v_1,\ldots,v_k$ is a basis for $V$, then the set of all \begin{equation} \phi_{i_1}\wedge\phi_{i_2}\wedge\cdots\wedge\phi_{i_k}\qquad 1\leq i_1 < \cdots < i_k\leq n \end{equation} is a basis for $\Lambda^k(V)$ where $\phi_i(v_j)=\delta_{ij}$. The package expresses a $k$-form in terms of this basis as in the following example: ```{r} (omega <- as.kform(rbind(c(1,2,8),c(1,3,7)),5:6)) ``` In algebraic notation, `omega` (or $\omega$) would be $5\phi_1\wedge\phi_2\wedge\phi_8+6\phi_1\wedge\phi_3\wedge\phi_7$ and we may write this as $\omega=5\phi_{128}+6\phi_{137}$. To take a wedge product of this with $\eta=2\phi_{235}+3\phi_{356}$ we would write \begin{eqnarray} \omega\wedge\eta &=& (5\phi_{128}+6\phi_{137})\wedge (2\phi_{235}+3\phi_{356})\\ &=& 10\phi_{128}\wedge\phi_{235} + 15\phi_{128}\wedge\phi_{356} + 12\phi_{137}\wedge\phi_{235} + 18\phi_{137}\wedge\phi_{356}\\ &=& 10\phi_1\wedge\phi_2\wedge\phi_8\wedge\phi_2\wedge\phi_3\wedge\phi_5 + 15\phi_1\wedge\phi_2\wedge\phi_8\wedge\phi_3\wedge\phi_5\wedge\phi_6\\&{}&\qquad + 12\phi_1\wedge\phi_3\wedge\phi_7\wedge\phi_2\wedge\phi_3\wedge\phi_5 + 18\phi_1\wedge\phi_3\wedge\phi_7\wedge\phi_3\wedge\phi_5\wedge\phi_6\\ &=& 0+ 15\phi_1\wedge\phi_2\wedge\phi_8\wedge\phi_3\wedge\phi_5\wedge\phi_6+0+0\\ &=& -15\phi_1\wedge\phi_2\wedge\phi_3\wedge\phi_5\wedge\phi_6\wedge\phi_8 \end{eqnarray} where we have used the rules repeatedly (especially the fact that $\omega\wedge\omega=0$ for _any_ alternating form). Package idiom would be: ```{r} eta <- as.kform(rbind(c(2,3,5),c(3,5,6)),2:3) wedge(omega,eta) ``` See how function `wedge()` does the legwork. # References