Clifford numbers
Supertype and associated functions
CliffordNumbers.AbstractCliffordNumber
— TypeAbstractCliffordNumber{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 toC
which subtypesAbstractCliffordNumber{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 byC
.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 constructx
. The fallback isgetfield(x, :data)::Tuple
, so any type declared with aNTuple
field nameddata
should have this defined automatically.
CliffordNumbers.nblades
— Functionnblades(::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
— Functionscalar_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
— FunctionCliffordNumbers.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
.
Note on function export
This function is nearly identical in semantics to StaticArraysCore.similar_type
. However, since this package does not depend on StaticArraysCore
, this function is not exported to avoid name conflicts whenever any package exporting StaticArraysCore.similar_type
is loaded.
If a package exports StaticArraysCore.similar_type
, that function will have methods added which match the methods in this package with the same signature. This may be triggered explicitly if desired with a using
or import
directive.
Concrete types
CliffordNumbers.CliffordNumber
— TypeCliffordNumber{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
— TypeCliffordNumbers.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
— TypeEvenCliffordNumber{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
— TypeOddCliffordNumber{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
— TypeKVector{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
— Methodgrade(::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
— Functionscalar_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
— Functionscalar_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
— Methodwiden(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
— Functionwiden_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
— Methodreal(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
— Methodcomplex(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
— Functionisscalar(x::AbstractCliffordNumber)
Determines whether the Clifford number x
is a scalar, meaning that all of its blades of nonzero grade are zero.
CliffordNumbers.ispseudoscalar
— Functionispseudoscalar(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
— Functionscalar(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
— Functionpseudoscalar(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 = :σ)