Internal methods
Hamming weights and related operations
CliffordNumbers.Hamming
— ModuleCliffordNumbers.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.
CliffordNumbers.Hamming.isevil
— FunctionCliffordNumbers.Hamming.isevil(i::Integer) -> Bool
Determines whether a number is evil, meaning that its Hamming weight (sum of its binary digits) is even.
CliffordNumbers.Hamming.isodious
— FunctionCliffordNumbers.Hamming.isodious(i::Integer) -> Bool
Determines whether a number is odious, meaning that its Hamming weight (sum of its binary digits) is odd.
CliffordNumbers.Hamming.number_of_parity
— FunctionCliffordNumbers.Hamming.number_of_parity(n::Integer, modulo::Bool)
Returns the nth number whose Hamming weight is even (for modulo = false
) or odd (for modulo = true
).
CliffordNumbers.Hamming.evil_number
— FunctionCliffordNumbers.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).
CliffordNumbers.Hamming.odious_number
— FunctionCliffordNumbers.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).
CliffordNumbers.Hamming.next_of_hamming_weight
— FunctionCliffordNumbers.Hamming.next_of_hamming_weight(n::Integer)
Returns the next integer with the same Hamming weight as n
.
CliffordNumbers.Hamming.hamming_number
— FunctionCliffordNumbers.Hamming.hamming_number(w::Integer, n::Integer)
Gets the n
th 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
Indexing
CliffordNumbers.signmask
— FunctionCliffordNumbers.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).
CliffordNumbers._sort_with_parity!
— FunctionCliffordNumbers._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.
CliffordNumbers.blade_indices_type
— FunctionCliffordNumbers.blade_indices_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 AbstractBladeIndices{Q,C}
object. This is to avoid issues with the proliferation of type parameters that would construct identical BladeIndices
objects otherwise: for instance, BladeIndices{VGA(3),EvenCliffordNumber{VGA(3),Float32,4}}()
and BladeIndices{VGA(3),EvenCliffordNumber{VGA(3),Int}}()
have identical elements, and are equal when compared with ==
, but are not the same object.
Preventing proliferation of type parameters is critical when working with generated functions that have no generic implementation (i.e. an if @generated
block).
For types defined in this package, this strips the scalar type parameter T
and any length parameter present, but leaves the algebra type parameter Q
.
Examples
julia> CliffordNumbers.blade_indices_type(CliffordNumber{VGA(3),Float32,8})
CliffordNumber{VGA(3)}
julia> CliffordNumbers.blade_indices_type(KVector{2,STA,Bool})
KVector{2,STA}
CliffordNumbers.CGNBladeIndices
— TypeCliffordNumbers.CGNBladeIndices{Q,C<:AbstractCliffordNumber{Q},N,I,R}
Compactly represents all valid indices of C
in a singleton type. The last three type parameters are Boolean values which represent the application of negation (N
), grade involution (I
), or reversion (R
) to the indices.
Broadcasting
Custom broadcast implementations are used to change the values of the type parameters N
, I
, and R
, so that the types do not need to be managed directly with their constructors.
Printing of each variant type is done using map
syntax:
julia> show(CliffordNumbers.CGNBladeIndices{VGA(3),KVector{2,VGA(3)},true,true,true}())
-map(conj, BladeIndices(KVector{2, VGA(3)}))
Aliases
For convenience, the alias BladeIndices
is provided, which produces none of these transformations.
Construction
CliffordNumbers.zero_tuple
— FunctionCliffordNumbers.zero_tuple(::Type{T}, ::Val{L}) -> NTuple{L,T}
Generates a Tuple
of length L
with all elements being zero(T)
.
CliffordNumbers.zero_tuple(::Type{C<:AbstractCliffordNumber})
-> NTuple{nblades(C),scalar_type(C)}
Generates a Tuple
that can be used to construct zero(C)
.
CliffordNumbers.check_element_count
— FunctionCliffordNumbers.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.
Multiplication kernels
CliffordNumbers.mul
— FunctionCliffordNumbers.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.
CliffordNumbers.GradeFilter
— TypeCliffordNumbers.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 BladeIndex{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})(::BladeIndex{Q}, ::BladeIndex{Q}) # Or if the definition allows for more arguments (::GradeFilter{:f})(::BladeIndex{Q}...) where Q
CliffordNumbers.nondegenerate_mask
— FunctionCliffordNumbers.nondegenerate_mask(a::BladeIndex{Q}, B::NTuple{L,BladeIndex{Q}})
Constructs a Boolean mask which is false
for any multiplication that squares a degenerate blade; true
otherwise.
CliffordNumbers.mul_mask
— FunctionCliffordNumbers.mul_mask(F::GradeFilter, a::BladeIndex{Q}, B::NTuple{L,BladeIndices{Q}})
CliffordNumbers.mul_mask(F::GradeFilter, B::NTuple{L,BladeIndices{Q}}, a::BladeIndex{Q})
CliffordNumbers.mul_mask(F::GradeFilter, a::BladeIndex{Q}, B::BladeIndices{Q})
CliffordNumbers.mul_mask(F::GradeFilter, B::BladeIndices{Q}, a::BladeIndex{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
.
CliffordNumbers.mul_signs
— FunctionCliffordNumbers.mul_signs(F::GradeFilter, a::BladeIndex{Q}, B::NTuple{L,BladeIndices{Q}})
CliffordNumbers.mul_signs(F::GradeFilter, B::NTuple{L,BladeIndices{Q}}, a::BladeIndex{Q})
CliffordNumbers.mul_signs(F::GradeFilter, a::BladeIndex{Q}, B::BladeIndices{Q})
CliffordNumbers.mul_signs(F::GradeFilter, B::BladeIndices{Q}, a::BladeIndex{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}()
.
CliffordNumbers.bitindex_shuffle
— FunctionCliffordNumbers.bitindex_shuffle(a::BladeIndex{Q}, B::NTuple{L,BladeIndex{Q}})
CliffordNumbers.bitindex_shuffle(a::BladeIndex{Q}, B::BladeIndices{Q})
CliffordNumbers.bitindex_shuffle(B::NTuple{L,BladeIndex{Q}}, a::BladeIndex{Q})
CliffordNumbers.bitindex_shuffle(B::BladeIndices{Q}, a::BladeIndex{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 BladeIndex{Q}
objects suitable for implementing a geometric product.
Taylor series exponential
CliffordNumbers.exp_taylor
— FunctionCliffordNumbers.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.
Return types for operations
CliffordNumbers.product_return_type
— FunctionCliffordNumbers.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.
CliffordNumbers.exponential_type
— FunctionCliffordNumbers.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.