Internal methods


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(i::Integer) -> Bool

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

CliffordNumbers.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(n::Integer, modulo::Bool)

Returns the nth number whose Hamming weight is even (for modulo = false) or odd (for modulo = true).


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


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


julia> CliffordNumbers.hamming_number(3, 2)


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

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.


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.


julia> CliffordNumbers.bitindices_type(CliffordNumber{VGA(3),Float32,8})

julia> CliffordNumbers.bitindices_type(KVector{2,STA,Bool})


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

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

    -> NTuple{nblades(C),scalar_type(C)}

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

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.

Multiplication kernels

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


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


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(::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.


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.