---
title: "Matrices with quaternion or octonion entries: class `onionmat` in the `onion` package"
author: "Robin K. S. Hankin"
output: html_vignette
bibliography: onionpaper.bib
vignette: >
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteIndexEntry{onionmat}
  %\usepackage[utf8]{inputenc}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
options(rmarkdown.html_vignette.check_title = FALSE)
library("onion")
set.seed(1)
```

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

## Introduction

To cite the `onion` package in publications please use
@hankin2006_onion.  This short document shows how matrices with
octonion or quaternion entries may be created and manipulated with the
`onionmat` class of the `onion` R package.

## `onionmat` objects

A good place to start is function `romat()`, which creates a simple
`onionmat` object:

```{r}
set.seed(0)
options(digits=2)
romat()
```

This illustrates many features of the package.  An `onionmat` object
has two slots.  The first slot, `x`, is an onion [a vector of
quaternions or octonions] and the second, `M`, an integer matrix
which is used to store attributes such as dimensions and dimnames.
The elements of `M` and `d` are in bijective correspondence; thus
element `[b,AR]` is number 17 and this is seen to be approximately
$-0.81 + 0.24i -1.43j +0.37k$.  Most R idiom will work with such
objects, here is a brief sample.

```{r}
A <- matrix(rquat(21),7,3)  # matrix() calls onion::onionmat()
A
```

See above how object `A` has no rownames or colnames and the defaults are used.  We may extract components:

```{r}
A[1,]
```

above, the resulting object is an onion but we may retain the onionmat character using `drop`:

```{r}
A[1,,drop=FALSE]
```


The extraction methods operate as expected:

```{r}
Re(A)
k(A)
```


(above, the matrices returned are numeric).  Also replacement methods work as expected:

```{r}
j(A) <- -1
A
```

Some of the summary methods work:

```{r}
sum(A)
```

## Matrix multiplication

Matrix multiplication is implemented.


```{r}
A <- matrix(rquat(21),3,7)
umbral <- state.abb[1:7]
rownames(A) <- letters[1:3]
colnames(A) <- umbral

B <- matrix(rquat(28),7,4)
rownames(B) <- umbral
colnames(B) <- c("H","He","Li","Be")

A %*% B
```


However, it is often preferable (but no faster in this case) to use
functions such as `cprod()` and `tcprod()`:


```{r}
C <- matrix(rquat(14),7,2)
rownames(C) <- umbral
colnames(C) <- month.abb[1:2]
cprod(B,C)
```

and indeed the single-argument versions work as expected:

```{r}
tcprod(A) - A %*% ht(A)
```


## Octonions

Here I consider $3\times 3$ Hermitian octonionic matrices which are
known be a special case of a Jordan algebra (see the `jordan` package
for more systematic Jordan algebra R functionality).

```{r}
x <- cprod(matrix(roct(12),4,3))
x
```

We see that `x` is Hermitian symmetric:

```{r}
max(Mod(Im(x+t(x))))
```

[that is, the imaginary components of symmetrically placed elements
are mutually conjugate].  We may verify that $3\times 3$ matrices form
a Jordan algebra under the composition rule $A\circ B=(AB+BA)/2$
[juxtaposition indicating regular matrix multiplication]; the identity is 

\[(xy)(xx) = x(y(xx)).\]

First we define the Jordan product:

```{r}
`%o%` <- function(x,y){(x%*%y + y%*%x)/2}
```

then create a couple of random Hermitian octonionic matrices:

```{r}
x <- cprod(matrix(roct(12),4,3))
y <- cprod(matrix(roct(12),4,3)) # x and y are 3-by-3 Hermitian octonionic matrices
```

We first verify numerically that the Jordan product of two Hermitian
symmetric matrices is Hermitian:

```{r}
jj <- x %o% y
max(Mod(Im(jj+t(jj))))
```

then verify the Jordan identity:

```{r}
LHS <- (x %o% y) %o% (x %o% x)
RHS <- x %o% (y %o% (x %o% x))
max(Mod(LHS-RHS))  # zero to numerical precision
```

showing that the Jordan identity is satisfied, up to a small numerical
tolerance.  However, $4\times 4$ octonionic matrices do not satisfy
the Jordan identity:

```{r}
x <- cprod(matrix(roct(16),4,4))
y <- cprod(matrix(roct(16),4,4)) # x and y are 4-by-4 Hermitian octonionic matrices
LHS <- (x %o% y) %o% (x %o% x)
RHS <- x %o% (y %o% (x %o% x))
max(Mod(LHS-RHS))  # miles off
```


## Note on the print method

Above we have been using the default print method but it is possible
to use a more compact notation, which is useful if a matrix has many
short entries.


```{r}
o <- rsomat()
o
options(show_onionmats_in_place = TRUE)
o
```
