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.bitindices_type
— FunctionCliffordNumbers.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}
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 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
CliffordNumbers.nondegenerate_mask
— FunctionCliffordNumbers.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.
CliffordNumbers.mul_mask
— FunctionCliffordNumbers.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
.
CliffordNumbers.mul_signs
— FunctionCliffordNumbers.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}()
.
CliffordNumbers.bitindex_shuffle
— FunctionCliffordNumbers.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.
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.