Skip to content

Commit

Permalink
Ripped out old QuadraticForm internals
Browse files Browse the repository at this point in the history
  • Loading branch information
brainandforce committed May 2, 2024
1 parent fe6ed1b commit ec20185
Show file tree
Hide file tree
Showing 15 changed files with 86 additions and 330 deletions.
10 changes: 5 additions & 5 deletions src/CliffordNumbers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ const BaseNumber = Union{Real,Complex}
include("hamming.jl")
# New module for metric signatures
include("metrics.jl")
export Metrics
using .Metrics
import .Metrics: dimension, blade_count, grades, is_degenerate, is_positive_definite
# Tools for defining quadratic forms/metric signatures (convention may not be great)
include("quadratic.jl")
export QuadraticForm, APS, STA, VGA, PGA, CGA
export dimension, blade_count, grades
export Metrics
export Signature, VGA, PGA, CGA, LGA, LGAEast, LGAWest, Exterior
export dimension, blade_count, grades, is_degenerate, is_positive_definite
export VGA2D, VGA3D, PGA2D, PGA3D, CGA2D, CGA3D, STA, STAEast, STAWest, STAP, STAPEast, STAPWest
# Abstract supertype for all Clifford numbers
include("abstract.jl")
export AbstractCliffordNumber
Expand Down
4 changes: 0 additions & 4 deletions src/abstract.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ end
(::Type{T})(x::Vararg{BaseNumber}) where {Q,T<:AbstractCliffordNumber{Q}} = T(x)

#---Get type parameters----------------------------------------------------------------------------#

QuadraticForm(::Type{<:AbstractCliffordNumber{Q}}) where Q = Q
QuadraticForm(::AbstractCliffordNumber{Q}) where Q = Q

"""
signature(T::Type{<:AbstractCliffordNumber{Q}}) = Q
signature(x::AbstractCliffordNumber{Q}) = Q
Expand Down
84 changes: 5 additions & 79 deletions src/bitindex.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ end
Base.UInt(i::BitIndex) = i.i & ~signmask(Int)
Base.Int(i::BitIndex) = Int(UInt(i))

const GenericBitIndex = BitIndex{QuadraticForm}

#---Treat as scalar for the sake of broadcasting---------------------------------------------------#

Broadcast.broadcastable(b::BitIndex) = tuple(b)
Expand Down Expand Up @@ -72,17 +70,6 @@ function _sort_with_parity(t::NTuple{L}) where L
return (ntuple(i -> v[i], Val(L)), sign)
end

function _bitindex(Q::Type{<:QuadraticForm}, t::NTuple)
@assert all(in(1:blade_count(Q)), t) "1-vector indices are between 1 and $(blade_count(Q))."
(t, parity) = _sort_with_parity(t)
i = signmask(UInt, parity)
for x in t
# Pairs of identical elements will be removed with xor
i = xor(i, 2^(x-1))
end
return BitIndex{Q}(i)
end

function _bitindex(::Val{S}, t::NTuple) where S
@assert all(in(eachindex(S)), t) "Some of the indices are not valid for the given signature."
(t, parity) = _sort_with_parity(t)
Expand All @@ -94,7 +81,7 @@ function _bitindex(::Val{S}, t::NTuple) where S
end

"""
BitIndex(::Type{Q}, i::Integer...)
BitIndex(::Val{Q}, i::Integer...)
BitIndex(x, i::Integer...) = BitIndex(signature(x), i...)
Constructs a `BitIndex{Q}` from a list of integers that represent the basis 1-vectors of the space.
Expand All @@ -104,26 +91,11 @@ This package uses a lexicographic convention for basis blades: in the algebra of
basis bivectors are {e₁e₂, e₁e₃, e₂e₃}. The sign of the `BitIndex{Q}` is negative when the parity of
the basis vector permutation is odd.
"""
BitIndex(::Type{Q}, i::Integer...) where Q<:QuadraticForm = _bitindex(Q, promote(i...))
BitIndex(S::Val, i::Integer...) = _bitindex(S, promote(i...))
BitIndex(x, i::Integer...) = BitIndex(Val(signature(x)), i...)

#---Show method------------------------------------------------------------------------------------#

function show(io::IO, b::BitIndex{Q}) where Q<:QuadraticForm
print(io, "-"^signbit(b), BitIndex, "(", Q, iszero(Int(b)) ? ")" : ", ")
iszero(UInt(b)) && return nothing
found_first_vector = false
for a in 1:min(dimension(Q), 8*sizeof(UInt) - 1)
if !iszero(UInt(b) & 2^(a-1))
found_first_vector && print(io, ", ")
print(io, a)
found_first_vector = true
end
end
print(io, ")")
end

function show(io::IO, b::BitIndex{Q}) where Q
print(io, "-"^signbit(b), BitIndex, "(Val(", Q, ")", iszero(Int(b)) ? ")" : ", ")
iszero(UInt(b)) && return nothing
Expand Down Expand Up @@ -229,14 +201,8 @@ end
Returns the signbit associated with squaring the basis blade indexed by `b`.
"""
function signbit_of_square(b::BitIndex{QuadraticForm{P,Q,R}}) where {P,Q,R}
return xor(!iszero(grade(b) & 2), isodd(count_ones(UInt(b) & -2^P)))
end

signbit_of_square(b::BitIndex{<:QuadraticForm{<:Any,0,<:Any}}) = !iszero(grade(b) & 2)

function signbit_of_square(b::BitIndex{Q}) where Q
return xor(!iszero(grade(b) & 2), isodd(count_ones(UInt(b) & !positive_square_bits(b))))
return xor(!iszero(grade(b) & 2), isodd(count_ones(UInt(b) & ~positive_square_bits(Q))))
end

"""
Expand All @@ -245,10 +211,7 @@ end
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`.
"""
nondegenerate_square(b::BitIndex{QuadraticForm{P,Q,R}}) where {P,Q,R} = iszero(UInt(b) & -2^(P+Q))
nondegenerate_square(::BitIndex{<:QFNondegenerate}) = true

nondegenerate_square(b::BitIndex{Q}) where Q = iszero(UInt(b) & !zero_square_bits(Q))
nondegenerate_square(b::BitIndex{Q}) where Q = iszero(UInt(b) & zero_square_bits(Q))

"""
CliffordNumbers.sign_of_square(b::BitIndex) -> Int8
Expand Down Expand Up @@ -283,18 +246,6 @@ end

# Account for the sign bits of signed integers
signbit_of_mult(a::Integer, b::Integer) = xor(signbit_of_mult(unsigned.(a,b)...), signbit(xor(a,b)))
signbit_of_mult(a::GenericBitIndex, b::GenericBitIndex) = signbit_of_mult(UInt(a), UInt(b))

function signbit_of_mult(
a::BitIndex{QuadraticForm{P,Q,R}},
b::BitIndex{QuadraticForm{P,Q,R}}
) where {P,Q,R}
base_signbit = xor(signbit_of_mult(UInt(a), UInt(b)), signbit(a), signbit(b))
iszero(Q) && return base_signbit
# Only perform this test for pseudo-Riemannian metrics
q = sum(UInt(2)^(n-1) for n in P .+ (1:Q); init=0)
return xor(base_signbit, !isevil(UInt(a) & UInt(b) & q))
end

function signbit_of_mult(a::BitIndex{Q}, b::BitIndex{Q}) where Q
base_signbit = xor(signbit_of_mult(UInt(a), UInt(b)), signbit(a), signbit(b))
Expand All @@ -304,46 +255,21 @@ end
signbit_of_mult(i) = signbit_of_mult(i,i)

"""
CliffordNumbers.nondegenerate_mult(a::T, b::T) where T<:BitIndex{QuadraticForm{P,Q,R}} -> Bool
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`.
"""
function nondegenerate_mult(
a::BitIndex{QuadraticForm{P,Q,R}},
b::BitIndex{QuadraticForm{P,Q,R}}
) where {P,Q,R}
# This mask filters out the nondegenerate components, which are the highest bits
mask = -UInt(2)^(P+Q)
return iszero(UInt(a) & UInt(b) & mask)
end

nondegenerate_mult(a::BitIndex{Q}, b::BitIndex{Q}) where Q<:QuadraticForm{<:Any,<:Any,0} = true

function nondegenerate_mult(a::BitIndex{Q}, b::BitIndex{Q}) where Q
return iszero(UInt(a) & UInt(b) & zero_square_bits(Q))
end

"""
CliffordNumbers.sign_of_mult(a::T, b::T) where T<:BitIndex{QuadraticForm{P,Q,R}} -> Int8
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.
"""
function sign_of_mult(
a::BitIndex{QuadraticForm{P,Q,R}},
b::BitIndex{QuadraticForm{P,Q,R}}
) where {P,Q,R}
base_signbit = signbit_of_mult(UInt(a), UInt(b))
# For Euclidean spaces no further processing is needed
iszero(R) && return Int8(-1)^base_signbit
# If any dimension squares to zero, just return zero
r = sum(UInt(2)^(n-1) for n in (P + Q) .+ (1:R); init=0)
return iszero(UInt(a) & UInt(b) & r) ? Int8(-1)^base_signbit : Int8(0)
end

sign_of_mult(a::GenericBitIndex, b::GenericBitIndex) = Int8(-1)^signbit_of_mult(a,b)

function sign_of_mult(a::BitIndex{Q}, b::BitIndex{Q}) where Q
return Int8(-1)^signbit_of_mult(a,b) * !nondegenerate_mult(a,b)
end
Expand Down
6 changes: 1 addition & 5 deletions src/cliffordnumber.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ nonzero_grades(::Type{<:CliffordNumber{Q}}) where Q = 0:dimension(Q)
#---Default BitIndices construction should include all possible BitIndex objects-------------------#

BitIndices{Q}() where Q = BitIndices{Q,CliffordNumber{Q}}()
BitIndices(Q::Type{<:QuadraticForm}) = BitIndices{Q}()
BitIndices(Q::Metrics.AbstractSignature) = BitIndices{Q}()

#---Clifford number indexing-----------------------------------------------------------------------#

Expand All @@ -50,10 +50,6 @@ BitIndices(Q::Type{<:QuadraticForm}) = BitIndices{Q}()
return sign(b) * (@inbounds x.data[to_index(x, b)])
end

@inline function getindex(x::CliffordNumber{Q}, b::GenericBitIndex) where Q
return sign(b) * x.data[to_index(x, b)]
end

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

one(C::Type{<:CliffordNumber{Q}}) where Q = C(ntuple(isone, Val(length(C))))
Expand Down
2 changes: 2 additions & 0 deletions src/convert.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ end

#---Specialized conversion methods for certain representations and signatures----------------------#

#= TODO: fix this once metric signature interface stabilizes
function convert(::Type{T}, x::AbstractCliffordNumber{QFComplex,<:Real}) where T<:BaseNumber
return convert(T, x[scalar_index(x)] + x[pseudoscalar_index(x)] * im)
end
function convert(::Type{T}, z::Complex) where T<:AbstractCliffordNumber{QFComplex,<:Real}
return convert(T, CliffordNumber{QFComplex}(real(z), imag(z)))
end
=#

# k-vectors of grade 0 are scalars
convert(::Type{T}, k::KVector{0}) where T<:BaseNumber = convert(T, only(k.data))
Expand Down
5 changes: 3 additions & 2 deletions src/kvector.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@ end

#---Multiplicative identity and pseudoscalar-------------------------------------------------------#

one(C::Type{Q}) where Q = KVector{0,Q}(numeric_type(C)(true))
one(::Type{<:AbstractCliffordNumber{Q}}) where Q = one(Q)
one(::Type{<:KVector{<:Any,Q}}) where Q = KVector{0,Q}(true)
one(::Type{<:KVector{<:Any,Q,T}}) where {Q,T} = KVector{0,Q,T}(true)
one(::Type{<:AbstractCliffordNumber{Q}}) where Q = one(KVector{0,Q})

pseudoscalar(::Type{Q}) where Q = KVector{dimension(Q),Q}(true)

Expand Down
1 change: 0 additions & 1 deletion src/math.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ isscalar(x::Union{CliffordNumber,EvenCliffordNumber}) = all(iszero, Tuple(x)[2:e
isscalar(x::OddCliffordNumber) = iszero(x)
isscalar(x::KVector) = iszero(x)
isscalar(::KVector{0}) = true
isscalar(::AbstractCliffordNumber{QuadraticForm{0,0,0}}) = true
isscalar(::BaseNumber) = true

"""
Expand Down
2 changes: 1 addition & 1 deletion src/metrics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ const STAP = STAPWest
@doc (@doc STAPWest) STAP

export dimension, blade_count, grades, is_degenerate, is_positive_definite
export VGA, PGA, CGA, LGA, LGAEast, LGAWest
export Signature, VGA, PGA, CGA, LGA, LGAEast, LGAWest
export VGA2D, VGA3D, PGA2D, PGA3D, CGA2D, CGA3D, STA, STAEast, STAWest, STAP, STAPEast, STAPWest

Base.show(io::IO, s::Union{VGA,PGA,CGA,LGA}) = print(io, typeof(s), '(', signed(s.dimensions), ')')
Expand Down
Loading

0 comments on commit ec20185

Please sign in to comment.