Skip to content

Commit

Permalink
Created nblades function to avoid conflict with Base.length seman…
Browse files Browse the repository at this point in the history
…tics
  • Loading branch information
brainandforce committed May 17, 2024
1 parent 2a7b8c4 commit d4aa7d4
Show file tree
Hide file tree
Showing 10 changed files with 46 additions and 37 deletions.
1 change: 1 addition & 0 deletions docs/src/api/clifford.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

```@docs
CliffordNumbers.AbstractCliffordNumber
CliffordNumbers.nblades
CliffordNumbers.scalar_type
CliffordNumbers.similar_type
```
Expand Down
2 changes: 1 addition & 1 deletion src/CliffordNumbers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export VGA2D, VGA3D, PGA2D, PGA3D, CGA2D, CGA3D, STA, STAEast, STAWest, STAP, ST
# Abstract supertype for all Clifford numbers
include("abstract.jl")
export AbstractCliffordNumber
export signature, scalar_type
export nblades, signature, scalar_type
# Working with the grades represented by an AbstractCliffordNumber subtype
include("grades.jl")
export nonzero_grades, has_grades_of
Expand Down
34 changes: 24 additions & 10 deletions src/abstract.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,21 @@
AbstractCliffordNumber{Q,T} <: Number
An element of a Clifford algebra, often referred to as a multivector, with quadratic form `Q` and
element type `T`.
element type `T`. These are statically size and therefore should be able to be stored inline in
arrays or other data structures,
# Interface
## Required implementation
All subtypes `C` of `AbstractCliffordNumber{Q}` must implement the following functions:
* `Base.length(x::C)` should return the number of nonzero basis elements represented by `x`.
* `CliffordNumbers.similar_type(::Type{C}, ::Type{T}, ::Type{Q}) where {C,T,Q}` should construct a
new type similar to `C` which subtypes `AbstractCliffordNumber{Q,T}` that may serve as a
constructor.
* `Base.getindex(x::C, b::BitIndex{Q})` should allow one to recover the coefficients associated
with each basis blade represented by `C`.
## Required implementation for static types
* `Base.length(::Type{C})` should be defined, with `Base.length(x::C) = length(typeof(x))`.
* `nblades(::Type{C})` should be defined to return the number of basis blades represented by the
type. By default, `nblades(x::AbstractCliffordNumber) = nblades(typeof(x))`.
* `Base.Tuple(x::C)` should return the tuple used to construct `x`. The fallback is
`getfield(x, :data)::Tuple`, so any type declared with a `NTuple` field named `data` should have
this defined automatically.
Expand All @@ -30,6 +29,21 @@ end

(::Type{T})(x::Vararg{BaseNumber}) where {Q,T<:AbstractCliffordNumber{Q}} = T(x)

#---Number of blades-------------------------------------------------------------------------------#
"""
nblades(::Type{<:Number}) -> Int
nblades(x::Number)
Returns the number of blades represented by a `Number` subtype or instance. For subtypes of `Number`
that are not `AbstractCliffordNumber`, this is always 1.
This function is separate from `Base.length` since `AbstractCliffordNumber` is a scalar type for
which `collect()` returns a zero-dimensional array. For consistency, `length(x)` should always equal
`length(collect(x))`.
"""
nblades(::Type{<:Number}) = 1
nblades(x::Number) = nblades(typeof(x))

#---Get type parameters----------------------------------------------------------------------------#
"""
signature(T::Type{<:AbstractCliffordNumber{Q}}) = Q
Expand Down Expand Up @@ -76,13 +90,13 @@ zero_tuple(::Type{T}, ::Val{L}) where {T,L} = ntuple(Returns(zero(T)), Val(L))

"""
CliffordNumbers.zero_tuple(::Type{C<:AbstractCliffordNumber})
-> NTuple{length(C),scalar_type(C)}
-> NTuple{nblades(C),scalar_type(C)}
Generates a `Tuple` that can be used to construct `zero(C)`.
"""
zero_tuple(::Type{C}) where C<:AbstractCliffordNumber = zero_tuple(scalar_type(C), Val(length(C)))
zero_tuple(::Type{C}) where C<:AbstractCliffordNumber = zero_tuple(scalar_type(C), Val(nblades(C)))

zero(::Type{C}) where C<:AbstractCliffordNumber = C(zero_tuple(Bool, Val(length(C))))
zero(::Type{C}) where C<:AbstractCliffordNumber = C(zero_tuple(Bool, Val(nblades(C))))
zero(x::AbstractCliffordNumber) = zero(typeof(x))

# The default defintion assumes oneunit(T) = T(one(x))
Expand Down Expand Up @@ -193,11 +207,11 @@ short_typename(::Type{C}) where C<:AbstractCliffordNumber = C
short_typename(x::AbstractCliffordNumber) = short_typename(typeof(x))

function show(io::IO, x::AbstractCliffordNumber)
print(io, short_typename(x), (isone(length(x)) ? string('(', only(Tuple(x)), ')') : Tuple(x)))
print(io, short_typename(x), (isone(nblades(x)) ? string('(', only(Tuple(x)), ')') : Tuple(x)))
end

function summary(io::IO, x::AbstractCliffordNumber)
println(io, length(x), "-element ", short_typename(x), ":")
println(io, nblades(x), "-element ", short_typename(x), ":")
end

#---Algebra mismatch errors------------------------------------------------------------------------#
Expand Down
4 changes: 2 additions & 2 deletions src/bitindices.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ by `C`.
abstract type AbstractBitIndices{Q,C<:AbstractCliffordNumber{Q}} <: AbstractVector{BitIndex{Q}}
end

size(::Type{<:AbstractBitIndices{Q,C}}) where {Q,C} = tuple(length(C))
size(::Type{<:AbstractBitIndices{Q,C}}) where {Q,C} = tuple(nblades(C))
size(b::AbstractBitIndices) = size(typeof(b))

length(::Type{<:AbstractBitIndices{Q,C}}) where {Q,C} = length(C)
length(::Type{<:AbstractBitIndices{Q,C}}) where {Q,C} = nblades(C)
length(::T) where T<:AbstractBitIndices = length(T)

# Conversion to tuple
Expand Down
8 changes: 3 additions & 5 deletions src/cliffordnumber.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,11 @@ CliffordNumber{Q}(x::Tuple{Vararg{T}}) where {Q,T<:BaseNumber} = CliffordNumber{
CliffordNumber{Q}(x::Tuple{Vararg{BaseNumber}}) where Q = CliffordNumber{Q}(promote(x...))

# Convert real/complex numbers to CliffordNumber
(::Type{T})(x::BaseNumber) where T<:CliffordNumber = T(ntuple(i -> x*isone(i), Val(length(T))))
(::Type{T})(x::BaseNumber) where T<:CliffordNumber = T(ntuple(i -> x*isone(i), Val(nblades(T))))

#---Number of elements-----------------------------------------------------------------------------#

length(::Type{<:CliffordNumber{Q}}) where Q = blade_count(Q)
length(m::CliffordNumber) = length(typeof(m))

nblades(::Type{<:CliffordNumber{Q}}) where Q = blade_count(Q)
nonzero_grades(::Type{<:CliffordNumber{Q}}) where Q = 0:dimension(Q)

#---Default BitIndices construction should include all possible BitIndex objects-------------------#
Expand All @@ -54,7 +52,7 @@ end

#---Multiplicative identity------------------------------------------------------------------------#

one(C::Type{<:CliffordNumber{Q}}) where Q = C(ntuple(isone, Val(length(C))))
one(C::Type{<:CliffordNumber{Q}}) where Q = C(ntuple(isone, Val(nblades(C))))

#---Similar types----------------------------------------------------------------------------------#

Expand Down
8 changes: 3 additions & 5 deletions src/even.jl
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,11 @@ function Z2CliffordNumber{P,Q}(x::Tuple{Vararg{BaseNumber}}) where {P,Q}
end

# Convert real/complex numbers to CliffordNumber
(::Type{T})(x::BaseNumber) where {T<:Z2CliffordNumber} = T(ntuple(i -> x*isone(i), Val(length(T))))
(::Type{T})(x::BaseNumber) where {T<:Z2CliffordNumber} = T(ntuple(i -> x*isone(i), Val(nblades(T))))

#---Number of elements-----------------------------------------------------------------------------#

length(::Type{<:Z2CliffordNumber{P,Q}}) where {P,Q} = div(blade_count(Q), 2)
length(x::Z2CliffordNumber) = length(typeof(x))

nblades(::Type{<:Z2CliffordNumber{P,Q}}) where {P,Q} = div(blade_count(Q), 2)
nonzero_grades(::Type{<:Z2CliffordNumber{P,Q}}) where {P,Q} = P:2:dimension(Q)

#---Indexing---------------------------------------------------------------------------------------#
Expand All @@ -83,7 +81,7 @@ end

#---Multiplicative identity------------------------------------------------------------------------#

one(C::Type{<:EvenCliffordNumber{Q}}) where Q = C(ntuple(isone, Val(length(C))))
one(C::Type{<:EvenCliffordNumber{Q}}) where Q = C(ntuple(isone, Val(nblades(C))))

#---Similar types----------------------------------------------------------------------------------#

Expand Down
6 changes: 2 additions & 4 deletions src/kvector.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ KVector{K,Q}(x::Tuple{Vararg{BaseNumber}}) where {K,Q} = KVector{K,Q}(promote(x.

#---Number of elements-----------------------------------------------------------------------------#

length(::Type{KVector{K,Q,T,L}}) where {K,Q,T,L} = L
length(::Type{<:KVector{K,Q}}) where {K,Q} = binomial(dimension(Q), K)
length(x::KVector) = length(typeof(x))
nblades(::Type{<:KVector{K,Q}}) where {K,Q} = binomial(dimension(Q), K)

#---Indexing---------------------------------------------------------------------------------------#

Expand All @@ -52,7 +50,7 @@ end
@inline function to_index(C::Type{<:KVector{K,Q}}, b::BitIndex{Q}) where {K,Q}
# Default to 1 as a valid index for any KVector instance
i = 1
for n in 1:length(C)
for n in 1:nblades(C)
is_same_blade(b, (@inbounds BitIndices(C)[n])) && (i = n)
end
return i
Expand Down
6 changes: 3 additions & 3 deletions src/math.jl
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ conj(x::T) where T<:KVector = T(x.data .* Int8(-1)^!iszero((grade(x) + 1) & 2))
function +(x::AbstractCliffordNumber, y::BaseNumber)
T = promote_type(typeof(x), typeof(y))
b = BitIndices(T)
data = ntuple(i -> x[b[i]] + (iszero(grade(b[i])) * y), Val(length(T)))
data = ntuple(i -> x[b[i]] + (iszero(grade(b[i])) * y), Val(nblades(T)))
return T(data)
end

Expand All @@ -112,14 +112,14 @@ end
function -(x::AbstractCliffordNumber, y::BaseNumber)
T = promote_type(typeof(x), typeof(y))
b = BitIndices(T)
data = ntuple(i -> x[b[i]] - (iszero(grade(b[i])) * y), Val(length(T)))
data = ntuple(i -> x[b[i]] - (iszero(grade(b[i])) * y), Val(nblades(T)))
return T(data)
end

function -(x::BaseNumber, y::AbstractCliffordNumber)
T = promote_type(typeof(x), typeof(y))
b = BitIndices(T)
data = ntuple(i -> (iszero(grade(b[i])) * x) - y[b[i]], Val(length(T)))
data = ntuple(i -> (iszero(grade(b[i])) * x) - y[b[i]], Val(nblades(T)))
return T(data)
end

Expand Down
2 changes: 1 addition & 1 deletion src/multiply.jl
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ kernel just returns the geometric product.
x_mask = mul_mask(F(), a, inds)
# Filter out indexing operations that automatically go to zero
# This must be done manually since we want to work directly with tuples
y_mask = map(in, grade.(inds), ntuple(Returns(nonzero_grades(y)), Val(length(C))))
y_mask = map(in, grade.(inds), ntuple(Returns(nonzero_grades(y)), Val(nblades(C))))
# Don't append operations that won't actually do anything
if any(x_mask) && any(y_mask)
# Resolve BitIndex to an integer here to avoid having to call Base.to_index at runtime
Expand Down
12 changes: 6 additions & 6 deletions test/indexing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,10 @@ end
end

@testset "Type lengths" begin
@test length(KVector{2,STA}) === length(KVector{2,STA,Int,6})
@test length(zero(KVector{2,STA})) === length(KVector{2,STA,Int,6})
@test length(CliffordNumber{STA}) === length(CliffordNumber{STA,Int,16})
@test length(zero(CliffordNumber{STA})) === length(CliffordNumber{STA,Int,16})
@test length(EvenCliffordNumber{STA}) === length(EvenCliffordNumber{STA,Int,8})
@test length(zero(EvenCliffordNumber{STA})) === length(EvenCliffordNumber{STA,Int,8})
@test nblades(KVector{2,STA}) === nblades(KVector{2,STA,Int,6})
@test nblades(zero(KVector{2,STA})) === nblades(KVector{2,STA,Int,6})
@test nblades(CliffordNumber{STA}) === nblades(CliffordNumber{STA,Int,16})
@test nblades(zero(CliffordNumber{STA})) === nblades(CliffordNumber{STA,Int,16})
@test nblades(EvenCliffordNumber{STA}) === nblades(EvenCliffordNumber{STA,Int,8})
@test nblades(zero(EvenCliffordNumber{STA})) === nblades(EvenCliffordNumber{STA,Int,8})
end

0 comments on commit d4aa7d4

Please sign in to comment.