Mathematical operations
Involutions and duals
Base.reverse
— Methodreverse(i::BitIndex) = i' -> BitIndex
reverse(x::AbstractCliffordNumber) = x' -> typeof(x)
Performs the reverse operation on the basis blade indexed by b
or the Clifford number x
. The sign of the reverse depends on the grade of the basis blade g
, and is positive for g % 4 in 0:1
and negative for g % 4 in 2:3
.
Base.adjoint
— Methodadjoint(i::BitIndex) = i' -> BitIndex
adjoint(x::AbstractCliffordNumber) = x' -> typeof(x)
An alias for reverse(i::BitIndex)
used to implement operator notation.
CliffordNumbers.grade_involution
— Methodgrade_involution(i::BitIndex) -> BitIndex
grade_involution(x::AbstractCliffordNumber) -> typeof(x)
Calculates the grade involution of the basis blade indexed by b
or the Clifford number x
. This effectively reflects all of the basis vectors of the space along their own mirror operation, which makes elements of odd grade flip sign.
Base.conj
— Methodconj(i::BitIndex) -> BitIndex
conj(x::AbstractCliffordNumber) -> typeof(x)
Calculates the Clifford conjugate of the basis blade indexed by b
or the Clifford number x
. This is equal to grade_involution(reverse(x))
.
CliffordNumbers.left_complement
— Methodleft_complement(b::BitIndex{Q}) -> BitIndex{Q}
Returns the left complement of b
, define so that left_complement(b) * b
generates the pseudoscalar index of elements of the algebra Q
.
When the left complement is applied twice, the original BitIndex
object is returned up to a change of sign, given by (-1)^(grade(b) * (dimension(Q) - grade(b))). This implies that in algebras of odd dimension, the left complement and [right complement](@ref right_complement) are identical because either
grade(b)or
dimension(Q) - grade(b)must be even. The complement is independent of the signature of
Q`, depending only on the dimension.
Lengyel's convention for the left complement is an underbar.
CliffordNumbers.right_complement
— Methodright_complement(b::BitIndex{Q}) -> BitIndex{Q}
Returns the right complement of b
, define so that b * right_complement(b)
generates the pseudoscalar index of elements of the algebra Q
.
When the right complement is applied twice, the original BitIndex
object is returned up to a change of sign, given by (-1)^(grade(b) * (dimension(Q) - grade(b))). This implies that in algebras of odd dimension, the [left complement](@ref left_complement) and right complement are identical because either
grade(b)or
dimension(Q) - grade(b)must be even. The complement is independent of the signature of
Q`, depending only on the dimension.
Lengyel's convention for the right complement is an overbar.
Inverses
CliffordNumbers.versor_inverse
— FunctionCliffordNumbers.versor_inverse(x::AbstractCliffordNumber)
Calculates the versor inverse of x
, equal to x' / abs2(x)
.
The versor inverse is only guaranteed to be an inverse for versors. Not all Clifford numbers have a well-defined inverse, (for instance, in algebras with 2 or more positive-squaring, dimensions, 1 + e₁ has no inverse). To validate the result, use inv(x)
instead.
Base.inv
— Methodinv(x::AbstractCliffordNumber) -> AbstractCliffordNumber
Calculates the inverse of x
, if it exists, using the versor inverse formula x' / abs2(x)
. The result is tested to check if its left and right products with x
are approximately 1, and a CliffordNumbers.InverseException
is thrown if this test does not pass.
Addition and subtraction
Addition and subtraction integrate seamlessly with those of the Julia Base number types, and no special documentation is included here.
Products
Products with scalars
The standard multiplication and division operations (*
, /
, //
) between Clifford numbers and scalars behave as expected. Base.muladd
has been overloaded to take advantage of fma instructions available on some hardware platforms.
Base.muladd
— Methodmuladd(x::Union{Real,Complex}, y::AbstractCliffordNumber{Q}, z::AbstractCliffordNumber{Q})
muladd(x::AbstractCliffordNumber{Q}, y::Union{Real,Complex}, z::AbstractCliffordNumber{Q})
Multiplies a scalar with a Clifford number and adds another Clifford number, utilizing optimizations made available with scalar muladd
, such as fma
if hardware support is available.
Geometric products
Base.:*
— Function*(x::AbstractCliffordNumber{Q}, y::AbstractCliffordNumber{Q})
(x::AbstractCliffordNumber{Q})(y::AbstractCliffordNumber{Q})
Calculates the geometric product of x
and y
, returning the smallest type which is able to represent all nonzero basis blades of the result.
CliffordNumbers.:⨼
— Functionleft_contraction(x::AbstractCliffordNumber{Q}, y::AbstractCliffordNumber{Q})
⨼(x::AbstractCliffordNumber{Q}, y::AbstractCliffordNumber{Q})
Calculates the left contraction of x
and y
.
For basis blades A
of grade m
and B
of grade n
, the left contraction is zero if n < m
, otherwise it is KVector{n-m,Q}(A*B)
.
CliffordNumbers.:⨽
— Functionright_contraction(x::AbstractCliffordNumber{Q}, y::AbstractCliffordNumber{Q})
⨽(x::AbstractCliffordNumber{Q}, y::AbstractCliffordNumber{Q})
Calculates the right contraction of x
and y
.
For basis blades A
of grade m
and B
of grade n
, the right contraction is zero if m < n
, otherwise it is KVector{m-n,Q}(A*B)
.
CliffordNumbers.dot
— FunctionCliffordNumbers.dot(x::AbstractCliffordNumber{Q}, y::AbstractCliffordNumber{Q})
Calculates the dot product of x
and y
.
For basis blades A
of grade m
and B
of grade n
, the dot product is equal to the left contraction when m >= n
and is equal to the right contraction (up to sign) when n >= m
.
Why is this function not exported?
The LinearAlgebra package also defines a dot
function, and if both packages are used together, this will cause a name conflict if CliffordNumbers.dot
is exported. In the future, we will try to resolve this without requiring a LinearAlgebra dependency.
Additionally, there is reason to prefer the use of the left and right contractions over the dot product because the contractions require fewer exceptions in their definitions and properties.
CliffordNumbers.hestenes_dot
— FunctionCliffordNumbers.hestenes_dot(x::AbstractCliffordNumber{Q}, y::AbstractCliffordNumber{Q})
Returns the Hestenes product: this is equal to the dot product given by dot(x, y)
but is equal to to zero when either x
or y
is a scalar.
Why is this function not exported?
In almost every case, left and right contractions are preferable - the dot product and the Hestenes product are less regular in algebraic sense, and the conditionals present in its implementation slow it down relative to contractions. It is provided for the sake of exact reproducibility of results which use it.
CliffordNumbers.:∧
— Function∧(x::AbstractCliffordNumber{Q}, y::AbstractCliffordNumber{Q})
wedge(x::AbstractCliffordNumber{Q}, y::AbstractCliffordNumber{Q})
Calculates the wedge (outer) product of two Clifford numbers x
and y
with quadratic form Q
.
Note that the wedge product, in general, is not equal to the commutator product (or antisymmetric product), which may be invoked with the commutator
function or the ×
operator.
CliffordNumbers.:∨
— Function∨(x::AbstractCliffordNumber, y::AbstractCliffordNumber)
regressive(x::AbstractCliffordNumber, y::AbstractCliffordNumber)
Calculates the regressive product of x
and y
. This is accomplished by taking the wedge product of the left complements of x
and y
, then taking the right complement of the result.
CliffordNumbers.:×
— Function×(x::AbstractCliffordNumber{Q}, y::AbstractCliffordNumber{Q})
commutator(x::AbstractCliffordNumber{Q}, y::AbstractCliffordNumber{Q})
Calculates the commutator (or antisymmetric) product, equal to 1//2 * (x*y - y*x)
.
Note that the commutator product, in general, is not equal to the wedge product, which may be invoked with the wedge
function or the ∧
operator.
Type promotion
Because of the rational 1//2
factor in the product, inputs with scalar types subtyping Integer
will be promoted to Rational
subtypes.
CliffordNumbers.:⨰
— Function⨰(x::AbstractCliffordNumber{Q}, y::AbstractCliffordNumber{Q})
anticommutator(x::AbstractCliffordNumber{Q}, y::AbstractCliffordNumber{Q})
Calculates the anticommutator (or symmetric) product, equal to 1//2 * (x*y + y*x)
.
Note that the dot product, in general, is not equal to the anticommutator product, which may be invoked with dot
. In some cases, the preferred operators might be the left and right contractions, which use infix operators ⨼
and ⨽
respectively.
Type promotion
Because of the rational 1//2
factor in the product, inputs with scalar types subtyping Integer
will be promoted to Rational
subtypes.
Scalar products and normalization
CliffordNumbers.scalar_product
— Functionscalar_product(x::AbstractCliffordNumber{Q}, y::AbstractCliffordNumber{Q})
Calculates the scalar product of two Clifford numbers with quadratic form Q
. The result is a Real
or Complex
number. This can be converted back to an AbstractCliffordNumber
.
The result is equal to scalar(x * y)
, but does not calculate the coefficients associated with any other basis blades.
Base.abs2
— Methodabs2(x::AbstractCliffordNumber{Q,T}) -> T
Calculates the modulus of x
by calculating the scalar product of x
with its reverse: scalar_product(x, x')
. In positive-definite metrics, this value is positive for any nonzero multivector and equal to zero(T)
for any multivector equal to zero.
Base.abs
— Methodabs(x::AbstractCliffordNumber{Q}) -> Union{Real,Complex}
Calculates the norm of x
, equal to sqrt(abs(abs2(x)))
.
The inclusion of abs
in this expression accounts for the possibility that the algebra Q
contains 1-blades with a negative square, which would result in abs(x)
being imaginary. In these cases, abs(x)
may not be a norm, but it is used internally by normalize(x)
to calculate a normalization factor.
CliffordNumbers.normalize
— Functionnormalize(x::AbstractCliffordNumber{Q}) -> AbstractCliffordNumber{Q}
Normalizes x
so that its modulus (as calculated by abs2
) is 1, 0, or -1. This procedure cannot change the sign of the modulus.
If abs2(x)
is zero (possible in any non-positive-definite metric), x
is returned unchanged.
Exponentiation
Base.exp
— Methodexp(x::AbstractCliffordNumber{Q})
Returns the natural exponential of a Clifford number.
For special cases where m squares to a scalar, the following shortcuts can be used to calculate exp(x)
:
- When x^2 < 0:
exp(x) === cos(abs(x)) + x * sin(abs(x)) / abs(x)
- When x^2 > 0:
exp(x) === cosh(abs(x)) + x * sinh(abs(x)) / abs(x)
- When x^2 == 0:
exp(x) == 1 + x
CliffordNumbers.exppi
— Functionexppi(x::AbstractCliffordNumber)
Returns the natural exponential of π * x
with greater accuracy than exp(π * x)
in the case where x^2
is a negative scalar, especially for large values of abs(x)
.
CliffordNumbers.exptau
— Functionexptau(x::AbstractCliffordNumber)
Returns the natural exponential of 2π * x
with greater accuracy than exp(2π * x)
in the case where x^2
is a negative scalar, especially for large values of abs(x)
.