Antiassociative algebras with R: the `evitaicossa` package

knitr::opts_chunk$set(echo = TRUE)
options(rmarkdown.html_vignette.check_title = FALSE)
library("evitaicossa")
set.seed(1)
knitr::include_graphics(system.file("help/figures/evitaicossa.png", package = "evitaicossa"))

Here I introduce the evitaicossa R package for antiassociative algebras. An algebra is a vector space in which the vectors possess a bilinear product. Formally, a vector space is a set $V$ of vectors which form an Abelian group under addition and also satisfy the following axioms:

Above, $\mathbf{u},\mathbf{v}\in V$ are vectors, $a,b$ are scalars [here the real numbers], and $1$ is the multiplicative identity. We also require a bilinear vector product, mapping pairs of vectors to vectors; vector multiplication is denoted using juxtaposition, as in $\mathbf{u}\mathbf{v}$, which satisfies the following axioms:

Note the absence of commutativity and associativity. Associative algebras seem to be the most common, and examples would include multivariate polynomials [@hankin2022_mvp,@hankin2022_spray], Clifford algebras [@hankin2022_clifford], Weyl algebras [@hankin2022_weyl_arxiv], and free algebras [@hankin2022_freealg]. Non-associative algebras would include the octonions [@hankin2006_onion] and Jordan algebras [@hankin2023_jordan]. Here I consider antiassociative algebras in which the usual associativity relation $\mathbf{u}(\mathbf{v}\mathbf{w})=(\mathbf{u}\mathbf{v})\mathbf{w}$ is replaced by the relation $\mathbf{u}(\mathbf{v}\mathbf{w})=-(\mathbf{u}\mathbf{v})\mathbf{w}$.

Antiassociative algebras

Algebras satisfying $\mathbf{u}(\mathbf{v}\mathbf{w})=-(\mathbf{u}\mathbf{v})\mathbf{w}$ exhibit some startling behaviour. Firstly, in the vector space there are no scalars except for $0\in\mathbb{R}$. Proof: for any $x\in\mathbb{R}$, we have $x^3=x(xx)=-(xx)x=-x^3$; thus $x^3=-x^3$, so $x=0$. Secondly, antiassociative algebras are nilpotent of order 4:

$$ (\mathbf{a}\mathbf{b})(\mathbf{c}\mathbf{d}) = -\mathbf{a}(\mathbf{b}(\mathbf{c}\mathbf{d})) = \mathbf{a}((\mathbf{b}\mathbf{c})\mathbf{d}) = -(\mathbf{a}(\mathbf{b}\mathbf{c}))\mathbf{d} = ((\mathbf{a}\mathbf{b})\mathbf{c})\mathbf{d} = -(\mathbf{a}\mathbf{b})(\mathbf{c}\mathbf{d}) $$

We see that $(\mathbf{a}\mathbf{b})(\mathbf{c}\mathbf{d})=-(\mathbf{a}\mathbf{b})(\mathbf{c}\mathbf{d})$ so $\mathbf{a}\mathbf{b}\mathbf{c}\mathbf{d}$ (however bracketed) must be zero.

The free antiassociative algebra

We consider vector spaces generated by a finite alphabet of symbols $\mathbf{x}_1,\ldots,\mathbf{x}_n$. These will be denoted generally by a single letter, as in $\mathbf{a},\mathbf{b},\ldots,\mathbf{z}$. We now consider the algebra spanned by products of linear combinations of these symbols, subject only to the axioms of an algebra [and the antiassociative relation $\mathbf{u}(\mathbf{v}\mathbf{w})=-(\mathbf{u}\mathbf{v})\mathbf{w}$]. Given an alphabet $\mathbf{x}_1,\ldots,\mathbf{x}_n$, the general form of an element of an antiassociative algebra will be

$$ \sum_{i}\alpha_i\mathbf{x}i + \sum{i,j}\alpha_{ij}\mathbf{x}i\mathbf{x}_j+ \sum{i,j,k}\alpha_{ijk}(\mathbf{x}_i\mathbf{x}_j)\mathbf{x}_k $$

(see @remm2024antiassociative for a proof, but note that she uses $\mathbf{x}i(\mathbf{x}_j\mathbf{x}_k)$ rather than $(\mathbf{x}_i\mathbf{x}_j)\mathbf{x}_k$ for the triple products; a brief discussion is given in the appendix). In the package, the components of the first term $\sum{i}\alpha_i\mathbf{x}i$ are known as "single-symbol" terms [$\mathbf{x}_i$] and coefficients [$\alpha_i$] respectively. Similarly, the components of $\sum{i,j}\alpha_{ij}\mathbf{x}i\mathbf{x}_j$ are known as the "double-symbol" terms and coefficients; and the components of $\sum{i,j,k}\alpha_{ijk}(\mathbf{x}_i\mathbf{x}_j)\mathbf{x}_k$ are the "triple-symbol" terms and coefficients.

Addition is performed elementwise among the single-, double-, and triple- components; the result is the (formal) composition of the three results. Given

$$A= \sum_{i}\alpha_i\mathbf{x}i + \sum{i,j}\alpha_{ij}\mathbf{x}i\mathbf{x}_j+ \sum{i,j,k}\alpha_{ijk}(\mathbf{x}_i\mathbf{x}_j)\mathbf{x}_k $$

$$B= \sum_{i}\beta_i\mathbf{x}i + \sum{i,j}\beta_{ij}\mathbf{x}i\mathbf{x}_j+ \sum{i,j,k}\beta_{ijk}(\mathbf{x}_i\mathbf{x}_j)\mathbf{x}_k $$

(where the sums run from $1$ to $n$), we define the sum $A+B$ to be

$$ \sum_{i}(\alpha_i+\beta_i)\mathbf{x}i + \sum{i,j}(\alpha_{ij}+\beta_{ij})\mathbf{x}i\mathbf{x}_j+ \sum{i,j,k}(\alpha_{ijk}+\beta_{ijk})(\mathbf{x}_i\mathbf{x}_j)\mathbf{x}_k $$

Multiplication is slightly more involved. We define the product $AB$ to be

$$ \sum_{i,j}\alpha_i\beta_{ij}\mathbf{x}i\mathbf{x}_j +\sum{i,j,k}\alpha_{ij}\beta_{k}(\mathbf{x}i\mathbf{x}_j)\mathbf{x}_k -\sum{i,j,k}\alpha_i\beta_{jk}(\mathbf{x}_i\mathbf{x}_j)\mathbf{x}_k. $$

The minus sign in front of the third term embodies antiassociativity.

The evitaicossa package

The evitaicossa package implements these relations in the context of an R-centric suite of software. I give some examples of the package in use. A good place to start is function raaa(), which returns a simple random element of the free antiassociative algebra:

raaa()

(the default alphabet for this command is $\left\lbrace\mathbf{a},\mathbf{b},\mathbf{c},\mathbf{d}\right\rbrace$). We see the print method for the package which shows some of the structure of the object. This one has some single-symbol elements, some double-symbol and some triple-symbol elements.

It is possible to create elements using the aaa() or as.aaa() functions:

x  <- as.aaa(c("p","q","r"))
x1 <- aaa(s1 = c("p","r","x"),c(-1,5,6))
y <- aaa(d1 = letters[1:3],d2 = c("foo","bar","baz"),dc=1:3)
z <- aaa(
    t1 = c("bar","bar","bar"),
    t2 = c("q","r","s"),
    t3 = c("foo","foo","bar"),
    tc = 5:7)

And then apply arithmetic operations to these objects:

x
x1
x+x1

(above, note the cancellation in x+x1). Multiplication is also implemented (package idiom is to use an asterisk *):

x*(x1+y)

Check:

x*(x1+y) == x*x1 + x*y

We end with a remarkable identity:

$$ (\mathbf{a}+\mathbf{a}\mathbf{x})(\mathbf{b} + \mathbf{x}\mathbf{b})=\mathbf{a}\mathbf{b} $$

Numerically:

a <- raaa()
b <- raaa()
x <- raaa()
(a+a*x)*(b+x*b) == a*b

Extract and replace methods

Because of the tripartite nature of antiassociative algebra, the package provides three families of extraction methods: single(), double() and triple(), which return the different components of an object:

a
single(a)
double(a)
triple(a)

The corresponding replacement methods are also implemented:

single(a) <- 0
a
double(a) <- double(b) * 1000
a

Square bracket extraction and replacement is also implemented:

(a <- raaa(s=5))
a[s1=c("c","e"),t1="c",t2="d",t3="d"]

Above we pass named arguments (\code{s1} et seq.) and the appropriate aaa object is returned. Zero coeffients are discarded. This mode also implements replacement methods:

(a <- raaa(s=5))
a[s1="a",d1=c("c","w"),d2=c("d","w")] <- 888
a

The other square bracket method is to pass an (unnamed) character vector:

(a <- raaa())

Note on disordR discipline

If we try to access the symbols or coefficients of an aaa object [functions s1() and sc() respectively], we get a disord object [@hankin2022_disordR]. Suppose we wish to extract the single-symbol terms and the single-symbol coefficients:

x
s1(x)
sc(x)

See how the hash codes of the symbols and coeffients match. However, the double-symbol terms and coefficients, while internally matching, differ from the single-symbol stuff:

list(d1(x),d2(x),dc(x))

Above, see how the double-symbol terms and double-symbol coefficients have consistent hashes, but do not match the single-symbol objects (or indeed the triple-symbol objects).

Matrix index extraction

If square bracket extraction is given an index that is a matrix, it is interpreted rowwise:

l <- letters[1:3]
(a <- aaa(s1=l,sc=1:3, d1=l,d2=rev(l),dc=3:1,t1=l,t2=l,t3=rev(l),tc=1:3))
a[cbind(l,l)]
a[cbind(rev(l),l,l)] <- 88
a

Note on generalized antiassociativity

We may generalize antiassociativity to $\mathbf{a}(\mathbf{b}\mathbf{c})=k(\mathbf{a}\mathbf{b})\mathbf{c}$. Thus associativity is recovered if $k=1$ and antiassociativity if $k=-1$. Then the nilpotence argument becomes:

$$ (\mathbf{a}\mathbf{b})(\mathbf{c}\mathbf{d}) = k^{-1}\mathbf{a}(\mathbf{b}(\mathbf{c}\mathbf{d})) = \mathbf{a}((\mathbf{b}\mathbf{c})\mathbf{d}) = k(\mathbf{a}(\mathbf{b}\mathbf{c}))\mathbf{d} = k^2((\mathbf{a}\mathbf{b})\mathbf{c})\mathbf{d} = k(\mathbf{a}\mathbf{b})(\mathbf{c}\mathbf{d}) $$

The value of $k$ may be set at compile-time by editing file src/anti.h. The line in question reads:

#define K -1 // a(bc) == K(ab)c

but it is possible to change the value of K. Note that this will cause test_aac.R, one of the testthat suite, to fail R CMD check.

Appendix

As noted above, @remm2024antiassociative uses $\mathbf{x}_i(\mathbf{x}_j\mathbf{x}_k)$ rather than $(\mathbf{x}_i\mathbf{x}_j)\mathbf{x}_k$ for the triple products. I chose the latter because R idiom for multiplication is left associative:

x <- 3
class(x) <- "foo"
`*.foo` <- function(x,y){x + y + x}
print.foo <- function(x){print(unclass(x))}
c(`(x*x)*x` = (x*x)*x,  `x*(x*x)` = x*(x*x),  `x*x*x` = x*x*x)

Above we see that x*x*x is interpreted as (x*x)*x, which is why the sign convention in the package was adopted.

References



Try the evitaicossa package in your browser

Any scripts or data that you put into this service are public.

evitaicossa documentation built on June 28, 2024, 5:08 p.m.