CliffordNumbers.jl is a simple, statically sized multivector (Clifford number) implementation for Julia using graded representations. This allows for common multivector operations, particularly the various products of geometric algebra, to be easily implemented with extremely high performance (faster than matrix multiplications of matrix representations) without depending on any linear algebra library. Additionally, the multivectors provided by this package can be stored inline in arrays or other data structures.
Clifford algebras are algebras of orthonormality: they expand a real or complex vector space with a notion of normal vectors (those with unit square, or unit magnitude) and orthogonal vectors.
The term "geometric algebra" is synonymous in a mathematical sense with Clifford algebra, but is used by a practicioners of a new pedagogical movement to emphasize their use in applied mathematics. In particular, additive representations are favored over matrix representations for reasons of clarity, and the package implements all representations of elements and operations on them in this manner.
If you work with 3D graphics, you may already be familiar with the use of Clifford algebras: the quaternions used to represent rotation are a Clifford algebra. Specifically, they are isomorphic to the even subalgebra of the algebra of physical space, and the elements represent rotations in 3D. The full algebra of physical space augments rotations with reflections, allowing any point isometry (combined with dilations) to be represented.
Clifford algebras are also ubiquitous in physics, as the orthonormality relationship applies to 3D space and (3+1)D spacetime. The Pauli matrices are a matrix representation of the algebra of physical space, and the Dirac matrices are a matrix representation of the spacetime algebra. These Clifford algebras naturally extend vector algebra, and even allow for calculus to be done with them.
Here is a short guide to the most commonly used algebras, which can be extended to any number of dimensions.
Elements of all of the above algebras are constructible in this package.
This package exports AbstractCliffordNumber{Q,T}
and its subtypes, which describe the behavior of
multivectors with algebra Q
and scalar type T<:Union{Real,Complex}
. This is a subtype of
Number
, and therefore acts as a scalar for the purpose of broadcasting. For this reason, we
provide an nblades
function separate from Base.length
to count the number of blades represented
by a type.
To index an AbstractCliffordNumber
, we provide the BitIndex{Q}
type, which allows for arbitrary
components to be indexed, and the BitIndices{Q,C<:AbstractCliffordNumber{Q}}
type, which provides
all valid indices of instances of C
that are not constrained to be zero. Indexing with ordinary
integers is disallowed, but Tuple(::AbstractCliffordNumber)
obtains the backing Tuple
.
AbstractCliffordNumber{Q,T}
includes the following concrete subtypes:
CliffordNumber{Q,T,L}
, which represents the coefficients associated with all basis blades.EvenCliffordNumber{Q,T,L}
and OddCliffordNumber{Q,T,L}
, which represents multivectors with
only basis blades of even or odd grade being nonzero. These are especially important when dealing
with physically realizable Euclidean transformations (rotations and translations).KVector{K,Q,T,L}
, which represents multivectors with only basis blades of grade K
being
nonzero. This is especially useful for representing common vectors, bivectors, pseudovectors, etc.The type promotion system is heavily leveraged to minimize the memory footprint needed to represent
the results of various operations. Promotion can convert the numeric types associated with two
AbstractCliffordNumber{Q}
instances (for instance, the sum of KVector{1,APS,Int}
and
KVector{1,APS,Float64}
is KVector{1,APS,Float64}
), but it can also leverage grade information to
promote to smaller types: the sum of KVector{1,APS,Int}
and KVector{3,APS,Int}
is an
OddCliffordNumber{APS,Int}
, but the sum of KVector{1,APS,Int}
and KVector{2,APS,Int}
is a
CliffordNumber{APS,Int}
.
We provide the scalar_promote
and scalar_convert
functions to allow for promotion of the scalar
types backing an AbstractCliffordNumber
without needlessly expanding the represented grades.
Although AbstractCliffordNumber
instances are scalars, the BitIndex{Q}
type can be used to
retrieve coefficients associated with specific basis blades. The full set of BitIndex{Q}
types for
some x::AbstractCliffordNumber
can be generated with BitIndices(x)
, and this is a binary ordered
vector of BitIndex{Q}
objects.
Mathematical operations are defined generically by working with the BitIndex{Q}
objects associated
with an AbstractCliffordNumber{Q,T}
. Elementwise operations on each element of a BitIndices
instance returns a TransformedBitIndices
, a wrapper which lazily associates a function with a
BitIndices
object, and this can be used to implement grade dependent operations, such as
(anti)automorphisms.
The following mathematical operations are supported by this package:
+
), subtraction and negation (-
) between algebra elements, or between algebra
elements and scalars*
)∧
) and regressive product (∨
)⨼
) and right (⨽
) contractions×
) and anticommutator product (⨰
)/
) and right (\
) division, including rational division (//
)muladd
operations involving scalars and multivectorsBase.adjoint
/'
or Base.reverse
), grade_involution
)Base.conj
)left_complement
and right_complement
)abs2
and abs
)Some of the names or implementations of various operations may change in the near future.
Note that AbstractCliffordNumber{Q,T}
is a scalar type, so dotted operators do not apply any
operations to each coefficient individually. However, they can be used to perform elementwise
operations on collections of Clifford numbers.
The inspiration for this work was the textbook Geometric Algebra for Computer Science (popularly abberviated to GA4CS) by Leo Dorst, Daniel Fontijne, and Stephen Mann. Originally, this package was written as an exercise to implement much of the library described in the book, but I decided to publish it once I was able to figure out how to optimize multivector products.
I also want to acknowledge the community at bivector.net, particularly its associated Discord server, for providing me with a large amount of knowledge regarding geometric algebras. Particular community members I'd like to acknowledge include:
This work is dedicated to my best friends: Dr. Michael Davies (@medav), Kristel Forlano, and Danica Gressel (@DanicaGressel).