# Grades and indices

## Grades

`CliffordNumbers.nonzero_grades`

— Function```
nonzero_grades(::Type{<:AbstractCliffordNumber})
nonzero_grades(::AbstractCliffordNumber)
```

A function returning an indexable object representing all nonzero grades of a Clifford number representation.

This function is used to define the indexing of `RepresentedGrades`

, and should be defined for any subtypes of `AbstractCliffordNumber`

.

**Examples**

```
julia> CliffordNumbers.nonzero_grades(CliffordNumber{APS})
0:3
julia> CliffordNumbers.nonzero_grades(KVector{2,APS})
2:2
```

`CliffordNumbers.has_grades_of`

— Function```
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.

`BitIndex`

`CliffordNumbers.BitIndex`

— Type`BitIndex{Q}`

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

.

`CliffordNumbers.is_same_blade`

— Function`CliffordNumbers.is_same_blade(a::BitIndex{Q}, b::BitIndex{Q})`

Checks if `a`

and `b`

perform identical indexing up to sign.

### Special indices

`CliffordNumbers.scalar_index`

— Function`scalar_index(x::AbstractCliffordNumber{Q}) -> BitIndex{Q}`

Constructs the `BitIndex`

used to obtain the scalar (grade zero) portion of `x`

.

`CliffordNumbers.pseudoscalar_index`

— Function`pseudoscalar_index(x::AbstractCliffordNumber{Q}) -> BitIndex{Q}`

Constructs the `BitIndex`

used to obtain the pseudoscalar (highest grade) portion of `x`

.

### Tools for implementing mathematical operations

`Base.reverse`

— Method```
adjoint(i::BitIndex) = reverse(i::BitIndex) = i' -> BitIndex
adjoint(x::AbstractCliffordNumber) = 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`

.

`CliffordNumbers.grade_involution`

— Method```
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.

`Base.conj`

— Method```
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))`

.

`CliffordNumbers.left_complement`

— Method`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 either`

grade(b)`or`

dimension(Q) - grade(b)`must be even. The complement is independent of the signature of`

Q`, depending only on the dimension.

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

`CliffordNumbers.right_complement`

— Method`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 either`

grade(b)`or`

dimension(Q) - grade(b)`must be even. The complement is independent of the signature of`

Q`, depending only on the dimension.

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

`CliffordNumbers.grade`

— Method`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))`

).

`CliffordNumbers.sign_of_square`

— Function`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)`

.

`CliffordNumbers.signbit_of_square`

— Function`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.

`CliffordNumbers.nondegenerate_square`

— Function`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`

.

`CliffordNumbers.sign_of_mult`

— Function`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.

`CliffordNumbers.signbit_of_mult`

— Function```
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.

`CliffordNumbers.nondegenerate_mult`

— Function`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`

.

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

.

`CliffordNumbers.has_wedge`

— Function`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.

`BitIndices`

and related types

`CliffordNumbers.AbstractBitIndices`

— Type`AbstractBitIndices{Q,C<:AbstractCliffordNumber{Q}} <: AbstractVector{BitIndex{Q}}`

Supertype for vectors containing all valid `BitIndex{Q}`

objects for the basis elements represented by `C`

.

`CliffordNumbers.BitIndices`

— Type`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.

`CliffordNumbers.TransformedBitIndices`

— Type`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.