# Mathematical operations

## Involutions and duals

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

## Inverses

`CliffordNumbers.versor_inverse`

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

`Base.inv`

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

## 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.muladd`

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

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

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

.

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

.

`CliffordNumbers.dot`

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

`CliffordNumbers.hestenes_dot`

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

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

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

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

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

### Scalar products and normalization

`CliffordNumbers.scalar_product`

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

.

`Base.abs2`

— Method`abs2(x::AbstractCliffordNumber{Q,T}) -> T`

Calculates the squared norm of `x`

, equal to `scalar_product(x, x')`

.

`Base.abs`

— Method`abs(x::AbstractCliffordNumber{Q,T}) -> Union{Real,Complex}`

Calculates the norm of `x`

, equal to `sqrt(scalar_product(x, x'))`

.

`CliffordNumbers.normalize`

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

Normalizes `x`

so that its magnitude (as calculated by `abs2(x)`

) is 1.

## Exponentiation

`Base.exp`

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

`CliffordNumbers.exppi`

— Function`CliffordNumbers.exptau`

— Function