# Clifford numbers

## Supertype and associated functions

`CliffordNumbers.AbstractCliffordNumber`

— Type`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.

**Interface**

**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.

`CliffordNumbers.nblades`

— Function```
nblades(::Type{<:Number}) -> Int
nblades(x::Number)
```

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))`

.

`CliffordNumbers.scalar_type`

— Function```
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`

.

`CliffordNumbers.similar_type`

— Function```
CliffordNumbers.similar_type(
C::Type{<: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

`CliffordNumbers.CliffordNumber`

— Type`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`

— Type`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}
```

`CliffordNumbers.EvenCliffordNumber`

— Type`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.

`CliffordNumbers.OddCliffordNumber`

— Type`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.

`CliffordNumbers.KVector`

— Type`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.

`CliffordNumbers.grade`

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

Returns the grade represented by a `KVector{K}`

, which is K.

## Promotion and conversion

`CliffordNumbers.scalar_convert`

— Function```
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`

.

**Examples**

```
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)
2.0f0
```

`CliffordNumbers.scalar_promote`

— Function`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`

.

`Base.widen`

— Method```
widen(C::Type{<:AbstractCliffordNumber})
widen(x::AbstractCliffordNumber)
```

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)`

.

`CliffordNumbers.widen_grade`

— Function```
widen_grade(C::Type{<:AbstractCliffordNumber})
widen_grade(x::AbstractCliffordNumber)
```

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

`Base.real`

— Method`real(x::AbstractCliffordNumber{Q,T})`

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.

`Base.complex`

— Method`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

`CliffordNumbers.isscalar`

— Function`isscalar(x::AbstractCliffordNumber)`

Determines whether the Clifford number `x`

is a scalar, meaning that all of its blades of nonzero grade are zero.

`CliffordNumbers.ispseudoscalar`

— Function`ispseudoscalar(m::AbstractCliffordNumber)`

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.

`CliffordNumbers.scalar`

— Function`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.

`CliffordNumbers.pseudoscalar`

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

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.

## Defining basis variables

`CliffordNumbers.@basis_vars`

— Macro`@basis_vars(Q, ::Type{T}; prefix = Metrics.blade_symbol(Q))`

Generates variables in the global scope representing the 1-blade basis elements of `Q`

.

The default prefix for most algebras is 'e', which can cause problems with multiplying through juxtaposition: Julia interprets `2e0`

as scientific notation. For the sake of clarity, use explicit multiplication (`2*e0`

) or change the prefix.

Lorentzian geometric algebras default to `γ`

as the default prefix and do not have this problem.

**Examples**

```
julia> @basis_vars(VGA(3), prefix = :σ)
```