--- title: "Complex arithmetic using Clifford algebra" author: "Robin K. S. Hankin" output: html_vignette bibliography: clifford.bib vignette: > %\VignetteIndexEntry{Complex arithmetic using Clifford algebra} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE) library("clifford") ``` ```{r out.width='20%', out.extra='style="float:right; padding:10px"',echo=FALSE} knitr::include_graphics(system.file("help/figures/clifford.png", package = "clifford")) ``` To cite the `clifford` package in publications please use @hankin2022_clifford. This short document shows how complex arithmetic may be implemented using Clifford algebra (of course, if one really wants to use complex numbers, base R is much more efficient and uses nicer idiom than the methods presented here). Recall that complex numbers are a two-dimensional algebra over the reals, with $(a,b)\cdot(c,d)=(ac-bd,ad+bc)$; we usually write $(a,b)$ as $a+bi$. There are two natural ways to identify complex numbers with Clifford objects; but because they use different signatures it is more convenient to treat them separately. ## First method We use $\operatorname{Cl}(0,1)$, so $e_1^2=-1$. Package idiom is straightforward; to coerce complex numbers to Clifford objects and vice versa, we need a couple of functions: ```{r label=coercionfuncs} signature(0,1) options(maxdim=1) # paranoid-level safety measure complex_to_clifford <- function(z){Re(z) + e(1)*Im(z)} clifford_to_complex <- function(C){const(C) + 1i*getcoeffs(C,1)} clifford_to_complex <- function(C){const(C) + 1i*coeffs(Im(C))} ``` Then numerical verification is immediate. First we choose some complex numbers: ```{r label=numversetup} z1 <- 35 + 67i z2 <- -2 + 12i ``` Then, for example: ```{r label=examplecoerce} z1 complex_to_clifford(z1) ``` Checking that the coercion is a homomorphism is easy: ```{r label=numverdo} complex_to_clifford(z1) * complex_to_clifford(z2) == complex_to_clifford(z1*z2) ``` Above, note that the `*` on the left is the geometric product, while the `*` on the right is the usual complex multiplication. And because the map is invertible we can check the other way too: ```{r label=otherway} (C1 <- 23 + 7*e(1)) clifford_to_complex(C1) C2 <- 2 - 8*e(1) clifford_to_complex(C1)*clifford_to_complex(C2) == clifford_to_complex(C1*C2) ``` ## Second method We use $\operatorname{Cl}(2)$, so $e_1^2=e_2^2=1$, and identify the imaginary unit $i$ with $e_{12}$ (thus $e_{12}^2=e_{12}e_{12}=e_{1212}=-e_{1122}=-e_1^2e_2^2=-1$). A general complex number $z=x+iy$ maps to Clifford object $x + ye_{12}$. ```{r label=secondcoercions} options(maxdim=2) # paranoid-level safety measure signature(2) complex_to_clifford <- function(z){Re(z) + e(1:2)*Im(z)} clifford_to_complex <- function(C){const(C) + 1i*coeffs(Im(C))} ``` Then numerical verification: ```{r label=thennumver} z1 <- 35 + 67i z2 <- -2 + 12i complex_to_clifford(z1) * complex_to_clifford(z2) == complex_to_clifford(z1*z2) ``` ```{r label=gobackwards} C1 <- 23 + 7*e(1:2) C2 <- 2 - 8*e(1:2) clifford_to_complex(C1)*clifford_to_complex(C2) == clifford_to_complex(C1*C2) ``` ### Note The identification $x+iy\longrightarrow x+ye_{12}$ is a homomorphism whenever $e_1^2e_2^2=1$; above we used $\operatorname{Cl}(2,0)$ so $e_1^2=e_2^2=1$. However, the relation is also satisfied if $e_1^2=e_2^2=-1$, so we can equally well use $\operatorname{Cl}(0,2)$: ```{r label=useothersig} signature(0,2) c( complex_to_clifford(z1)*complex_to_clifford(z2) == complex_to_clifford(z1*z2), clifford_to_complex(C1)*clifford_to_complex(C2) == clifford_to_complex(C1*C2) ) ``` ### Default It is best to return the signature and `maxdim` to their default values in order to prevent interference with other vignettes: ```{r label=restoresig} options(maxdim=NULL) signature(Inf) ``` ## References