diff --git a/dev/.documenter-siteinfo.json b/dev/.documenter-siteinfo.json index bd1e774..d83ec4a 100644 --- a/dev/.documenter-siteinfo.json +++ b/dev/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.11.1","generation_timestamp":"2024-11-12T21:18:54","documenter_version":"1.7.0"}} \ No newline at end of file +{"documenter":{"julia_version":"1.11.1","generation_timestamp":"2024-11-13T19:25:58","documenter_version":"1.8.0"}} \ No newline at end of file diff --git a/dev/api/clifford.html b/dev/api/clifford.html index 7bc0734..d0bd684 100644 --- a/dev/api/clifford.html +++ b/dev/api/clifford.html @@ -1,21 +1,21 @@ -CliffordNumbers · CliffordNumbers.jl

Clifford numbers

Supertype and associated functions

CliffordNumbers.AbstractCliffordNumberType
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.
source
CliffordNumbers.nbladesFunction
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)).

source
CliffordNumbers.scalar_typeFunction
scalar_type(::Type{<:AbstractCliffordNumber{Q,T}}) = T
+CliffordNumbers · CliffordNumbers.jl

Clifford numbers

Supertype and associated functions

CliffordNumbers.AbstractCliffordNumberType
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.
source
CliffordNumbers.nbladesFunction
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)).

source
CliffordNumbers.scalar_typeFunction
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.

source
CliffordNumbers.similar_typeFunction
CliffordNumbers.similar_type(
+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.

source
CliffordNumbers.similar_typeFunction
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.

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.

source

Concrete types

CliffordNumbers.CliffordNumberType
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.

source
CliffordNumbers.Z2CliffordNumberType
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}
source
CliffordNumbers.EvenCliffordNumberType
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.

source
CliffordNumbers.OddCliffordNumberType
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.

source
CliffordNumbers.KVectorType
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.

source
CliffordNumbers.gradeMethod
grade(::Type{<:KVector{K}}) = K
-grade(x::KVector{K}) = k

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

source

Promotion and conversion

CliffordNumbers.scalar_convertFunction
scalar_convert(T::Type{<:Union{Real,Complex}}, x::AbstractCliffordNumber) -> T
+) -> 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.

source

Concrete types

CliffordNumbers.CliffordNumberType
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.

source
CliffordNumbers.Z2CliffordNumberType
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}
source
CliffordNumbers.EvenCliffordNumberType
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.

source
CliffordNumbers.OddCliffordNumberType
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.

source
CliffordNumbers.KVectorType
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.

source
CliffordNumbers.gradeMethod
grade(::Type{<:KVector{K}}) = K
+grade(x::KVector{K}) = k

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

source

Promotion and conversion

CliffordNumbers.scalar_convertFunction
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
source
CliffordNumbers.scalar_promoteFunction
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.

source
Base.widenMethod
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).

source
CliffordNumbers.widen_gradeFunction
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).

source

Real and complex algebras

Base.realMethod
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.

source
Base.complexMethod
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.

source

Scalar and pseudoscalar components

CliffordNumbers.isscalarFunction
isscalar(x::AbstractCliffordNumber)

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

source
CliffordNumbers.ispseudoscalarFunction
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.

source
CliffordNumbers.scalarFunction
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.

source
CliffordNumbers.pseudoscalarFunction
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.

source

Defining basis variables

CliffordNumbers.@basis_varsMacro
@basis_vars(Q, ::Type{T}; prefix = Metrics.blade_symbol(Q))

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

Warning

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 = :σ)
-
source
+2.0f0
source
CliffordNumbers.scalar_promoteFunction
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.

source
Base.widenMethod
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).

source
CliffordNumbers.widen_gradeFunction
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).

source

Real and complex algebras

Base.realMethod
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.

source
Base.complexMethod
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.

source

Scalar and pseudoscalar components

CliffordNumbers.isscalarFunction
isscalar(x::AbstractCliffordNumber)

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

source
CliffordNumbers.ispseudoscalarFunction
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.

source
CliffordNumbers.scalarFunction
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.

source
CliffordNumbers.pseudoscalarFunction
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.

source

Defining basis variables

CliffordNumbers.@basis_varsMacro
@basis_vars(Q, ::Type{T}; prefix = Metrics.blade_symbol(Q))

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

Warning

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 = :σ)
+
source
diff --git a/dev/api/extensions.html b/dev/api/extensions.html index d5ec0b0..a315ea9 100644 --- a/dev/api/extensions.html +++ b/dev/api/extensions.html @@ -1,5 +1,5 @@ Extensions · CliffordNumbers.jl

Extensions

[Quaternions.jl]

Quaternions.QuaternionMethod
Quaternion(c::AbstractCliffordNumber{VGA(3)})
-Quaternion{T}(c::AbstractCliffordNumber{VGA(3)})

Constructs a quaternion from an element of the algebra of physical space, the 3D geometric algebra with a positive-definite signature whose even subalgebra is isomorphic to the quaternion algebra ℍ. Any odd-grade coefficients of c are lost. If the type parameter T is supplied, the scalars of the input are converted to type T.

If loss of odd-grade coefficients should throw an error, use convert(Quaternion, c) or convert(Quaternion{T}, c) instead of the constructor.

source
Quaternions.slerpMethod
slerp(x::AbstractCliffordNumber{VGA(3)}, y::AbstractCliffordNumber{VGA(3)}, t::Real)
-    -> EvenCliffordNumber{VGA(3)}

Performs spherical linear interpolation for rotors in the 3D vanilla geometric algebra, treating them as if they were Quaternion instances.

source
Quaternions.slerpMethod
slerp(x::Quaternion, y::AbstractCliffordNumber{VGA(3)}, t::Real) -> EvenCliffordNumber{VGA(3)}
-slerp(x::AbstractCliffordNumber{VGA(3)}, y::Quaternion, t::Real) -> EvenCliffordNumber{VGA(3)}

Performs spherical linear interpolation for rotors in the 3D vanilla geometric algebra, treating them as if they were Quaternion instances. The resulting output gains Clifford number semantics, so it is of type EvenCliffordNumber{VGA(3)} instead of Quaternion.

source

[Quaternions.jl]: https://github.com/JuliaGeometry/Quaternions.jl

+Quaternion{T}(c::AbstractCliffordNumber{VGA(3)})

Constructs a quaternion from an element of the algebra of physical space, the 3D geometric algebra with a positive-definite signature whose even subalgebra is isomorphic to the quaternion algebra ℍ. Any odd-grade coefficients of c are lost. If the type parameter T is supplied, the scalars of the input are converted to type T.

If loss of odd-grade coefficients should throw an error, use convert(Quaternion, c) or convert(Quaternion{T}, c) instead of the constructor.

source
Quaternions.slerpMethod
slerp(x::AbstractCliffordNumber{VGA(3)}, y::AbstractCliffordNumber{VGA(3)}, t::Real)
+    -> EvenCliffordNumber{VGA(3)}

Performs spherical linear interpolation for rotors in the 3D vanilla geometric algebra, treating them as if they were Quaternion instances.

source
Quaternions.slerpMethod
slerp(x::Quaternion, y::AbstractCliffordNumber{VGA(3)}, t::Real) -> EvenCliffordNumber{VGA(3)}
+slerp(x::AbstractCliffordNumber{VGA(3)}, y::Quaternion, t::Real) -> EvenCliffordNumber{VGA(3)}

Performs spherical linear interpolation for rotors in the 3D vanilla geometric algebra, treating them as if they were Quaternion instances. The resulting output gains Clifford number semantics, so it is of type EvenCliffordNumber{VGA(3)} instead of Quaternion.

source

[Quaternions.jl]: https://github.com/JuliaGeometry/Quaternions.jl

diff --git a/dev/api/indexing.html b/dev/api/indexing.html index abdbfb6..c1468a3 100644 --- a/dev/api/indexing.html +++ b/dev/api/indexing.html @@ -10,9 +10,9 @@ 2:2 julia> nonzero_grades(Float64) -0:0source
CliffordNumbers.has_grades_ofFunction
has_grades_of(S::Type{<:AbstractCliffordNumber}, T::Type{<:AbstractCliffordNumber}) -> Bool
-has_grades_of(x::AbstractCliffordNumber, y::AbstractCliffordNumber) -> Bool

Returns true if the grades represented in S are also represented in T; false otherwise.

source

BitIndex

CliffordNumbers.BitIndexType
BitIndex{Q}

A representation of an index corresponding to a basis blade of the geometric algebra with quadratic form Q.

source
CliffordNumbers.is_same_bladeFunction
CliffordNumbers.is_same_blade(a::BitIndex{Q}, b::BitIndex{Q})

Checks if a and b perform identical indexing up to sign.

source

Special indices

CliffordNumbers.scalar_indexFunction
scalar_index(x::AbstractCliffordNumber{Q}) -> BitIndex{Q}

Constructs the BitIndex used to obtain the scalar (grade zero) portion of x.

source
CliffordNumbers.pseudoscalar_indexFunction
pseudoscalar_index(x::AbstractCliffordNumber{Q}) -> BitIndex{Q}

Constructs the BitIndex used to obtain the pseudoscalar (highest grade) portion of x.

source

Tools for implementing mathematical operations

Base.reverseMethod
reverse(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.

source
CliffordNumbers.grade_involutionMethod
grade_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.

source
Base.conjMethod
conj(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)).

source
CliffordNumbers.left_complementMethod
left_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 eithergrade(b)ordimension(Q) - grade(b)must be even. The complement is independent of the signature ofQ`, depending only on the dimension.

Lengyel's convention for the left complement is an underbar.

source
CliffordNumbers.right_complementMethod
right_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 eithergrade(b)ordimension(Q) - grade(b)must be even. The complement is independent of the signature ofQ`, depending only on the dimension.

Lengyel's convention for the right complement is an overbar.

source
CliffordNumbers.gradeMethod
grade(i::BitIndex) -> Int

Returns the grade of the basis blade represented by i, which ranges from 0 to the dimension of the space represented by i (equal to dimension(signature(i))).

source
CliffordNumbers.sign_of_squareFunction
CliffordNumbers.sign_of_square(b::BitIndex) -> Int8

Returns the sign associated with squaring the basis blade indexed by b using an Int8 as proxy: positive signs return Int8(1), negative signs return Int8(-1), and zeros from degenerate components return Int8(0).

source
CliffordNumbers.signbit_of_squareFunction
CliffordNumbers.signbit_of_square(b::BitIndex) -> Bool

Returns the signbit associated with squaring the basis blade indexed by b.

For basis blades squaring to zero, the result is not meaningful.

source
CliffordNumbers.nondegenerate_squareFunction
CliffordNumbers.nondegenerate_square(b::BitIndex) -> Bool

Returns false if squaring the basis blade b is zero due to a degenerate component, true otherwise. For a nondegenerate metric, this is always true.

source
CliffordNumbers.sign_of_multFunction
CliffordNumbers.sign_of_mult(a::T, b::T) where T<:BitIndex -> Int8

Returns an Int8 that carries the sign associated with the multiplication of two basis blades of Clifford/geometric algebras of the same quadratic form.

source
CliffordNumbers.signbit_of_multFunction
CliffordNumbers.signbit_of_mult(a::Integer, [b::Integer]) -> Bool
-CliffordNumbers.signbit_of_mult(a::BitIndex, [b::BitIndex]) -> Bool

Calculates the sign bit associated with multiplying basis elements indexed with bit indices supplied as either integers or BitIndex instances. The sign bit flips when the order of a and b are reversed, unless a === b.

As with Base.signbit(), true represents a negative sign and false a positive sign. However, in degenerate metrics (such as those of projective geometric algebras) the sign bit may be irrelevant as the multiplication of those basis blades would result in zero.

source
CliffordNumbers.nondegenerate_multFunction
CliffordNumbers.nondegenerate_mult(a::T, b::T) where T<:BitIndex -> Bool

Returns false if the product of a and b is zero due to the squaring of a degenerate component, true otherwise. This function always returns true if R === 0.

source
Base.:*Method
*(a::BitIndex{Q}, b::BitIndex{Q}) -> BitIndex{Q}

Returns the BitIndex corresponding to the basis blade resulting from the geometric product of the basis blades indexed by a and b.

source
CliffordNumbers.has_wedgeFunction
CliffordNumbers.has_wedge(a::BitIndex{Q}, b::BitIndex{Q}, [c::BitIndex{Q}...]) -> Bool

Returns true if the basis blades indexed by a, b, or any other blades c... have a nonzero wedge product; false otherwise. This is determined by comparing all bits of the arguments (except the sign bit) to identify any matching basis blades using bitwise AND.

source
CliffordNumbers.AbstractBitIndicesType
AbstractBitIndices{Q,C<:AbstractCliffordNumber{Q}} <: AbstractVector{BitIndex{Q}}

Supertype for vectors containing all valid BitIndex{Q} objects for the basis elements represented by C.

source
CliffordNumbers.BitIndicesType
BitIndices{Q,C<:AbstractCliffordNumber{Q,<:Any}} <: AbstractVector{BitIndex{Q}}

Represents a range of valid BitIndex objects for the nonzero components of a given multivector of algebra Q.

For a generic AbstractCliffordNumber{Q}, this returns BitIndices{Q,CliffordNumber{Q}}, which contains all possible indices for a multivector associated with the algebra parameter Q. For sparser representations, such as KVector{K,Q}, the object only contains the indices of the nonzero elements of the multivector.

Construction

BitIndices can be constructed by calling the type constructor with the Clifford number or its type. This will automatically strip some type parameters so that identical BitIndices objects are constructed regardless of the scalar type.

For this reason, you should not use BitIndices{Q,C}(); instead use BitIndices(C).

Indexing

BitIndices always uses one-based indexing like most Julia arrays. Although it is more natural in the dense case to use zero-based indexing, as the basis blades are naturally encoded in the indices for the dense representation of CliffordNumber, one-based indexing is used by the tuples which contain the data associated with this package's implementations of Clifford numbers.

Broadcasting

Because BitIndices(x) only lazily references the indices of x, we define a new type, TransformedBitIndices, which allows for a function f to be lazily associated with the BitIndices object, and this type is constructed when a f.(BitIndices(x)) is called.

Interfaces for new subtypes of AbstractCliffordNumber

When defining the behavior of BitIndices for new subtypes T of AbstractCliffordNumber, Base.getindex(::BitIndices{Q,T}, i::Integer) should be defined so that all indices of T that are not constrained to be zero are returned.

You should also define CliffordNumbers.bitindices_type(::Type{T}) so that type parameters that do not affect the construction of the BitIndices object are stripped.

source
CliffordNumbers.TransformedBitIndicesType
TransformedBitIndices{Q,C,F} <: AbstractBitIndices{Q,C}

Lazy representation of BitIndices{Q,C} with some function of type f applied to each element. These objects can be used to perform common operations which act on basis blades or grades, such as the reverse or grade involution.

source
+0:0source
CliffordNumbers.has_grades_ofFunction
has_grades_of(S::Type{<:AbstractCliffordNumber}, T::Type{<:AbstractCliffordNumber}) -> Bool
+has_grades_of(x::AbstractCliffordNumber, y::AbstractCliffordNumber) -> Bool

Returns true if the grades represented in S are also represented in T; false otherwise.

source

BitIndex

CliffordNumbers.BitIndexType
BitIndex{Q}

A representation of an index corresponding to a basis blade of the geometric algebra with quadratic form Q.

source
CliffordNumbers.is_same_bladeFunction
CliffordNumbers.is_same_blade(a::BitIndex{Q}, b::BitIndex{Q})

Checks if a and b perform identical indexing up to sign.

source

Special indices

CliffordNumbers.scalar_indexFunction
scalar_index(x::AbstractCliffordNumber{Q}) -> BitIndex{Q}

Constructs the BitIndex used to obtain the scalar (grade zero) portion of x.

source
CliffordNumbers.pseudoscalar_indexFunction
pseudoscalar_index(x::AbstractCliffordNumber{Q}) -> BitIndex{Q}

Constructs the BitIndex used to obtain the pseudoscalar (highest grade) portion of x.

source

Tools for implementing mathematical operations

Base.reverseMethod
reverse(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.

source
CliffordNumbers.grade_involutionMethod
grade_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.

source
Base.conjMethod
conj(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)).

source
CliffordNumbers.left_complementMethod
left_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 eithergrade(b)ordimension(Q) - grade(b)must be even. The complement is independent of the signature ofQ`, depending only on the dimension.

Lengyel's convention for the left complement is an underbar.

source
CliffordNumbers.right_complementMethod
right_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 eithergrade(b)ordimension(Q) - grade(b)must be even. The complement is independent of the signature ofQ`, depending only on the dimension.

Lengyel's convention for the right complement is an overbar.

source
CliffordNumbers.gradeMethod
grade(i::BitIndex) -> Int

Returns the grade of the basis blade represented by i, which ranges from 0 to the dimension of the space represented by i (equal to dimension(signature(i))).

source
CliffordNumbers.sign_of_squareFunction
CliffordNumbers.sign_of_square(b::BitIndex) -> Int8

Returns the sign associated with squaring the basis blade indexed by b using an Int8 as proxy: positive signs return Int8(1), negative signs return Int8(-1), and zeros from degenerate components return Int8(0).

source
CliffordNumbers.signbit_of_squareFunction
CliffordNumbers.signbit_of_square(b::BitIndex) -> Bool

Returns the signbit associated with squaring the basis blade indexed by b.

For basis blades squaring to zero, the result is not meaningful.

source
CliffordNumbers.nondegenerate_squareFunction
CliffordNumbers.nondegenerate_square(b::BitIndex) -> Bool

Returns false if squaring the basis blade b is zero due to a degenerate component, true otherwise. For a nondegenerate metric, this is always true.

source
CliffordNumbers.sign_of_multFunction
CliffordNumbers.sign_of_mult(a::T, b::T) where T<:BitIndex -> Int8

Returns an Int8 that carries the sign associated with the multiplication of two basis blades of Clifford/geometric algebras of the same quadratic form.

source
CliffordNumbers.signbit_of_multFunction
CliffordNumbers.signbit_of_mult(a::Integer, [b::Integer]) -> Bool
+CliffordNumbers.signbit_of_mult(a::BitIndex, [b::BitIndex]) -> Bool

Calculates the sign bit associated with multiplying basis elements indexed with bit indices supplied as either integers or BitIndex instances. The sign bit flips when the order of a and b are reversed, unless a === b.

As with Base.signbit(), true represents a negative sign and false a positive sign. However, in degenerate metrics (such as those of projective geometric algebras) the sign bit may be irrelevant as the multiplication of those basis blades would result in zero.

source
CliffordNumbers.nondegenerate_multFunction
CliffordNumbers.nondegenerate_mult(a::T, b::T) where T<:BitIndex -> Bool

Returns false if the product of a and b is zero due to the squaring of a degenerate component, true otherwise. This function always returns true if R === 0.

source
Base.:*Method
*(a::BitIndex{Q}, b::BitIndex{Q}) -> BitIndex{Q}

Returns the BitIndex corresponding to the basis blade resulting from the geometric product of the basis blades indexed by a and b.

source
CliffordNumbers.has_wedgeFunction
CliffordNumbers.has_wedge(a::BitIndex{Q}, b::BitIndex{Q}, [c::BitIndex{Q}...]) -> Bool

Returns true if the basis blades indexed by a, b, or any other blades c... have a nonzero wedge product; false otherwise. This is determined by comparing all bits of the arguments (except the sign bit) to identify any matching basis blades using bitwise AND.

source
CliffordNumbers.AbstractBitIndicesType
AbstractBitIndices{Q,C<:AbstractCliffordNumber{Q}} <: AbstractVector{BitIndex{Q}}

Supertype for vectors containing all valid BitIndex{Q} objects for the basis elements represented by C.

source
CliffordNumbers.BitIndicesType
BitIndices{Q,C<:AbstractCliffordNumber{Q,<:Any}} <: AbstractVector{BitIndex{Q}}

Represents a range of valid BitIndex objects for the nonzero components of a given multivector of algebra Q.

For a generic AbstractCliffordNumber{Q}, this returns BitIndices{Q,CliffordNumber{Q}}, which contains all possible indices for a multivector associated with the algebra parameter Q. For sparser representations, such as KVector{K,Q}, the object only contains the indices of the nonzero elements of the multivector.

Construction

BitIndices can be constructed by calling the type constructor with the Clifford number or its type. This will automatically strip some type parameters so that identical BitIndices objects are constructed regardless of the scalar type.

For this reason, you should not use BitIndices{Q,C}(); instead use BitIndices(C).

Indexing

BitIndices always uses one-based indexing like most Julia arrays. Although it is more natural in the dense case to use zero-based indexing, as the basis blades are naturally encoded in the indices for the dense representation of CliffordNumber, one-based indexing is used by the tuples which contain the data associated with this package's implementations of Clifford numbers.

Broadcasting

Because BitIndices(x) only lazily references the indices of x, we define a new type, TransformedBitIndices, which allows for a function f to be lazily associated with the BitIndices object, and this type is constructed when a f.(BitIndices(x)) is called.

Interfaces for new subtypes of AbstractCliffordNumber

When defining the behavior of BitIndices for new subtypes T of AbstractCliffordNumber, Base.getindex(::BitIndices{Q,T}, i::Integer) should be defined so that all indices of T that are not constrained to be zero are returned.

You should also define CliffordNumbers.bitindices_type(::Type{T}) so that type parameters that do not affect the construction of the BitIndices object are stripped.

source
CliffordNumbers.TransformedBitIndicesType
TransformedBitIndices{Q,C,F} <: AbstractBitIndices{Q,C}

Lazy representation of BitIndices{Q,C} with some function of type f applied to each element. These objects can be used to perform common operations which act on basis blades or grades, such as the reverse or grade involution.

source
diff --git a/dev/api/internal.html b/dev/api/internal.html index 21d1e6a..9e1a5cf 100644 --- a/dev/api/internal.html +++ b/dev/api/internal.html @@ -1,25 +1,25 @@ -Internals · CliffordNumbers.jl

Internal methods

CliffordNumbers.HammingModule
CliffordNumbers.Hamming

A submodule containing methods for working with the sum of binary digits contained in an integer. This is essential to representing the basis blades of a geometric algebra, as the presence or absence of each possible basis vector in a blade can be represented by a binary 1 or 0. Operations that require knowledge of the grade of a basis blade will need the operations in this submodule.

source
CliffordNumbers.Hamming.isevilFunction
CliffordNumbers.Hamming.isevil(i::Integer) -> Bool

Determines whether a number is evil, meaning that its Hamming weight (sum of its binary digits) is even.

source
CliffordNumbers.Hamming.isodiousFunction
CliffordNumbers.Hamming.isodious(i::Integer) -> Bool

Determines whether a number is odious, meaning that its Hamming weight (sum of its binary digits) is odd.

source
CliffordNumbers.Hamming.evil_numberFunction
CliffordNumbers.Hamming.evil_number(n::Integer)

Returns the nth evil number, with the first evil number (n == 1) defined to be 0.

Evil numbers are numbers which have an even Hamming weight (sum of its binary digits).

source
CliffordNumbers.Hamming.odious_numberFunction
CliffordNumbers.Hamming.odious_number(n::Integer)

Returns the nth odious number, with the first odious number (n == 1) defined to be 1.

Odious numbers are numbers which have an odd Hamming weight (sum of its binary digits).

source
CliffordNumbers.Hamming.hamming_numberFunction
CliffordNumbers.Hamming.hamming_number(w::Integer, n::Integer)

Gets the nth number with Hamming weight w. The first number with this Hamming weight (n = 1) is 2^w - 1.

Example

julia> CliffordNumbers.hamming_number(3, 2)
-11
source

Indexing

CliffordNumbers.signmaskFunction
CliffordNumbers.signmask([T::Type{<:Integer} = UInt], [signbit::Bool = true]) -> T

Generates a signmask, or a string of bits where the only 1 bit is the sign bit. If signbit is set to false, this returns zero (or whatever value is represented by all bits being 0).

source
CliffordNumbers._sort_with_parity!Function
CliffordNumbers._sort_with_parity!(v::AbstractVector{<:Real}) -> Tuple{typeof(v),Bool}

Performs a parity-tracking insertion sort of v, which modifies v in place. The function returns a tuple containing v and the parity, which is true for an odd permutation and false for an even permutation. This is implemented with a modified insertion sort algorithm.

source
CliffordNumbers.bitindices_typeFunction
CliffordNumbers.bitindices_type(C::Type{<:AbstractCliffordNumber{Q,T}})

Removes extraneous type parameters from C, converting it to the least parameterized type that can be used to parameterize an AbstractBitIndices{Q,C} object. This is to avoid issues with the proliferation of type parameters that would construct identical BitIndices objects otherwise: for instance, BitIndices{VGA(3),EvenCliffordNumber{VGA(3),Float32,4}}() and BitIndices{VGA(3),EvenCliffordNumber{VGA(3),Int}}() have identical elements, and are equal when compared with ==, but are not the same object.

For types defined in this package, this strips the scalar type parameter T and any length parameters present.

Examples

julia> CliffordNumbers.bitindices_type(CliffordNumber{VGA(3),Float32,8})
+Internals · CliffordNumbers.jl

Internal methods

CliffordNumbers.HammingModule
CliffordNumbers.Hamming

A submodule containing methods for working with the sum of binary digits contained in an integer. This is essential to representing the basis blades of a geometric algebra, as the presence or absence of each possible basis vector in a blade can be represented by a binary 1 or 0. Operations that require knowledge of the grade of a basis blade will need the operations in this submodule.

source
CliffordNumbers.Hamming.isevilFunction
CliffordNumbers.Hamming.isevil(i::Integer) -> Bool

Determines whether a number is evil, meaning that its Hamming weight (sum of its binary digits) is even.

source
CliffordNumbers.Hamming.isodiousFunction
CliffordNumbers.Hamming.isodious(i::Integer) -> Bool

Determines whether a number is odious, meaning that its Hamming weight (sum of its binary digits) is odd.

source
CliffordNumbers.Hamming.evil_numberFunction
CliffordNumbers.Hamming.evil_number(n::Integer)

Returns the nth evil number, with the first evil number (n == 1) defined to be 0.

Evil numbers are numbers which have an even Hamming weight (sum of its binary digits).

source
CliffordNumbers.Hamming.odious_numberFunction
CliffordNumbers.Hamming.odious_number(n::Integer)

Returns the nth odious number, with the first odious number (n == 1) defined to be 1.

Odious numbers are numbers which have an odd Hamming weight (sum of its binary digits).

source
CliffordNumbers.Hamming.hamming_numberFunction
CliffordNumbers.Hamming.hamming_number(w::Integer, n::Integer)

Gets the nth number with Hamming weight w. The first number with this Hamming weight (n = 1) is 2^w - 1.

Example

julia> CliffordNumbers.hamming_number(3, 2)
+11
source

Indexing

CliffordNumbers.signmaskFunction
CliffordNumbers.signmask([T::Type{<:Integer} = UInt], [signbit::Bool = true]) -> T

Generates a signmask, or a string of bits where the only 1 bit is the sign bit. If signbit is set to false, this returns zero (or whatever value is represented by all bits being 0).

source
CliffordNumbers._sort_with_parity!Function
CliffordNumbers._sort_with_parity!(v::AbstractVector{<:Real}) -> Tuple{typeof(v),Bool}

Performs a parity-tracking insertion sort of v, which modifies v in place. The function returns a tuple containing v and the parity, which is true for an odd permutation and false for an even permutation. This is implemented with a modified insertion sort algorithm.

source
CliffordNumbers.bitindices_typeFunction
CliffordNumbers.bitindices_type(C::Type{<:AbstractCliffordNumber{Q,T}})

Removes extraneous type parameters from C, converting it to the least parameterized type that can be used to parameterize an AbstractBitIndices{Q,C} object. This is to avoid issues with the proliferation of type parameters that would construct identical BitIndices objects otherwise: for instance, BitIndices{VGA(3),EvenCliffordNumber{VGA(3),Float32,4}}() and BitIndices{VGA(3),EvenCliffordNumber{VGA(3),Int}}() have identical elements, and are equal when compared with ==, but are not the same object.

For types defined in this package, this strips the scalar type parameter T and any length parameters present.

Examples

julia> CliffordNumbers.bitindices_type(CliffordNumber{VGA(3),Float32,8})
 CliffordNumber{VGA(3)}
 
 julia> CliffordNumbers.bitindices_type(KVector{2,STA,Bool})
-KVector{2,STA}
source

Construction

CliffordNumbers.zero_tupleFunction
CliffordNumbers.zero_tuple(::Type{T}, ::Val{L}) -> NTuple{L,T}

Generates a Tuple of length L with all elements being zero(T).

source
CliffordNumbers.zero_tuple(::Type{C<:AbstractCliffordNumber})
-    -> NTuple{nblades(C),scalar_type(C)}

Generates a Tuple that can be used to construct zero(C).

source
CliffordNumbers.check_element_countFunction
CliffordNumbers.check_element_count(sz, [L], data)

Ensures that the number of elements in data is the same as the result of f(Q), where f is a function that generates the expected number of elements for the type. This function is used in the inner constructors of subtypes of AbstractCliffordNumber{Q} to ensure that the input has the correct length.

If provided, the length type parameter L can be included as an argument, and it will be checked for type (must be an Int) and value (must be equal to sz).

This function returns nothing, but throws an AssertionError for failed checks.

source

Multiplication kernels

Construction

CliffordNumbers.zero_tupleFunction
CliffordNumbers.zero_tuple(::Type{T}, ::Val{L}) -> NTuple{L,T}

Generates a Tuple of length L with all elements being zero(T).

source
CliffordNumbers.zero_tuple(::Type{C<:AbstractCliffordNumber})
+    -> NTuple{nblades(C),scalar_type(C)}

Generates a Tuple that can be used to construct zero(C).

source
CliffordNumbers.check_element_countFunction
CliffordNumbers.check_element_count(sz, [L], data)

Ensures that the number of elements in data is the same as the result of f(Q), where f is a function that generates the expected number of elements for the type. This function is used in the inner constructors of subtypes of AbstractCliffordNumber{Q} to ensure that the input has the correct length.

If provided, the length type parameter L can be included as an argument, and it will be checked for type (must be an Int) and value (must be equal to sz).

This function returns nothing, but throws an AssertionError for failed checks.

source

Multiplication kernels

CliffordNumbers.mulFunction
CliffordNumbers.mul(
     x::AbstractCliffordNumber{Q},
     y::AbstractCliffordNumber{Q},
     [F::GradeFilter = GradeFilter{:*}()]
-)

A fast geometric product implementation using generated functions for specific cases, and generic methods which either convert the arguments or fall back to other methods.

The arguments to this function should all agree in scalar type T. The * function, which exposes the fast geometric product implementation, promotes the scalar types of the arguments before utilizing this kernel. The scalar multiplication operations are implemented using muladd, allowing for hardware fma operations to be used when available.

The GradeFilter F allows for some blade multiplications to be excluded if they meet certain criteria. This is useful for implementing products besides the geometric product, such as the wedge product, which excludes multiplications between blades with shared vectors. Without a filter, this kernel just returns the geometric product.

source
CliffordNumbers.GradeFilterType
CliffordNumbers.GradeFilter{S}

A type that can be used to filter certain products of blades in a geometric product multiplication. The type parameter S must be a Symbol. The single instance of GradeFilter{S} is a callable object which implements a function that takes two or more BitIndex{Q} objects a and b and returns false if the product of the blades indexed is zero.

To implement a grade filter for a product function f, define the following method: (::GradeFilter{:f})(::BitIndex{Q}, ::BitIndex{Q}) # Or if the definition allows for more arguments (::GradeFilter{:f})(::BitIndex{Q}...) where Q

source
CliffordNumbers.nondegenerate_maskFunction
CliffordNumbers.nondegenerate_mask(a::BitIndex{Q}, B::NTuple{L,BitIndex{Q}})

Constructs a Boolean mask which is false for any multiplication that squares a degenerate blade; true otherwise.

source
CliffordNumbers.mul_maskFunction
CliffordNumbers.mul_mask(F::GradeFilter, a::BitIndex{Q}, B::NTuple{L,BitIndices{Q}})
+)

A fast geometric product implementation using generated functions for specific cases, and generic methods which either convert the arguments or fall back to other methods.

The arguments to this function should all agree in scalar type T. The * function, which exposes the fast geometric product implementation, promotes the scalar types of the arguments before utilizing this kernel. The scalar multiplication operations are implemented using muladd, allowing for hardware fma operations to be used when available.

The GradeFilter F allows for some blade multiplications to be excluded if they meet certain criteria. This is useful for implementing products besides the geometric product, such as the wedge product, which excludes multiplications between blades with shared vectors. Without a filter, this kernel just returns the geometric product.

source
CliffordNumbers.GradeFilterType
CliffordNumbers.GradeFilter{S}

A type that can be used to filter certain products of blades in a geometric product multiplication. The type parameter S must be a Symbol. The single instance of GradeFilter{S} is a callable object which implements a function that takes two or more BitIndex{Q} objects a and b and returns false if the product of the blades indexed is zero.

To implement a grade filter for a product function f, define the following method: (::GradeFilter{:f})(::BitIndex{Q}, ::BitIndex{Q}) # Or if the definition allows for more arguments (::GradeFilter{:f})(::BitIndex{Q}...) where Q

source
CliffordNumbers.nondegenerate_maskFunction
CliffordNumbers.nondegenerate_mask(a::BitIndex{Q}, B::NTuple{L,BitIndex{Q}})

Constructs a Boolean mask which is false for any multiplication that squares a degenerate blade; true otherwise.

source
CliffordNumbers.mul_maskFunction
CliffordNumbers.mul_mask(F::GradeFilter, a::BitIndex{Q}, B::NTuple{L,BitIndices{Q}})
 CliffordNumbers.mul_mask(F::GradeFilter, B::NTuple{L,BitIndices{Q}}, a::BitIndex{Q})
 
 CliffordNumbers.mul_mask(F::GradeFilter, a::BitIndex{Q}, B::BitIndices{Q})
-CliffordNumbers.mul_mask(F::GradeFilter, B::BitIndices{Q}, a::BitIndex{Q})

Generates a NTuple{L,Bool} which is true whenever the multiplication of the blade indexed by a and blades indexed by B is nonzero. false is returned if the grades multiply to zero due to the squaring of a degenerate component, or if they are filtered by F.

source
CliffordNumbers.mul_signsFunction
CliffordNumbers.mul_signs(F::GradeFilter, a::BitIndex{Q}, B::NTuple{L,BitIndices{Q}})
+CliffordNumbers.mul_mask(F::GradeFilter, B::BitIndices{Q}, a::BitIndex{Q})

Generates a NTuple{L,Bool} which is true whenever the multiplication of the blade indexed by a and blades indexed by B is nonzero. false is returned if the grades multiply to zero due to the squaring of a degenerate component, or if they are filtered by F.

source
CliffordNumbers.mul_signsFunction
CliffordNumbers.mul_signs(F::GradeFilter, a::BitIndex{Q}, B::NTuple{L,BitIndices{Q}})
 CliffordNumbers.mul_signs(F::GradeFilter, B::NTuple{L,BitIndices{Q}}, a::BitIndex{Q})
 
 CliffordNumbers.mul_signs(F::GradeFilter, a::BitIndex{Q}, B::BitIndices{Q})
-CliffordNumbers.mul_signs(F::GradeFilter, B::BitIndices{Q}, a::BitIndex{Q})

Generates an NTuple{L,Int8} which represents the sign associated with the multiplication needed to calculate components of a multiplication result.

This is equivalent to sign.(B) unless F === CliffordNumbers.GradeFilter{:dot}().

source
CliffordNumbers.bitindex_shuffleFunction
CliffordNumbers.bitindex_shuffle(a::BitIndex{Q}, B::NTuple{L,BitIndex{Q}})
+CliffordNumbers.mul_signs(F::GradeFilter, B::BitIndices{Q}, a::BitIndex{Q})

Generates an NTuple{L,Int8} which represents the sign associated with the multiplication needed to calculate components of a multiplication result.

This is equivalent to sign.(B) unless F === CliffordNumbers.GradeFilter{:dot}().

source
CliffordNumbers.bitindex_shuffleFunction
CliffordNumbers.bitindex_shuffle(a::BitIndex{Q}, B::NTuple{L,BitIndex{Q}})
 CliffordNumbers.bitindex_shuffle(a::BitIndex{Q}, B::BitIndices{Q})
 
 CliffordNumbers.bitindex_shuffle(B::NTuple{L,BitIndex{Q}}, a::BitIndex{Q})
-CliffordNumbers.bitindex_shuffle(B::BitIndices{Q}, a::BitIndex{Q})

Performs the multiplication -a * b for each element of B for the above ordering, or -b * a for the below ordering, generating a reordered NTuple of BitIndex{Q} objects suitable for implementing a geometric product.

source

Taylor series exponential

CliffordNumbers.exp_taylorFunction
CliffordNumbers.exp_taylor(x::AbstractCliffordNumber, order = Val(16))

Calculates the exponential of x using a Taylor expansion up to the specified order. In most cases, 12 is as sufficient number.

Notes

16 iterations is currently used because the number of loop iterations is not currently a performance bottleneck.

source

Return types for operations

CliffordNumbers.product_return_typeFunction
CliffordNumbers.product_return_type(::Type{X}, ::Type{Y}, [::GradeFilter{S}])

Returns a suitable type for representing the product of Clifford numbers of types X and Y. The GradeFilter{S} argument allows for the return type to be changed depending on the type of product. Without specialization on S, a type suitable for the geometric product is returned.

source
CliffordNumbers.exponential_typeFunction
CliffordNumbers.exponential_type(::Type{<:AbstractCliffordNumber})
-CliffordNumbers.exponential_type(x::AbstractCliffordNumber)

Returns the type expected when exponentiating a Clifford number. This is an EvenCliffordNumber if the nonzero grades of the input are even, a CliffordNumber otherwise.

source
+CliffordNumbers.bitindex_shuffle(B::BitIndices{Q}, a::BitIndex{Q})

Performs the multiplication -a * b for each element of B for the above ordering, or -b * a for the below ordering, generating a reordered NTuple of BitIndex{Q} objects suitable for implementing a geometric product.

source

Taylor series exponential

CliffordNumbers.exp_taylorFunction
CliffordNumbers.exp_taylor(x::AbstractCliffordNumber, order = Val(16))

Calculates the exponential of x using a Taylor expansion up to the specified order. In most cases, 12 is as sufficient number.

Notes

16 iterations is currently used because the number of loop iterations is not currently a performance bottleneck.

source

Return types for operations

CliffordNumbers.product_return_typeFunction
CliffordNumbers.product_return_type(::Type{X}, ::Type{Y}, [::GradeFilter{S}])

Returns a suitable type for representing the product of Clifford numbers of types X and Y. The GradeFilter{S} argument allows for the return type to be changed depending on the type of product. Without specialization on S, a type suitable for the geometric product is returned.

source
CliffordNumbers.exponential_typeFunction
CliffordNumbers.exponential_type(::Type{<:AbstractCliffordNumber})
+CliffordNumbers.exponential_type(x::AbstractCliffordNumber)

Returns the type expected when exponentiating a Clifford number. This is an EvenCliffordNumber if the nonzero grades of the input are even, a CliffordNumber otherwise.

source
diff --git a/dev/api/math.html b/dev/api/math.html index e7ae9b7..516e66b 100644 --- a/dev/api/math.html +++ b/dev/api/math.html @@ -1,14 +1,14 @@ Math · CliffordNumbers.jl

Mathematical operations

Involutions and duals

Base.reverseMethod
reverse(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.

source
Base.adjointMethod
adjoint(i::BitIndex) = i' -> BitIndex
-adjoint(x::AbstractCliffordNumber) = x' -> typeof(x)

An alias for reverse(i::BitIndex) used to implement operator notation.

source
CliffordNumbers.grade_involutionMethod
grade_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.

source
Base.conjMethod
conj(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)).

source
CliffordNumbers.left_complementMethod
left_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 eithergrade(b)ordimension(Q) - grade(b)must be even. The complement is independent of the signature ofQ`, depending only on the dimension.

Lengyel's convention for the left complement is an underbar.

source
CliffordNumbers.right_complementMethod
right_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 eithergrade(b)ordimension(Q) - grade(b)must be even. The complement is independent of the signature ofQ`, depending only on the dimension.

Lengyel's convention for the right complement is an overbar.

source

Inverses

CliffordNumbers.versor_inverseFunction
CliffordNumbers.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.

source
Base.invMethod
inv(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.

source

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.muladdMethod
muladd(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.

source

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.

source
CliffordNumbers.:⨼Function
left_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).

source
CliffordNumbers.:⨽Function
right_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).

source
CliffordNumbers.dotFunction
CliffordNumbers.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.

source
CliffordNumbers.hestenes_dotFunction
CliffordNumbers.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.

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

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

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

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

source

Scalar products and normalization

CliffordNumbers.scalar_productFunction
scalar_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.

source
Base.abs2Method
abs2(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.

source
Base.absMethod
abs(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.

source
CliffordNumbers.normalizeFunction
normalize(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.

source

Exponentiation

Base.expMethod
exp(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

See also: exppi, exptau.

source
CliffordNumbers.exppiFunction
exppi(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).

See also: exp, exptau.

source
CliffordNumbers.exptauFunction
exptau(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).

See also: exp, exppi.

source
+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.

source
Base.adjointMethod
adjoint(i::BitIndex) = i' -> BitIndex
+adjoint(x::AbstractCliffordNumber) = x' -> typeof(x)

An alias for reverse(i::BitIndex) used to implement operator notation.

source
CliffordNumbers.grade_involutionMethod
grade_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.

source
Base.conjMethod
conj(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)).

source
CliffordNumbers.left_complementMethod
left_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 eithergrade(b)ordimension(Q) - grade(b)must be even. The complement is independent of the signature ofQ`, depending only on the dimension.

Lengyel's convention for the left complement is an underbar.

source
CliffordNumbers.right_complementMethod
right_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 eithergrade(b)ordimension(Q) - grade(b)must be even. The complement is independent of the signature ofQ`, depending only on the dimension.

Lengyel's convention for the right complement is an overbar.

source

Inverses

CliffordNumbers.versor_inverseFunction
CliffordNumbers.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.

source
Base.invMethod
inv(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.

source

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.muladdMethod
muladd(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.

source

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.

source
CliffordNumbers.:⨼Function
left_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).

source
CliffordNumbers.:⨽Function
right_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).

source
CliffordNumbers.dotFunction
CliffordNumbers.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.

source
CliffordNumbers.hestenes_dotFunction
CliffordNumbers.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.

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

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

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

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

source

Scalar products and normalization

CliffordNumbers.scalar_productFunction
scalar_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.

source
Base.abs2Method
abs2(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.

source
Base.absMethod
abs(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.

source
CliffordNumbers.normalizeFunction
normalize(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.

source

Exponentiation

Base.expMethod
exp(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

See also: exppi, exptau.

source
CliffordNumbers.exppiFunction
exppi(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).

See also: exp, exptau.

source
CliffordNumbers.exptauFunction
exptau(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).

See also: exp, exppi.

source
diff --git a/dev/api/metrics.html b/dev/api/metrics.html index 12746c8..d47b230 100644 --- a/dev/api/metrics.html +++ b/dev/api/metrics.html @@ -1,13 +1,13 @@ -Metric signatures · CliffordNumbers.jl

Metric signatures

Signature types

CliffordNumbers.Metrics.AbstractSignatureType
Metrics.AbstractSignature <: AbstractVector{Int8}

Supertype for all data types that represent metric signatures. This includes the generic Signature type as well as other specialized types.

Metric signatures can be interpreted as the signs of the diagonal elements of the metric tensor. All elements are either -1, 0, or 1. All nondegenerate Clifford algebras admit an orthonormal basis corresponding to the metric.

Aside from the generic Metrics.Signature subtype, types for commonly used algebras are available, including Metrics.VGA, Metrics.PGA, and Metrics.CGA. Custom signatures with firmer bounds on their behavior can be implemented by subtyping this type.

source
CliffordNumbers.Metrics.SignatureType
Metrics.Signature <: Metrics.AbstractSignature
+Metric signatures · CliffordNumbers.jl

Metric signatures

Signature types

CliffordNumbers.Metrics.AbstractSignatureType
Metrics.AbstractSignature <: AbstractVector{Int8}

Supertype for all data types that represent metric signatures. This includes the generic Signature type as well as other specialized types.

Metric signatures can be interpreted as the signs of the diagonal elements of the metric tensor. All elements are either -1, 0, or 1. All nondegenerate Clifford algebras admit an orthonormal basis corresponding to the metric.

Aside from the generic Metrics.Signature subtype, types for commonly used algebras are available, including Metrics.VGA, Metrics.PGA, and Metrics.CGA. Custom signatures with firmer bounds on their behavior can be implemented by subtyping this type.

source
CliffordNumbers.Metrics.SignatureType
Metrics.Signature <: Metrics.AbstractSignature
 Metrics.Signature(
     dimensions::Integer,
     negative::UInt,
     degenerate::UInt,
     [first_index::Integer = 1]
-)

Contains information about the metric associated with a Clifford algebra or Clifford number. This type is constructed to be as generic as possible; other subtypes of Metrics.AbstractSignature may provide firmer guarantees on behavior, such as VGA.

The number which the dimensions square to is stored in a pair of UInt fields. The negative field consists of 1 bits for dimensions that square to a negative number, and 0 bits for those squaring to a positive number, matching the convention of sign bits in signed numbers.

The degenerate field consists of 1 bits for degenerate dimensions (dimensions that square to zero) and 0 bits for nondegenerate dimensions.

The numerical index of the first basis vector is first_index, which defaults to 1. Some algebras conventionally use 0 as the first index, such as projective geometric algebras and Lorentzian geometric algebras, and in some cases it may be useful to start with a negative index if there are a larger number of modeling dimensions.

source
CliffordNumbers.Metrics.VGAType
VGA <: Metrics.AbstractSignature

Represents the signature associated with a vanilla geometric algebra (VGA), a positive-definite geometric algebra which models space without any projective dimensions.

source
CliffordNumbers.Metrics.PGAType
PGA <: Metrics.AbstractSignature

Represents the signature associated with a PGA (projective geometric algebra) with the given number of modeled dimensions. The constructed algebra will contain the number of modeled dimensions plus one degenerate (zero-squaring) dimension represented by e₀. This degenerate dimension corresponds with the n∞ null vector in CGA (conformal geometric algebra).

source
CliffordNumbers.Metrics.CGAType
CGA <: Metrics.AbstractSignature

Represents the signature of a CGA (conformal geometric algebra) with the given number of modeled dimensions. The constructed algebra will contain the number of modeled dimensions plus one positive-squaring dimension and one negative-squaring dimension.

There are two common choices of vector basis for the extra dimensions added when working with CGA. The most straightforward one is e₊ and e₋, which square to +1 and -1, respectively, and this is what is used internally, with the negative-squaring dimension being the first one.

However, there is another commonly used basis: define null vectors n₀ = (e₋ - e₊)/2 and n∞ = e₋ - e₊, which represent the origin point and the point at infinity, respectively. n∞ corresponds to e₀ in PGA (projective geometric algebra).

source
CliffordNumbers.Metrics.LGAType
LGA{C} <: Metrics.AbstractSignature

Represents the signature of a Lorentzian geometric algebra (LGA), an algebra which models a given number of spatial dimensions associated with a single time dimension at index 0.

The type parameter C corresponds to the sign bit associated with the square of the spatial 1-blades. For convenience, the following aliases are defined:

const LGAEast = LGA{false}
-const LGAWest = LGA{true}

The names correspond to the "East Coast" and "West Coast" conventions for the metric signature of spacetime, with the East Coast convention having positive squares for spatial 1-blades and the West Coast convention having negative squares for spatial 1-blades.

source
CliffordNumbers.Metrics.LGAEastType
LGA{C} <: Metrics.AbstractSignature

Represents the signature of a Lorentzian geometric algebra (LGA), an algebra which models a given number of spatial dimensions associated with a single time dimension at index 0.

The type parameter C corresponds to the sign bit associated with the square of the spatial 1-blades. For convenience, the following aliases are defined:

const LGAEast = LGA{false}
-const LGAWest = LGA{true}

The names correspond to the "East Coast" and "West Coast" conventions for the metric signature of spacetime, with the East Coast convention having positive squares for spatial 1-blades and the West Coast convention having negative squares for spatial 1-blades.

source
CliffordNumbers.Metrics.LGAWestType
LGA{C} <: Metrics.AbstractSignature

Represents the signature of a Lorentzian geometric algebra (LGA), an algebra which models a given number of spatial dimensions associated with a single time dimension at index 0.

The type parameter C corresponds to the sign bit associated with the square of the spatial 1-blades. For convenience, the following aliases are defined:

const LGAEast = LGA{false}
-const LGAWest = LGA{true}

The names correspond to the "East Coast" and "West Coast" conventions for the metric signature of spacetime, with the East Coast convention having positive squares for spatial 1-blades and the West Coast convention having negative squares for spatial 1-blades.

source
CliffordNumbers.Metrics.ExteriorType
Exterior <: Metrics.AbstractSignature

Represents a signature corresponding to an exterior algebra. In an exterior algebra, all 1-blades square to 0, and the geometric product is equivalent ot the wedge product.

Unlike VGA, PGA, CGA, and LGA, the first index is not assumed when constructing this object, and can be manually specified. If it is not specified, it defaults to 1.

source

Aliases for common signatures

CliffordNumbers.Metrics.VGA2DConstant
VGA2D (alias for VGA(2))

The algebra of 2D space. The even subalgebra of this algebra is isomorphic to ℂ, the complex numbers.

source
CliffordNumbers.Metrics.VGA3DConstant
VGA3D (alias for VGA(3))

The algebra of physical space, a 3D VGA which is commonly used (explicitly and implicitly) to model non-relativistic physics. It also serves as the subalgebra of both signature conventions of the spacetime algebra (available as STAEast and STAWest).

The even subalgebra of this algebra is isomorphic to ℍ, the quaternions.

source
CliffordNumbers.Metrics.PGA3DConstant
PGA3D (alias for PGA(3))

The projective geometric algebra of 3D space, which represents points, lines, and planes in a 3D space.

source
CliffordNumbers.Metrics.CGA2DConstant
CGA2D (alias for CGA(2))

The conformal geometric algebra of 2D space, which represents points, lines, and circles on the plane. This algebra constitutes a framework for compass and straightedge constructions.

This algebra is isomorphic to STAEast, and this isomorphism is the reason why the default convention for spacetime algebras in this package is the West Coast (mostly negative) convention.

source
CliffordNumbers.Metrics.CGA3DConstant
CGA3D (alias for CGA(3))

The conformal geometric algebra of 3D space, which represents points, lines, and planes, as well as circles and spheres. This algebra constitutes a framework for extending compass and straightedge constructions to 3 dimensions.

source
CliffordNumbers.Metrics.STAEastConstant
STAEast (alias for LGAEast(3))

The spacetime algebra using the East Coast sign convention (spatial dimensions square positive, temporal dimensions square negative), with the temporal dimension at index 0.

This convention is not the default STA convention, since this signature is identical to that of the 2D conformal geometric algebra.

source
CliffordNumbers.Metrics.STAPEastConstant
STAPEast (alias for Signature(5, 0b00010, 0b00001, -1))

The projective spacetime algebra using the East Coast sign convention (spatial dimensions square positive, temporal dimensions square negative). The degenerate dimension is at index -1.

As with STA, the default convention for STAP is the West Coast metric. For an explanation, see STA.

source
CliffordNumbers.Metrics.STAPWestConstant
STAPWest (alias for Signature(5, 0b11100, 0b00001, -1))
-const STAP = STAPWest

The projective spacetime algebra using the West Coast sign convention (spatial dimensions square negative, temporal dimensions square positive). The degenerate dimension is at index -1.

As with STA, the default convention for STAP is the West Coast metric. For an explanation, see STA.

source

Associated methods

CliffordNumbers.Metrics.dimensionFunction
dimension(s::AbstractSignature) -> Int8

Returns the total number of dimensions associated with s. The default implementation returns signed(s.dimensions).

The total number of basis blades is equal to to the size of the power set of all basis vectors, and is equal to 2^dimension(s).

source
CliffordNumbers.signatureFunction
signature(T::Type{<:AbstractCliffordNumber{Q}}) = Q
-signature(x::AbstractCliffordNumber{Q}) = Q

Returns the metric signature object associated with an AbstractCliffordNumber x or its type T.

source
CliffordNumbers.Metrics.gradesFunction
grades(s::AbstractSignature) -> UnitRange{Int8}

Returns the total number of grades associated with s, which is equal to 0:dimension(s).

source
CliffordNumbers.Metrics.is_degenerateFunction
is_degenerate(s::AbstractSignature)

Returns true if any basis elements of s square to 0.

This does not imply that no elements of the associated Clifford algebra square to 0.

source
+)

Contains information about the metric associated with a Clifford algebra or Clifford number. This type is constructed to be as generic as possible; other subtypes of Metrics.AbstractSignature may provide firmer guarantees on behavior, such as VGA.

The number which the dimensions square to is stored in a pair of UInt fields. The negative field consists of 1 bits for dimensions that square to a negative number, and 0 bits for those squaring to a positive number, matching the convention of sign bits in signed numbers.

The degenerate field consists of 1 bits for degenerate dimensions (dimensions that square to zero) and 0 bits for nondegenerate dimensions.

The numerical index of the first basis vector is first_index, which defaults to 1. Some algebras conventionally use 0 as the first index, such as projective geometric algebras and Lorentzian geometric algebras, and in some cases it may be useful to start with a negative index if there are a larger number of modeling dimensions.

source
CliffordNumbers.Metrics.VGAType
VGA <: Metrics.AbstractSignature

Represents the signature associated with a vanilla geometric algebra (VGA), a positive-definite geometric algebra which models space without any projective dimensions.

source
CliffordNumbers.Metrics.PGAType
PGA <: Metrics.AbstractSignature

Represents the signature associated with a PGA (projective geometric algebra) with the given number of modeled dimensions. The constructed algebra will contain the number of modeled dimensions plus one degenerate (zero-squaring) dimension represented by e₀. This degenerate dimension corresponds with the n∞ null vector in CGA (conformal geometric algebra).

source
CliffordNumbers.Metrics.CGAType
CGA <: Metrics.AbstractSignature

Represents the signature of a CGA (conformal geometric algebra) with the given number of modeled dimensions. The constructed algebra will contain the number of modeled dimensions plus one positive-squaring dimension and one negative-squaring dimension.

There are two common choices of vector basis for the extra dimensions added when working with CGA. The most straightforward one is e₊ and e₋, which square to +1 and -1, respectively, and this is what is used internally, with the negative-squaring dimension being the first one.

However, there is another commonly used basis: define null vectors n₀ = (e₋ - e₊)/2 and n∞ = e₋ - e₊, which represent the origin point and the point at infinity, respectively. n∞ corresponds to e₀ in PGA (projective geometric algebra).

source
CliffordNumbers.Metrics.LGAType
LGA{C} <: Metrics.AbstractSignature

Represents the signature of a Lorentzian geometric algebra (LGA), an algebra which models a given number of spatial dimensions associated with a single time dimension at index 0.

The type parameter C corresponds to the sign bit associated with the square of the spatial 1-blades. For convenience, the following aliases are defined:

const LGAEast = LGA{false}
+const LGAWest = LGA{true}

The names correspond to the "East Coast" and "West Coast" conventions for the metric signature of spacetime, with the East Coast convention having positive squares for spatial 1-blades and the West Coast convention having negative squares for spatial 1-blades.

source
CliffordNumbers.Metrics.LGAEastType
LGA{C} <: Metrics.AbstractSignature

Represents the signature of a Lorentzian geometric algebra (LGA), an algebra which models a given number of spatial dimensions associated with a single time dimension at index 0.

The type parameter C corresponds to the sign bit associated with the square of the spatial 1-blades. For convenience, the following aliases are defined:

const LGAEast = LGA{false}
+const LGAWest = LGA{true}

The names correspond to the "East Coast" and "West Coast" conventions for the metric signature of spacetime, with the East Coast convention having positive squares for spatial 1-blades and the West Coast convention having negative squares for spatial 1-blades.

source
CliffordNumbers.Metrics.LGAWestType
LGA{C} <: Metrics.AbstractSignature

Represents the signature of a Lorentzian geometric algebra (LGA), an algebra which models a given number of spatial dimensions associated with a single time dimension at index 0.

The type parameter C corresponds to the sign bit associated with the square of the spatial 1-blades. For convenience, the following aliases are defined:

const LGAEast = LGA{false}
+const LGAWest = LGA{true}

The names correspond to the "East Coast" and "West Coast" conventions for the metric signature of spacetime, with the East Coast convention having positive squares for spatial 1-blades and the West Coast convention having negative squares for spatial 1-blades.

source
CliffordNumbers.Metrics.ExteriorType
Exterior <: Metrics.AbstractSignature

Represents a signature corresponding to an exterior algebra. In an exterior algebra, all 1-blades square to 0, and the geometric product is equivalent ot the wedge product.

Unlike VGA, PGA, CGA, and LGA, the first index is not assumed when constructing this object, and can be manually specified. If it is not specified, it defaults to 1.

source

Aliases for common signatures

CliffordNumbers.Metrics.VGA2DConstant
VGA2D (alias for VGA(2))

The algebra of 2D space. The even subalgebra of this algebra is isomorphic to ℂ, the complex numbers.

source
CliffordNumbers.Metrics.VGA3DConstant
VGA3D (alias for VGA(3))

The algebra of physical space, a 3D VGA which is commonly used (explicitly and implicitly) to model non-relativistic physics. It also serves as the subalgebra of both signature conventions of the spacetime algebra (available as STAEast and STAWest).

The even subalgebra of this algebra is isomorphic to ℍ, the quaternions.

source
CliffordNumbers.Metrics.PGA3DConstant
PGA3D (alias for PGA(3))

The projective geometric algebra of 3D space, which represents points, lines, and planes in a 3D space.

source
CliffordNumbers.Metrics.CGA2DConstant
CGA2D (alias for CGA(2))

The conformal geometric algebra of 2D space, which represents points, lines, and circles on the plane. This algebra constitutes a framework for compass and straightedge constructions.

This algebra is isomorphic to STAEast, and this isomorphism is the reason why the default convention for spacetime algebras in this package is the West Coast (mostly negative) convention.

source
CliffordNumbers.Metrics.CGA3DConstant
CGA3D (alias for CGA(3))

The conformal geometric algebra of 3D space, which represents points, lines, and planes, as well as circles and spheres. This algebra constitutes a framework for extending compass and straightedge constructions to 3 dimensions.

source
CliffordNumbers.Metrics.STAEastConstant
STAEast (alias for LGAEast(3))

The spacetime algebra using the East Coast sign convention (spatial dimensions square positive, temporal dimensions square negative), with the temporal dimension at index 0.

This convention is not the default STA convention, since this signature is identical to that of the 2D conformal geometric algebra.

source
CliffordNumbers.Metrics.STAPEastConstant
STAPEast (alias for Signature(5, 0b00010, 0b00001, -1))

The projective spacetime algebra using the East Coast sign convention (spatial dimensions square positive, temporal dimensions square negative). The degenerate dimension is at index -1.

As with STA, the default convention for STAP is the West Coast metric. For an explanation, see STA.

source
CliffordNumbers.Metrics.STAPWestConstant
STAPWest (alias for Signature(5, 0b11100, 0b00001, -1))
+const STAP = STAPWest

The projective spacetime algebra using the West Coast sign convention (spatial dimensions square negative, temporal dimensions square positive). The degenerate dimension is at index -1.

As with STA, the default convention for STAP is the West Coast metric. For an explanation, see STA.

source

Associated methods

CliffordNumbers.Metrics.dimensionFunction
dimension(s::AbstractSignature) -> Int8

Returns the total number of dimensions associated with s. The default implementation returns signed(s.dimensions).

The total number of basis blades is equal to to the size of the power set of all basis vectors, and is equal to 2^dimension(s).

source
CliffordNumbers.signatureFunction
signature(T::Type{<:AbstractCliffordNumber{Q}}) = Q
+signature(x::AbstractCliffordNumber{Q}) = Q

Returns the metric signature object associated with an AbstractCliffordNumber x or its type T.

source
CliffordNumbers.Metrics.gradesFunction
grades(s::AbstractSignature) -> UnitRange{Int8}

Returns the total number of grades associated with s, which is equal to 0:dimension(s).

source
CliffordNumbers.Metrics.is_degenerateFunction
is_degenerate(s::AbstractSignature)

Returns true if any basis elements of s square to 0.

This does not imply that no elements of the associated Clifford algebra square to 0.

source
diff --git a/dev/assets/documenter.js b/dev/assets/documenter.js index 82252a1..7d68cd8 100644 --- a/dev/assets/documenter.js +++ b/dev/assets/documenter.js @@ -612,176 +612,194 @@ function worker_function(documenterSearchIndex, documenterBaseURL, filters) { }; } -// `worker = Threads.@spawn worker_function(documenterSearchIndex)`, but in JavaScript! -const filters = [ - ...new Set(documenterSearchIndex["docs"].map((x) => x.category)), -]; -const worker_str = - "(" + - worker_function.toString() + - ")(" + - JSON.stringify(documenterSearchIndex["docs"]) + - "," + - JSON.stringify(documenterBaseURL) + - "," + - JSON.stringify(filters) + - ")"; -const worker_blob = new Blob([worker_str], { type: "text/javascript" }); -const worker = new Worker(URL.createObjectURL(worker_blob)); - /////// SEARCH MAIN /////// -// Whether the worker is currently handling a search. This is a boolean -// as the worker only ever handles 1 or 0 searches at a time. -var worker_is_running = false; - -// The last search text that was sent to the worker. This is used to determine -// if the worker should be launched again when it reports back results. -var last_search_text = ""; - -// The results of the last search. This, in combination with the state of the filters -// in the DOM, is used compute the results to display on calls to update_search. -var unfiltered_results = []; - -// Which filter is currently selected -var selected_filter = ""; - -$(document).on("input", ".documenter-search-input", function (event) { - if (!worker_is_running) { - launch_search(); - } -}); - -function launch_search() { - worker_is_running = true; - last_search_text = $(".documenter-search-input").val(); - worker.postMessage(last_search_text); -} - -worker.onmessage = function (e) { - if (last_search_text !== $(".documenter-search-input").val()) { - launch_search(); - } else { - worker_is_running = false; - } - - unfiltered_results = e.data; - update_search(); -}; +function runSearchMainCode() { + // `worker = Threads.@spawn worker_function(documenterSearchIndex)`, but in JavaScript! + const filters = [ + ...new Set(documenterSearchIndex["docs"].map((x) => x.category)), + ]; + const worker_str = + "(" + + worker_function.toString() + + ")(" + + JSON.stringify(documenterSearchIndex["docs"]) + + "," + + JSON.stringify(documenterBaseURL) + + "," + + JSON.stringify(filters) + + ")"; + const worker_blob = new Blob([worker_str], { type: "text/javascript" }); + const worker = new Worker(URL.createObjectURL(worker_blob)); + + // Whether the worker is currently handling a search. This is a boolean + // as the worker only ever handles 1 or 0 searches at a time. + var worker_is_running = false; + + // The last search text that was sent to the worker. This is used to determine + // if the worker should be launched again when it reports back results. + var last_search_text = ""; + + // The results of the last search. This, in combination with the state of the filters + // in the DOM, is used compute the results to display on calls to update_search. + var unfiltered_results = []; + + // Which filter is currently selected + var selected_filter = ""; + + $(document).on("input", ".documenter-search-input", function (event) { + if (!worker_is_running) { + launch_search(); + } + }); -$(document).on("click", ".search-filter", function () { - if ($(this).hasClass("search-filter-selected")) { - selected_filter = ""; - } else { - selected_filter = $(this).text().toLowerCase(); + function launch_search() { + worker_is_running = true; + last_search_text = $(".documenter-search-input").val(); + worker.postMessage(last_search_text); } - // This updates search results and toggles classes for UI: - update_search(); -}); + worker.onmessage = function (e) { + if (last_search_text !== $(".documenter-search-input").val()) { + launch_search(); + } else { + worker_is_running = false; + } -/** - * Make/Update the search component - */ -function update_search() { - let querystring = $(".documenter-search-input").val(); + unfiltered_results = e.data; + update_search(); + }; - if (querystring.trim()) { - if (selected_filter == "") { - results = unfiltered_results; + $(document).on("click", ".search-filter", function () { + if ($(this).hasClass("search-filter-selected")) { + selected_filter = ""; } else { - results = unfiltered_results.filter((result) => { - return selected_filter == result.category.toLowerCase(); - }); + selected_filter = $(this).text().toLowerCase(); } - let search_result_container = ``; - let modal_filters = make_modal_body_filters(); - let search_divider = `
`; + // This updates search results and toggles classes for UI: + update_search(); + }); - if (results.length) { - let links = []; - let count = 0; - let search_results = ""; - - for (var i = 0, n = results.length; i < n && count < 200; ++i) { - let result = results[i]; - if (result.location && !links.includes(result.location)) { - search_results += result.div; - count++; - links.push(result.location); - } - } + /** + * Make/Update the search component + */ + function update_search() { + let querystring = $(".documenter-search-input").val(); - if (count == 1) { - count_str = "1 result"; - } else if (count == 200) { - count_str = "200+ results"; + if (querystring.trim()) { + if (selected_filter == "") { + results = unfiltered_results; } else { - count_str = count + " results"; + results = unfiltered_results.filter((result) => { + return selected_filter == result.category.toLowerCase(); + }); } - let result_count = `
${count_str}
`; - search_result_container = ` + let search_result_container = ``; + let modal_filters = make_modal_body_filters(); + let search_divider = `
`; + + if (results.length) { + let links = []; + let count = 0; + let search_results = ""; + + for (var i = 0, n = results.length; i < n && count < 200; ++i) { + let result = results[i]; + if (result.location && !links.includes(result.location)) { + search_results += result.div; + count++; + links.push(result.location); + } + } + + if (count == 1) { + count_str = "1 result"; + } else if (count == 200) { + count_str = "200+ results"; + } else { + count_str = count + " results"; + } + let result_count = `
${count_str}
`; + + search_result_container = ` +
+ ${modal_filters} + ${search_divider} + ${result_count} +
+ ${search_results} +
+
+ `; + } else { + search_result_container = `
${modal_filters} ${search_divider} - ${result_count} -
- ${search_results} -
-
+
0 result(s)
+ +
No result found!
`; - } else { - search_result_container = ` -
- ${modal_filters} - ${search_divider} -
0 result(s)
-
-
No result found!
- `; - } + } - if ($(".search-modal-card-body").hasClass("is-justify-content-center")) { - $(".search-modal-card-body").removeClass("is-justify-content-center"); - } + if ($(".search-modal-card-body").hasClass("is-justify-content-center")) { + $(".search-modal-card-body").removeClass("is-justify-content-center"); + } - $(".search-modal-card-body").html(search_result_container); - } else { - if (!$(".search-modal-card-body").hasClass("is-justify-content-center")) { - $(".search-modal-card-body").addClass("is-justify-content-center"); + $(".search-modal-card-body").html(search_result_container); + } else { + if (!$(".search-modal-card-body").hasClass("is-justify-content-center")) { + $(".search-modal-card-body").addClass("is-justify-content-center"); + } + + $(".search-modal-card-body").html(` +
Type something to get started!
+ `); } + } - $(".search-modal-card-body").html(` -
Type something to get started!
- `); + /** + * Make the modal filter html + * + * @returns string + */ + function make_modal_body_filters() { + let str = filters + .map((val) => { + if (selected_filter == val.toLowerCase()) { + return `${val}`; + } else { + return `${val}`; + } + }) + .join(""); + + return ` +
+ Filters: + ${str} +
`; } } -/** - * Make the modal filter html - * - * @returns string - */ -function make_modal_body_filters() { - let str = filters - .map((val) => { - if (selected_filter == val.toLowerCase()) { - return `${val}`; - } else { - return `${val}`; - } - }) - .join(""); - - return ` -
- Filters: - ${str} -
`; +function waitUntilSearchIndexAvailable() { + // It is possible that the documenter.js script runs before the page + // has finished loading and documenterSearchIndex gets defined. + // So we need to wait until the search index actually loads before setting + // up all the search-related stuff. + if (typeof documenterSearchIndex !== "undefined") { + runSearchMainCode(); + } else { + console.warn("Search Index not available, waiting"); + setTimeout(waitUntilSearchIndexAvailable, 1000); + } } +// The actual entry point to the search code +waitUntilSearchIndexAvailable(); + }) //////////////////////////////////////////////////////////////////////////////// require(['jquery'], function($) { diff --git a/dev/extensions.html b/dev/extensions.html index 365a5a6..c4f8984 100644 --- a/dev/extensions.html +++ b/dev/extensions.html @@ -26,4 +26,4 @@ julia> KVector{1, VGA(3)}(1, 2, 3) * 1.5u"m" (1.5e₁ + 3.0e₂ + 4.5e₃) m
Constructing Clifford numbers from `Quantity` coefficients fails

Attempts to construct a Clifford number from Quantity objects will fail, because Quantity does not subtype Real or Complex:

julia> KVector{1,VGA(3)}(1u"m", 2u"m", 3u"m")
 ERROR: ArgumentError:
-...

For this reason, Clifford numbers with mixed units cannot be constructed, and this is intentional: AbstractCliffordNumber assumes an orthonormal basis.

Supported operations include the geometric product and wedge product.

[Quaternions.jl]: https://github.com/JuliaGeometry/Quaternions.jl [Unitful.jl]: https://github.com/PainterQubits/Unitful.jl

+...

For this reason, Clifford numbers with mixed units cannot be constructed, and this is intentional: AbstractCliffordNumber assumes an orthonormal basis.

Supported operations include the geometric product and wedge product.

[Quaternions.jl]: https://github.com/JuliaGeometry/Quaternions.jl [Unitful.jl]: https://github.com/PainterQubits/Unitful.jl

diff --git a/dev/index.html b/dev/index.html index 733d4b8..f1498a9 100644 --- a/dev/index.html +++ b/dev/index.html @@ -1,2 +1,2 @@ -Home · CliffordNumbers.jl

CliffordNumbers

CliffordNumbers.jl is a package that provides fully static multivectors (Clifford numbers) in arbitrary dimensions and metrics. While in many cases, sparse representations of multivectors are more efficient, for spaces of low dimension, dense static representations may provide a performance and convenience advantage.

Design goals

The goal of this package is to provide a multivector implementation that:

  • Allows for the construction of multivectors in arbitrary metrics, with coefficients that subtype any instance of Julia's base numeric types, Real or Complex.
  • Provides data structures of fixed sizes that represent multivectors. This allows for instances to be allocated on the stack or stored inline in an Array rather than as pointers to individually allocated instances.
  • Provides dense representations of multivectors, as well as convenient sparse representations, which can be constructed from each other, converted in a way that guarantees representability, and allows for promotion between instances.
  • Subtypes Number: The term "Clifford number" emphasizes the perspective of multivectors as an extension of the real numbers, in the same way that complex numbers and quaternions extend them. (It should be noted that both complex numbers and quaternions are Clifford algebras themselves!)
  • Aggressively optimizes all mathematical operations, utilizing fma operations and SIMD instructions whenever possible, but without sacrificing numerical precision.
  • Interoperates with automatic differentiation tools and other packages which allow for the implementation of operations from geometric calculus.
  • Allows Julia to be used as a calculator for geometric algebra.
+Home · CliffordNumbers.jl

CliffordNumbers

CliffordNumbers.jl is a package that provides fully static multivectors (Clifford numbers) in arbitrary dimensions and metrics. While in many cases, sparse representations of multivectors are more efficient, for spaces of low dimension, dense static representations may provide a performance and convenience advantage.

Design goals

The goal of this package is to provide a multivector implementation that:

  • Allows for the construction of multivectors in arbitrary metrics, with coefficients that subtype any instance of Julia's base numeric types, Real or Complex.
  • Provides data structures of fixed sizes that represent multivectors. This allows for instances to be allocated on the stack or stored inline in an Array rather than as pointers to individually allocated instances.
  • Provides dense representations of multivectors, as well as convenient sparse representations, which can be constructed from each other, converted in a way that guarantees representability, and allows for promotion between instances.
  • Subtypes Number: The term "Clifford number" emphasizes the perspective of multivectors as an extension of the real numbers, in the same way that complex numbers and quaternions extend them. (It should be noted that both complex numbers and quaternions are Clifford algebras themselves!)
  • Aggressively optimizes all mathematical operations, utilizing fma operations and SIMD instructions whenever possible, but without sacrificing numerical precision.
  • Interoperates with automatic differentiation tools and other packages which allow for the implementation of operations from geometric calculus.
  • Allows Julia to be used as a calculator for geometric algebra.
diff --git a/dev/indexing.html b/dev/indexing.html index 847eebf..21b1a6a 100644 --- a/dev/indexing.html +++ b/dev/indexing.html @@ -37,4 +37,4 @@ true julia> BitIndices{STA,CliffordNumber{STA}}() == BitIndices{STA,CliffordNumber{STA,Float32,8}}() -true

For this reason, you should call BitIndices(x) or BitIndices(C) instead of directly constructing BitIndices{Q,C}().

TransformedBitIndices{Q,C,F}

If we want to perform a transformation on all elements of a BitIndices instance, we may use dot syntax and broadcast an operation: for instance, reverse.(BitIndices(x)) to obtain the reverse of all indices. Without any explicit specification of behavior, this will return a Vector, and for the sake of performance we'd like to avoid returning types without statically known lengths.

We could solve this by converting BitIndices to a Tuple internally as part of the broadcasting implementation, but doing this will cause its own set of problems: indexing an AbstractCliffordNumber with a Tuple returns a Tuple. This may be fine internally, if we know to call the constructor, but this is potentially confusing for new users. For this reason, we provide TransformedBitIndices{Q,C,F}, which is a lazy representation of a function applied to every element of BitIndices(C).

For convenience, we provide a few aliases for operations which are commonly used with BitIndices:

In the future, we may override some broadcast implementations to ensure that all of these types are interconvertible with each other and with BitIndices{Q,C}.

+true

For this reason, you should call BitIndices(x) or BitIndices(C) instead of directly constructing BitIndices{Q,C}().

TransformedBitIndices{Q,C,F}

If we want to perform a transformation on all elements of a BitIndices instance, we may use dot syntax and broadcast an operation: for instance, reverse.(BitIndices(x)) to obtain the reverse of all indices. Without any explicit specification of behavior, this will return a Vector, and for the sake of performance we'd like to avoid returning types without statically known lengths.

We could solve this by converting BitIndices to a Tuple internally as part of the broadcasting implementation, but doing this will cause its own set of problems: indexing an AbstractCliffordNumber with a Tuple returns a Tuple. This may be fine internally, if we know to call the constructor, but this is potentially confusing for new users. For this reason, we provide TransformedBitIndices{Q,C,F}, which is a lazy representation of a function applied to every element of BitIndices(C).

For convenience, we provide a few aliases for operations which are commonly used with BitIndices:

In the future, we may override some broadcast implementations to ensure that all of these types are interconvertible with each other and with BitIndices{Q,C}.

diff --git a/dev/metrics.html b/dev/metrics.html index 45b3ffa..00a7f86 100644 --- a/dev/metrics.html +++ b/dev/metrics.html @@ -1,2 +1,2 @@ -Metric signatures · CliffordNumbers.jl

Metric signatures

Clifford algebras are characterized by the metric signatures of the spaces they represent. Some are very commonly used, such as the algebra of physical space (APS), or are generated as part of a family, such as the projective geometric algebras (PGAs), but in other cases you may need the flexibility to work with custom metric signatures.

The CliffordNumbers.Metrics submodule provides tools for working with metric signatures.

Interface

The type parameter Q of AbstractCliffordNumber{Q,T} is not constrained in any way, which means that any type or data consisting of pure bits may reside there. However, for the sake of correctness and fully defined behavior, Q must satisfy an informal interface.

Metric signature objects are treated like AbstractVector{Int8} instances, but with the elements constrained to be equal to +1, 0, or -1, corresponding to basis 1-blades squaring to positive values, negative values, or zero. In the future, we may support arbitrary values for this type.

This array is not constrained to be a 1-based array, and the values of eachindex for the array correspond to the indices of the basis 1-blades of the algebra.

The Metrics.AbstractSignature type

We define a type, Metrics.AbstractSignature <: AbstractVector{Int8}, for which this interface is already partially implemented.

Pre-defined signatures

There are many commonly used families of algebras, and for the sake of convenience, we provide four subtypes of Metrics.AbstractSignature to handles these cases:

  • Metrics.VGA represents vanilla geometric algebras.
  • Metrics.PGA represents projective geometric algebras.
  • Metrics.CGA represents conformal geometric algebras.
  • Metrics.LGA{C} represents Lorentzian geometric algebras:
    • Metrics.LGAEast uses the East Coast convention (timelike dimensions square to -1).
    • Metrics.LGAWest uses the West Coast convention (timelike dimensions square to +1).

To construct an instance of one of these types, call it with the number of modeled spatial dimensions:

  • Metrics.VGA(3) models 3 spatial dimensions with no extra dimensions.
  • Metrics.PGA(3) models 3 spatial dimensions with 1 degenerate (zero-squaring) dimension.
  • Metrics.CGA(3) models 3 spatial dimensions with 2 extra dimensions.
  • Metrics.LGAEast(3) models 3 spatial dimensions with an extra negative-squaring time dimension.
+Metric signatures · CliffordNumbers.jl

Metric signatures

Clifford algebras are characterized by the metric signatures of the spaces they represent. Some are very commonly used, such as the algebra of physical space (APS), or are generated as part of a family, such as the projective geometric algebras (PGAs), but in other cases you may need the flexibility to work with custom metric signatures.

The CliffordNumbers.Metrics submodule provides tools for working with metric signatures.

Interface

The type parameter Q of AbstractCliffordNumber{Q,T} is not constrained in any way, which means that any type or data consisting of pure bits may reside there. However, for the sake of correctness and fully defined behavior, Q must satisfy an informal interface.

Metric signature objects are treated like AbstractVector{Int8} instances, but with the elements constrained to be equal to +1, 0, or -1, corresponding to basis 1-blades squaring to positive values, negative values, or zero. In the future, we may support arbitrary values for this type.

This array is not constrained to be a 1-based array, and the values of eachindex for the array correspond to the indices of the basis 1-blades of the algebra.

The Metrics.AbstractSignature type

We define a type, Metrics.AbstractSignature <: AbstractVector{Int8}, for which this interface is already partially implemented.

Pre-defined signatures

There are many commonly used families of algebras, and for the sake of convenience, we provide four subtypes of Metrics.AbstractSignature to handles these cases:

  • Metrics.VGA represents vanilla geometric algebras.
  • Metrics.PGA represents projective geometric algebras.
  • Metrics.CGA represents conformal geometric algebras.
  • Metrics.LGA{C} represents Lorentzian geometric algebras:
    • Metrics.LGAEast uses the East Coast convention (timelike dimensions square to -1).
    • Metrics.LGAWest uses the West Coast convention (timelike dimensions square to +1).

To construct an instance of one of these types, call it with the number of modeled spatial dimensions:

  • Metrics.VGA(3) models 3 spatial dimensions with no extra dimensions.
  • Metrics.PGA(3) models 3 spatial dimensions with 1 degenerate (zero-squaring) dimension.
  • Metrics.CGA(3) models 3 spatial dimensions with 2 extra dimensions.
  • Metrics.LGAEast(3) models 3 spatial dimensions with an extra negative-squaring time dimension.
diff --git a/dev/numeric.html b/dev/numeric.html index 7af21d3..92cf68d 100644 --- a/dev/numeric.html +++ b/dev/numeric.html @@ -8,4 +8,4 @@ 1 + 4σ₁σ₂ + 6σ₁σ₃ + 7σ₂σ₃ julia> convert(EvenCliffordNumber, test) -ERROR: InexactError: ...
Danger

This is an extremely important point: construction of a Clifford number type with fewer grades than the input performs a grade projection operation without throwing an error. However, conversion will throw an error if the grades of the input value are not present in the input type.

This is not how other subtypes of Number defined by Julia Base behave, as their conversion operations are generally defined to be identical to the constructor, and always throw the same error for a given pair of type and value.

If converting an AbstractCliffordNumber to any other numeric type, construction and conversion behave identically, as expected.

Construction and conversion of Clifford numbers from other Clifford numbers the only time that the quadratic form type parameter can be omitted, as it can be inferred directly from the input. In the case of CliffordNumbers.Z2CliffordNumber, the parity type parameter can also be inferred from a KVector input.

Scalar conversion

It may be desirable to convert the scalar type of a Clifford number without having to specify the full typename of the desired output type. The function scalar_convert(T, x) takes a type T<:Union{Real,Complex} and any Clifford number x and converts its scalar type to T. If x is a Real or Complex, it just converts x to an instance of T.

+ERROR: InexactError: ...
Danger

This is an extremely important point: construction of a Clifford number type with fewer grades than the input performs a grade projection operation without throwing an error. However, conversion will throw an error if the grades of the input value are not present in the input type.

This is not how other subtypes of Number defined by Julia Base behave, as their conversion operations are generally defined to be identical to the constructor, and always throw the same error for a given pair of type and value.

If converting an AbstractCliffordNumber to any other numeric type, construction and conversion behave identically, as expected.

Construction and conversion of Clifford numbers from other Clifford numbers the only time that the quadratic form type parameter can be omitted, as it can be inferred directly from the input. In the case of CliffordNumbers.Z2CliffordNumber, the parity type parameter can also be inferred from a KVector input.

Scalar conversion

It may be desirable to convert the scalar type of a Clifford number without having to specify the full typename of the desired output type. The function scalar_convert(T, x) takes a type T<:Union{Real,Complex} and any Clifford number x and converts its scalar type to T. If x is a Real or Complex, it just converts x to an instance of T.

diff --git a/dev/operations.html b/dev/operations.html index 48eb704..634fa53 100644 --- a/dev/operations.html +++ b/dev/operations.html @@ -1,8 +1,8 @@ Operations · CliffordNumbers.jl

Operations

Like with other numbers, standard mathematical operations are supported that relate Clifford numbers to elements of their scalar field and to each other.

Unary operations

Grade automorphisms

Grade automorphisms are operations which preserves the grades of each basis blade, but changes their sign depending on the grade. All of these operations are their own inverse.

All grade automorphisms are applicable to BitIndex objects, and the way they are implemented is through constructors that use TransformedBitIndices objects to alter each grade.

Reverse

The reverse is an operation which reverses the order of the wedge product that constructed each basis blade. This is implemented with methods for Base.reverse and Base.:~.

Syntax changes

Base.:~ for the reverse is deprecated and will be removed. Base.adjoint provides ' as a syntax for the reverse, and is the preferred method for performing the reverse.

This is the most commonly used automorphism, and in a sense can be thought of as equivalent to complex conjugation. When working with even elements of the algebras of 2D or 3D space, this behaves identically to complex conjugation and quaternion conjugation. However, this is not the case when working in the even subalgebras.

Base.reverseMethod
reverse(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.

source

Grade involution

Grade involution changes the sign of all odd grades, an operation equivalent to mirroring every basis vector of the space. This can be acheived with the grade_involution function.

When interpreting even multivectors as elements of the even subalgebra of a given algebra, the reverse operation of the algebra is equivalent to grade involution in the even subalgebra.

Grade involution is equivalent to complex conjugation in when dealing with the even subalgebra of 2D space (which is isomorphic to the complex numbers), but this is not true for quaternion conjugation. Instead, use the Clifford conjugate (described below).

CliffordNumbers.grade_involutionMethod
grade_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.

source

Clifford conjugation

The Clifford conjugate is the combination of the reverse and grade involution. This is implemented as Base.conj(::AbstractCliffordNumber). This operation arises in the application of a transformation, because the grade involution accounts for the sign change associated with the parity of the isometry, and it is combined with the reverse to perform the final operation.

Warning

conj(::AbstractCliffordNumber) implements the Clifford conjugate, not the reverse!

When dealing with the even subalgebras of 2D and 3D VGAs, which are isomorphic to the complex numbers and quaternions, respectively, the Clifford conjugate is equivalent to complex conjugation or quaternion conjugation. Otherwise, this is a less widely used operation than the above two.

Base.conjMethod
conj(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)).

source

Inverse

Many elements of a Clifford algebra have an inverse. In general, the inverse of a rotor R is equal to R' / abs2(R). It is possible to use other methods to find inverses of arbitrary multivectors of certain Clifford algebras, but this has not been implemented yet.

Inverses cannot exist for multivectors which square to zero. This is trivially true in any Clifford algebra with a degenerate metric, but it is possible to encounter these kinds of elements in algebras with positive-definite metrics.

Binary operations

Addition and subtraction

Addition and subtraction work as expected for Clifford numbers just as they do for other numbers. The promotion system handles all cases where objects of mixed type are added.

Products

Clifford algebras admit a variety of products. Common ones are implemented with infix operators.

Geometric product

The geometric product, or Clifford product, is the defining product of the Clifford algebra. This is implemented with the usual multiplication operator *, but it is also possible to use parenthetical notation as it is with real numbers.

Wedge product

The wedge product is the defining product of the exterior algebra. This is available with the wedge() function, or with the infix operator.

Tip

You can define elements of exterior algebras directly by using Metrics.Exterior(D), whose geometric product is equivalent to the wedge product.

Contractions and dot products

The contraction operations generalize the dot product of vectors to Clifford numbers. While it is possible to define a symmetric dot product (and one is provided in this package), the generalization of the dot product to Clifford numbers is naturally asymmetric in cases where the grade of one input blade is not equal to that of the other.

For Clifford numbers x and y, the left contraction x ⨼ y describes the result of projecting x onto the space spanned by y. If x and y are homogeneous in grade, this product is equal to the geometric product if grade(y) ≥ grade(x), and zero otherwise. For general multivectors, the left contraction can be calculated by applying this rule to the products of their basis blades.

The analogous right contraction is only nonzero if grade(x) ≥ grade(y), and it can be calculated with .

The dot product is a symmetric variation of the left and right contractions, and provides a looser constraint on the basis blades: grade(CliffordNumbers.dot(x,y)) must equal abs(grade(x) - grade(y)). The Hestenes dot product is equivalent to the dot product above, but is zero if either x or y is a scalar.

Note

Currently, the dot product is implemented with the unexported function CliffordNumbers.dot. This package does not depend on LinearAlgebra, so there would be a name conflict if this method were exported and both this package and LinearAlgebra were loaded.

Contractions are generally favored over the dot products due to their nicer implementations and properties, which have fewer exceptions. It is generally recommended that the Hestenes dot product be avoided, though it is included in this library for the sake of completeness as CliffordNumber.hestenes_dot, which is also not exported.

Commutator and anticommutator products

The commutator product (or antisymmetric product) of Clifford numbers x and y, denoted x × y, is equal to 1//2 * (x*y - y*x). This product is nonzero if the geometric product of x and y does not commute, and the value represents the degree to which they fail to commute.

The commutator product is the building block of Lie algebras; in particular, the commutator products of bivectors, which are also bivectors. With the bivectors of 3D space, the Lie algebra is equivalent to that generated by the cross product, hence the × notation.

The analogous anticommutator product (or symmetric product) is 1//2 * (x*y + y*x). This uses the operator, which is not an operator generally used for this purpose, but was selected as it looks similar to the commutator product, with the dot indicating the similarity with the dot product, which is also symmetric.

Defining new products: Multiplication internals

Products are implemented with the fast multiplication kernel CliffordNumbers.mul, which accepts two Clifford numbers with the same scalar type and a CliffordNumbers.GradeFilter object. This GradeFilter object defines a method that takes two or more BitIndex objects and returns false if their product is constrained to be zero.

CliffordNumbers.mul requires that the coefficient types of the numbers being multiplied are the same. Methods which leverage CliffordNumbers.mul should promote the coefficient types of the arguments to a common type using scalar_promote before passing them to the kernel. Any further promotion needed to return the final result is handled by the kernel.

In general, it is also strongly recommended to promote the types of the arguments to CliffordNumbers.Z2CliffordNumber or CliffordNumber for higher performance. Currently, the implementation of CliffordNumbers.mul is asymmetric, and does not consider which input is longer. Even in the preferred order, we find that KVector incurs a significant performance penalty.

Exponentiation

Exponentiation can be done using either a Clifford number as a base and an integer exponent, corresponding to iterations of the geometric product, or a Clifford number may be the exponent associated with a scalar.

Integer powers of Clifford numbers

As with all other Number instances, this can be done with the ^ infix operator:

julia> k = KVector{1,VGA(3)}(4,2,0)
+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.

source

Grade involution

Grade involution changes the sign of all odd grades, an operation equivalent to mirroring every basis vector of the space. This can be acheived with the grade_involution function.

When interpreting even multivectors as elements of the even subalgebra of a given algebra, the reverse operation of the algebra is equivalent to grade involution in the even subalgebra.

Grade involution is equivalent to complex conjugation in when dealing with the even subalgebra of 2D space (which is isomorphic to the complex numbers), but this is not true for quaternion conjugation. Instead, use the Clifford conjugate (described below).

CliffordNumbers.grade_involutionMethod
grade_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.

source

Clifford conjugation

The Clifford conjugate is the combination of the reverse and grade involution. This is implemented as Base.conj(::AbstractCliffordNumber). This operation arises in the application of a transformation, because the grade involution accounts for the sign change associated with the parity of the isometry, and it is combined with the reverse to perform the final operation.

Warning

conj(::AbstractCliffordNumber) implements the Clifford conjugate, not the reverse!

When dealing with the even subalgebras of 2D and 3D VGAs, which are isomorphic to the complex numbers and quaternions, respectively, the Clifford conjugate is equivalent to complex conjugation or quaternion conjugation. Otherwise, this is a less widely used operation than the above two.

Base.conjMethod
conj(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)).

source

Inverse

Many elements of a Clifford algebra have an inverse. In general, the inverse of a rotor R is equal to R' / abs2(R). It is possible to use other methods to find inverses of arbitrary multivectors of certain Clifford algebras, but this has not been implemented yet.

Inverses cannot exist for multivectors which square to zero. This is trivially true in any Clifford algebra with a degenerate metric, but it is possible to encounter these kinds of elements in algebras with positive-definite metrics.

Binary operations

Addition and subtraction

Addition and subtraction work as expected for Clifford numbers just as they do for other numbers. The promotion system handles all cases where objects of mixed type are added.

Products

Clifford algebras admit a variety of products. Common ones are implemented with infix operators.

Geometric product

The geometric product, or Clifford product, is the defining product of the Clifford algebra. This is implemented with the usual multiplication operator *, but it is also possible to use parenthetical notation as it is with real numbers.

Wedge product

The wedge product is the defining product of the exterior algebra. This is available with the wedge() function, or with the infix operator.

Tip

You can define elements of exterior algebras directly by using Metrics.Exterior(D), whose geometric product is equivalent to the wedge product.

Contractions and dot products

The contraction operations generalize the dot product of vectors to Clifford numbers. While it is possible to define a symmetric dot product (and one is provided in this package), the generalization of the dot product to Clifford numbers is naturally asymmetric in cases where the grade of one input blade is not equal to that of the other.

For Clifford numbers x and y, the left contraction x ⨼ y describes the result of projecting x onto the space spanned by y. If x and y are homogeneous in grade, this product is equal to the geometric product if grade(y) ≥ grade(x), and zero otherwise. For general multivectors, the left contraction can be calculated by applying this rule to the products of their basis blades.

The analogous right contraction is only nonzero if grade(x) ≥ grade(y), and it can be calculated with .

The dot product is a symmetric variation of the left and right contractions, and provides a looser constraint on the basis blades: grade(CliffordNumbers.dot(x,y)) must equal abs(grade(x) - grade(y)). The Hestenes dot product is equivalent to the dot product above, but is zero if either x or y is a scalar.

Note

Currently, the dot product is implemented with the unexported function CliffordNumbers.dot. This package does not depend on LinearAlgebra, so there would be a name conflict if this method were exported and both this package and LinearAlgebra were loaded.

Contractions are generally favored over the dot products due to their nicer implementations and properties, which have fewer exceptions. It is generally recommended that the Hestenes dot product be avoided, though it is included in this library for the sake of completeness as CliffordNumber.hestenes_dot, which is also not exported.

Commutator and anticommutator products

The commutator product (or antisymmetric product) of Clifford numbers x and y, denoted x × y, is equal to 1//2 * (x*y - y*x). This product is nonzero if the geometric product of x and y does not commute, and the value represents the degree to which they fail to commute.

The commutator product is the building block of Lie algebras; in particular, the commutator products of bivectors, which are also bivectors. With the bivectors of 3D space, the Lie algebra is equivalent to that generated by the cross product, hence the × notation.

The analogous anticommutator product (or symmetric product) is 1//2 * (x*y + y*x). This uses the operator, which is not an operator generally used for this purpose, but was selected as it looks similar to the commutator product, with the dot indicating the similarity with the dot product, which is also symmetric.

Defining new products: Multiplication internals

Products are implemented with the fast multiplication kernel CliffordNumbers.mul, which accepts two Clifford numbers with the same scalar type and a CliffordNumbers.GradeFilter object. This GradeFilter object defines a method that takes two or more BitIndex objects and returns false if their product is constrained to be zero.

CliffordNumbers.mul requires that the coefficient types of the numbers being multiplied are the same. Methods which leverage CliffordNumbers.mul should promote the coefficient types of the arguments to a common type using scalar_promote before passing them to the kernel. Any further promotion needed to return the final result is handled by the kernel.

In general, it is also strongly recommended to promote the types of the arguments to CliffordNumbers.Z2CliffordNumber or CliffordNumber for higher performance. Currently, the implementation of CliffordNumbers.mul is asymmetric, and does not consider which input is longer. Even in the preferred order, we find that KVector incurs a significant performance penalty.

Exponentiation

Exponentiation can be done using either a Clifford number as a base and an integer exponent, corresponding to iterations of the geometric product, or a Clifford number may be the exponent associated with a scalar.

Integer powers of Clifford numbers

As with all other Number instances, this can be done with the ^ infix operator:

julia> k = KVector{1,VGA(3)}(4,2,0)
 3-element KVector{1, VGA(3), Int64}:
 4e₁ + 2e₂
 
@@ -35,4 +35,4 @@
 
 julia> exptau(KVector{2,VGA(3)}(1/4, 0, 0))
 4-element EvenCliffordNumber{VGA(3), Float64}:
-1.0e₁e₂

This package also provides exptau, which calculates exp(2pi * x).

+1.0e₁e₂

This package also provides exptau, which calculates exp(2pi * x).

diff --git a/dev/performance.html b/dev/performance.html index b7775f0..fd5cb85 100644 --- a/dev/performance.html +++ b/dev/performance.html @@ -1,2 +1,2 @@ -Performance tips · CliffordNumbers.jl

Performance tips

While CliffordNumbers.jl is intended to be a fast library without much special attention needed to obtain good performance, there are some ways to ensure you are maximizing performance that may not be obvious to a first-time user.

Use literal powers when possible

When exponentiating an AbstractCliffordNumber, x^2 is preferred to x*x. This package overloads Base.literal_pow to provide efficient exponentiation in terms of the smallest type needed to represent the result.

As an example, KVector{1}, being a 1-blade, necessarily squares to a scalar, so the return type of (x::KVector{1,Q})^2 is always KVector{0,Q}. In general, every even power of a 1-blade is a scalar, and every odd power is a 1-blade. By contrast, x*x returns an EvenCliffordNumber{Q}. For small algebras, this distinction may not be significant, but in the 4D case, such as with the spacetime algebra, x*x is 8 times longer than x^2 if x is a KVector{1}.

It is also important to note that variable exponents will usually trigger promotion to either EvenCliffordNumber or CliffordNumber, depending on the grading of the input. The greatest benefit comes from exponents that may be evaluated at compile time.

Know which scalar types work best

In general, AbstractFloat scalars are the best choice for the scalar type, followed by Integer, then Rational, then BigInt or BigFloat.

!!! note Fixed point numbers Fixed-point numbers haven't been tested with this package, but they are likely as performant as their backing type, which is usually an Integer.

Scalars that are not pure bits

The most important examples of scalars that are not bits types are BigInt and BigFloat. While these may be necessary to represent certain coefficients accurately, there is a performance penalty for using them.

When a bits type is used as the scalar, Julia can represent an AbstractCliffordNumber as an inline array of scalars without having to resort to pointers. This provides two major benefits:

  • The type can live on the stack, meaning that no allocations are needed.
  • The type can be stored contiguously in an Array.

For types that are not pure bits, the scalars are stored as pointers to data on the heap, which may or may not be contiguous, and the performance is usually reduced.

Rational

Unlike the machine integer types Int8, Int16, Int32, and Int64, or the floating point types Float16, Float32, and Float64, performing operations with Rational types is significantly slower, since it requires the use of Euclidean division, which is very slow compared to addition and multiplication.

Specialized kernels for Rational products are provided that minimize the number of division operations needed, but these are still about 100 times slower than performing the same product with floating point scalars. Improving the speed of these multiplications is a goal for this package, but do not expect the speed to ever rival that of floating-point multiplication or division.

Avoid using CliffordNumber in most circumstances

When performing geometric operations, you can almost always restrict yourself to OddCliffordNumber or EvenCliffordNumber as your largest types. Avoid adding objects with odd and even grades, as this will trigger promotion to CliffordNumber.

If it appears CliffordNumber is needed, you may want to ask whether you are using the correct algebra for your problem. This question is less so about optimization of your code and more so about how you conceptualize your problem: sometimes it makes more sense to use a larger algebra to get a better picture of the geometry, and use EvenCliffordNumber in the larger algebra as your data representation.

One circumstance where you may wish to use CliffordNumber is when working with idempotents of the algebra, which may be relevant when working with spinors.

Know how your CPU's SIMD extensions work

At this point, you've hit hyperoptimization territory. Notes here are intended more so for developers contributing to this package than for ordinary users, but they are included for the sake of completeness.

SIMD width

CliffordNumbers.jl is written to take advantage of CPU SIMD extensions. Usually, these consist of fixed-size registers of 128, 256, or 512 bits, depending on the implementation.

While Julia can generate efficient code for Tuple types with up to 32 elements, it's especially efficient to use types that fit into one SIMD register. When using an x86 CPU with AVX2, which provides 256-bit registers, EvenCliffordNumber{STA,Float32} is a more performant choice than EvenCliffordNumber{STA,Float64}, since the former consists of 8 32-bit scalars (256 bits total) and the latter is twice the size (512 bits total).

SIMD operations

The various products of geometric algebra can be implemented in terms of three common SIMD operations: add, multiply, and permute. Although these operations are usually available for every basic real number type, some implementations have gaps which may prevent SIMD extension from being used.

One notable pitfall is the lack of SIMD multiply instructions for Int64 on x86 with AVX2 only. It is possible to perform a 64-bit multiply using AVX2, but these are not available as single instructions, and Julia's compiler does not generate SIMD code for these operations. On AVX-512 and AVX10, this instruction is available.

+Performance tips · CliffordNumbers.jl

Performance tips

While CliffordNumbers.jl is intended to be a fast library without much special attention needed to obtain good performance, there are some ways to ensure you are maximizing performance that may not be obvious to a first-time user.

Use literal powers when possible

When exponentiating an AbstractCliffordNumber, x^2 is preferred to x*x. This package overloads Base.literal_pow to provide efficient exponentiation in terms of the smallest type needed to represent the result.

As an example, KVector{1}, being a 1-blade, necessarily squares to a scalar, so the return type of (x::KVector{1,Q})^2 is always KVector{0,Q}. In general, every even power of a 1-blade is a scalar, and every odd power is a 1-blade. By contrast, x*x returns an EvenCliffordNumber{Q}. For small algebras, this distinction may not be significant, but in the 4D case, such as with the spacetime algebra, x*x is 8 times longer than x^2 if x is a KVector{1}.

It is also important to note that variable exponents will usually trigger promotion to either EvenCliffordNumber or CliffordNumber, depending on the grading of the input. The greatest benefit comes from exponents that may be evaluated at compile time.

Know which scalar types work best

In general, AbstractFloat scalars are the best choice for the scalar type, followed by Integer, then Rational, then BigInt or BigFloat.

!!! note Fixed point numbers Fixed-point numbers haven't been tested with this package, but they are likely as performant as their backing type, which is usually an Integer.

Scalars that are not pure bits

The most important examples of scalars that are not bits types are BigInt and BigFloat. While these may be necessary to represent certain coefficients accurately, there is a performance penalty for using them.

When a bits type is used as the scalar, Julia can represent an AbstractCliffordNumber as an inline array of scalars without having to resort to pointers. This provides two major benefits:

  • The type can live on the stack, meaning that no allocations are needed.
  • The type can be stored contiguously in an Array.

For types that are not pure bits, the scalars are stored as pointers to data on the heap, which may or may not be contiguous, and the performance is usually reduced.

Rational

Unlike the machine integer types Int8, Int16, Int32, and Int64, or the floating point types Float16, Float32, and Float64, performing operations with Rational types is significantly slower, since it requires the use of Euclidean division, which is very slow compared to addition and multiplication.

Specialized kernels for Rational products are provided that minimize the number of division operations needed, but these are still about 100 times slower than performing the same product with floating point scalars. Improving the speed of these multiplications is a goal for this package, but do not expect the speed to ever rival that of floating-point multiplication or division.

Avoid using CliffordNumber in most circumstances

When performing geometric operations, you can almost always restrict yourself to OddCliffordNumber or EvenCliffordNumber as your largest types. Avoid adding objects with odd and even grades, as this will trigger promotion to CliffordNumber.

If it appears CliffordNumber is needed, you may want to ask whether you are using the correct algebra for your problem. This question is less so about optimization of your code and more so about how you conceptualize your problem: sometimes it makes more sense to use a larger algebra to get a better picture of the geometry, and use EvenCliffordNumber in the larger algebra as your data representation.

One circumstance where you may wish to use CliffordNumber is when working with idempotents of the algebra, which may be relevant when working with spinors.

Know how your CPU's SIMD extensions work

At this point, you've hit hyperoptimization territory. Notes here are intended more so for developers contributing to this package than for ordinary users, but they are included for the sake of completeness.

SIMD width

CliffordNumbers.jl is written to take advantage of CPU SIMD extensions. Usually, these consist of fixed-size registers of 128, 256, or 512 bits, depending on the implementation.

While Julia can generate efficient code for Tuple types with up to 32 elements, it's especially efficient to use types that fit into one SIMD register. When using an x86 CPU with AVX2, which provides 256-bit registers, EvenCliffordNumber{STA,Float32} is a more performant choice than EvenCliffordNumber{STA,Float64}, since the former consists of 8 32-bit scalars (256 bits total) and the latter is twice the size (512 bits total).

SIMD operations

The various products of geometric algebra can be implemented in terms of three common SIMD operations: add, multiply, and permute. Although these operations are usually available for every basic real number type, some implementations have gaps which may prevent SIMD extension from being used.

One notable pitfall is the lack of SIMD multiply instructions for Int64 on x86 with AVX2 only. It is possible to perform a 64-bit multiply using AVX2, but these are not available as single instructions, and Julia's compiler does not generate SIMD code for these operations. On AVX-512 and AVX10, this instruction is available.