Skip to contents

To cite the clifford package in publications please use Hankin (2022). This short document shows a nice application of Clifford algebras to linear algebra. Suppose we have vectors a,b,c spanning R3 and are given xR3. We wish to write x=αa+βb+γc for some α,β,γR. The traditional Cramer’s rule for finding α,β,γ would be

α=det[x1b1c1x2b2c2x3b3c3]det[a1b1c1a2b2c2a3b3c3]β=det[a1x1c1a2x2c2a3x3c3]det[a1b1c1a2b2c2a3b3c3]γ=det[a1b1x1a2b2x2a3b3x3]det[a1b1c1a2b2c2a3b3c3]

where x=(x1,x2,x3)T, a=(a1,a2,a3)T, b=(b1,b2,b3)T and c=(c1,c2,c3)T. However, observe that this solution, while accurate, requires one to take a coordinate basis; and offers little in the way of intuition.

Using Clifford algebra

Considering R3 as a vector space and given vectors a,b,c spanning the space we can express any vector xR3 as

x=(xbcabc)a+(axcabc)b+(abxabc)c

which is Cramer’s rule expressed directly in vector form (rather than components). Observe that the numerator and denominator of each bracketed term is a pseudoscalar; the ratio of two pseudoscalars is an ordinary scalar. Package idiom is straightforward:

a <- as.1vector(runif(3))
b <- as.1vector(runif(3))
c <- as.1vector(runif(3))

(x <- as.1vector(1:3))
## Element of a Clifford algebra, equal to
## + 1e_1 + 2e_2 + 3e_3
options(maxdim = 3)  # needed to drop() pseudoscalars
abc <- drop(a ^ b ^ c)

alpha <- drop(x ^ b ^ c)/abc
beta  <- drop(a ^ x ^ c)/abc
gamma <- drop(a ^ b ^ x)/abc

c(alpha,beta,gamma)
## [1] -3.805997 -5.328439  8.309581
alpha*a + beta*b + gamma*c
## Element of a Clifford algebra, equal to
## + 1e_1 + 2e_2 + 3e_3
Mod(alpha*a + beta*b + gamma*c-x)
## [1] 0

Thus we have expressed x (except for possible roundoff error) as a linear combination of a,b,c, specifically x=αa+βb+γc. Conversely, we might know the coefficients and try to determine them using package idiom. Here we will use 1,2,3 and suppose that y=1a+2b+3c:

y <- a*1 + b*2 + c*3
c(
    drop(y ^ b ^ c)/abc,
    drop(a ^ y ^ c)/abc,
    drop(a ^ b ^ y)/abc
)
## [1] 1 2 3

Higher dimensional space

To accomplish this in arbitrary-dimensional space is straightforward. Here we consider R5:

n <- 5                                                 # dimensionality of space
options(maxdim=5)                                      # safety precaution
x <- as.1vector(seq_len(n))                            # target vector
x
## Element of a Clifford algebra, equal to
## + 1e_1 + 2e_2 + 3e_3 + 4e_4 + 5e_5
L <- replicate(n,as.1vector(rnorm(n)),simplify=FALSE)  # spanning vectors
subst <- function(L,n,x){L[[n]] <- x; return(L)}       # list substitution
coeff <- function(n,L,x){
      drop(Reduce(`^`,subst(L,n,x))/Reduce(`^`,L))
}

Then the coefficients are given by:

(alpha <- sapply(seq_len(n),coeff,L,x))
## [1]  21.610237  27.030973  11.866383 -22.222116   3.199427

and we can reconstitute vector x:

out <- as.clifford(0)
f <- function(i){alpha[i]*L[[i]]}
for(i in seq_len(n)){
      out <- out + f(i)
}
Mod(out-x)  # zero to numerical precision
## [1] 2.340649e-14

Or, somewhat slicker:

Reduce(`+`,sapply(seq_len(n),f,simplify=FALSE))
## Element of a Clifford algebra, equal to
## + 1e_1 + 2e_2 + 3e_3 + 4e_4 + 5e_5

Conversely, if we know the coefficients are, say, 15:11, then we would have

coeffs <- 15:11
x <- 0
for(i in seq_len(5)){x <- x + coeffs[i]*L[[i]]}
x
## Element of a Clifford algebra, equal to
## + 29.23618e_1 + 18.68409e_2 + 20.23065e_3 - 0.6361232e_4 - 40.82507e_5

And then to find the coefficients:

sapply(seq_len(n),coeff,L,x)
## [1] 15 14 13 12 11

Above we see that the original coefficients are recovered, up to numerical accuracy.

References

Hankin, R. K. S. 2022. “Clifford Algebra in R.” arXiv. https://doi.org/10.48550/ARXIV.2209.13659.