Clifford numbers

Supertype and associated functions

AbstractCliffordNumber{Q,T} <: Number

An element of a Clifford algebra, often referred to as a multivector, with quadratic form Q and element type T. These are statically size and therefore should be able to be stored inline in arrays or other data structures.


Required implementation

All subtypes C of AbstractCliffordNumber{Q} must implement the following functions:

  • CliffordNumbers.similar_type(::Type{C}, ::Type{T}, ::Type{Q}) where {C,T,Q} should construct a

new type similar to C which subtypes AbstractCliffordNumber{Q,T} that may serve as a constructor.

  • Base.getindex(x::C, b::BitIndex{Q}) should allow one to recover the coefficients associated

with each basis blade represented by C.

  • nblades(::Type{C}) should be defined to return the number of basis blades represented by the

type. By default, nblades(x::AbstractCliffordNumber) = nblades(typeof(x)).

  • Base.Tuple(x::C) should return the tuple used to construct x. The fallback is

getfield(x, :data)::Tuple, so any type declared with a NTuple field named data should have this defined automatically.

nblades(::Type{<:Number}) -> Int

Returns the number of blades represented by a Number subtype or instance. For subtypes of Number that are not AbstractCliffordNumber, this is always 1.

This function is separate from Base.length since AbstractCliffordNumber is a scalar type for which collect() returns a zero-dimensional array. For consistency, length(x) should always equal length(collect(x)).

scalar_type(::Type{<:AbstractCliffordNumber{Q,T}}) = T
scalar_type(T::Type{<:Union{Real,Complex}}) = T
scalar_type(x) = scalar_type(typeof(x))

Returns the numeric type associated with an AbstractCliffordNumber instance. For subtypes of Real and Complex, or their instances, this simply returns the input type or instance type.

Why not define eltype?

AbstractCliffordNumber instances behave like numbers, not arrays. If collect() is called on a Clifford number of type T, it should not construct a vector of coefficients; instead it should return an Array{T,0}. Similarly, a broadcasted multiplication should return the same result as normal multiplication, as is the case with complex numbers.

For subtypes T of Number, eltype(T) === T, and this is true for AbstractCliffordNumber.

    [N::Type{<:BaseNumber} = scalar_type(C)],
    [Q::Val = Val(signature(C))]
) -> Type{<:AbstractCliffordNumber{Q,N}}

Constructs a type similar to T but with numeric type N and quadratic form Q. The quadratic form must be wrapped in a Val to preserve type stability.

This function must be defined with all its arguments for each concrete type subtyping AbstractCliffordNumber.

Concrete types

CliffordNumber{Q,T,L} <: AbstractCliffordNumber{Q,T}

A dense multivector (or Clifford number), with quadratic form Q, element type T, and length L (which depends entirely on Q).

The coefficients are ordered by taking advantage of the natural binary structure of the basis. The grade of an element is given by the Hamming weight of its index. For the algebra of physical space, the order is: 1, e₁, e₂, e₁₂, e₃, e₁₃, e₂₃, e₁₂₃ = i. This order allows for more aggressive SIMD optimization when calculating the geometric product.

CliffordNumbers.Z2CliffordNumber{P,Q,T,L} <: AbstractCliffordNumber{Q,T}

A Clifford number whose only nonzero grades are even or odd. Clifford numbers of this form naturally arise as versors, the geometric product of 1-vectors.

The type parameter P is constrained to be a Bool: true for odd grade Clifford numbers, and false for even grade Clifford numbers, corresponding to the Boolean result of each grade modulo 2.

Type aliases

This type is not exported, and usually you will want to refer to the following aliases:

const EvenCliffordNumber{Q,T,L} = Z2CliffordNumber{false,Q,T,L}
const OddCliffordNumber{Q,T,L} = Z2CliffordNumber{true,Q,T,L}
EvenCliffordNumber{P,Q,T,L} (alias for CliffordNumbers.Z2CliffordNumber{false,Q,T,L})

A Clifford number whose only nonzero grades are even. These are the natural choice of representation for rotors and motors (Euclidean isometries preserving orientation, or "proper" isometries), as well as their composition with dilations.

OddCliffordNumber{P,Q,T,L} (alias for CliffordNumbers.Z2CliffordNumber{true,Q,T,L})

A Clifford number whose only nonzero grades are odd. These are the natural choice of representation for reflections, as well as their compositions with rotors and motors (Euclidean isometries preserving orientation, or "proper" isometries), as well as their composition with dilations.

KVector{K,Q,T,L} <: AbstractCliffordNumber{Q,T}

A multivector consisting only linear combinations of basis blades of grade K - in other words, a k-vector.

k-vectors have binomial(dimension(Q), K) components.

grade(::Type{<:KVector{K}}) = K
grade(x::KVector{K}) = k

Returns the grade represented by a KVector{K}, which is K.

Promotion and conversion

scalar_convert(T::Type{<:Union{Real,Complex}}, x::AbstractCliffordNumber) -> T
scalar_convert(T::Type{<:Union{Real,Complex}}, x::Union{Real,Complex}) -> T

If x is an AbstractCliffordNumber, converts the scalars of x to type T.

If x is a Real or Complex, converts x to T.


julia> scalar_convert(Float32, KVector{1,APS}(1, 2, 3))
3-element KVector{1, VGA(3), Float32}:
1.0σ₁ + 2.0σ₂ + 3.0σ

julia> scalar_convert(Float32, 2)
scalar_promote(x::AbstractCliffordNumber, y::AbstractCliffordNumber)

Promotes the scalar types of x and y to a common type. This does not increase the number of represented grades of either x or y.


Construct a new type whose scalar type is widened. This behavior matches that of widen(C::Type{Complex{T}}), which results in widening of its scalar type T.

For obtaining a representation of a Clifford number with an increased number of nonzero grades, use widen_grade(T).


For type arguments, construct the next largest type that can hold all of the grades of C. KVector{K,Q,T} widens to EvenCliffordNumber{Q,T} or OddCliffordNumber{Q,T}, and EvenCliffordNumber{Q,T} and OddCliffordNumber{Q,T} widen to CliffordNumber{Q,T}, which is the widest type.

For AbstractCliffordNumber arguments, the argument is converted to the result of widen_grade(typeof(x)).

For widening the scalar type of an AbstractCliffordNumber, use Base.widen(T).

Real and complex algebras


Gets the real portion of each coefficient of x. For T<:Real this operation does nothing; for T<:Complex{S} this an AbstractCliffordNumber{Q,S}.

Note that this does not return the scalar (grade 0) coefficient of x. Use scalar(x) to obtain this result in general, or real(scalar(x)) if only the real portion is desired.

complex(x::AbstractCliffordNumber, [y::AbstractCliffordNumber = zero(typeof(x))])

For a single argument x, converts the type of each coefficient to a suitable complex type.

For two arguments x and y, which are both real Clifford numbers, performs the sum x + y*im, constructing a complex Clifford number.

Note that this operation does not isolate a scalar (grade 0) coefficient of x or y. Use complex(scalar(x), [scalar(y)]) to obtain this result.

Scalar and pseudoscalar components


Determines whether the Clifford number x is a scalar, meaning that all of its blades of nonzero grade are zero.


Determines whether the Clifford number x is a pseudoscalar, meaning that all of its blades with grades below the dimension of the space are zero.

scalar(x::AbstractCliffordNumber{Q,T}) -> T

Returns the scalar portion of x as its scalar type. This is equivalent to x[scalar_index(x)].

To retain Clifford number semantics, use the KVector{0} constructor.

pseudoscalar(C::Type{<:AbstractCliffordNumber{Q,T}}) -> KVector{dimension(Q),Q,T}

Returns the pseudoscalar associated with the signature Q of the argument. The result will have the same scalar type as the input if such information is given; otherwise it will use Bool as the scalar type so as to promote to any other numeric type.