Skip to content

Commit

Permalink
Various improvements (#28)
Browse files Browse the repository at this point in the history
* Add Aqua tests and make them pass

* Fuller support for one and zero for all algebras

* Format

* Define LinearAlgebra.norm
  • Loading branch information
tpgillam committed Jan 5, 2024
1 parent e3540f0 commit 428b05a
Show file tree
Hide file tree
Showing 25 changed files with 194 additions and 35 deletions.
8 changes: 6 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
name = "SimpleGA"
uuid = "6f159fe9-4850-48a0-97c4-7cf487b3e6ea"
authors = ["Monumo Ltd.", "Tom Gillam <tpgillam@googlemail.com>"]
version = "0.2.0"
version = "0.2.1"

[deps]
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"

[compat]
Aqua = "0.8"
LinearAlgebra = "1"
SparseArrays = "1"
StaticArrays = "1"
Test = "1"
julia = "1.6"

[extras]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Test"]
test = ["Aqua", "Test"]
11 changes: 8 additions & 3 deletions src/core20.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@ end
function Base.promote_rule(::Type{Odd{S}}, ::Type{Odd{T}}) where {S<:Real,T<:Real}
return Odd{promote_type(S, T)}
end
Base.zero(a::Even) = Even(zero(a.c1))
Base.zero(a::Odd) = Odd(zero(a.c1))
Base.one(a::Even) = Even(one(a.c1))
Base.zero(::Type{Even{T}}) where {T} = Even(zero(Complex{T}))
Base.zero(::Type{Odd{T}}) where {T} = Odd(zero(Complex{T}))
Base.one(::Type{Even{T}}) where {T} = Even(one(Complex{T}))
Base.zero(a::Even) = zero(typeof(a))
Base.zero(a::Odd) = zero(typeof(a))
Base.one(a::Even) = one(typeof(a))

#Addition / subtraction
Base.:(-)(a::Even) = Even(-a.c1)
Expand Down Expand Up @@ -69,6 +72,8 @@ SimpleGA.project(a::Odd, n::Integer) = n == 1 ? a : zero(a)
LinearAlgebra.tr(a::Even) = real(a.c1)
LinearAlgebra.dot(a::Even, b::Even) = real(a.c1 * b.c1)
LinearAlgebra.dot(a::Odd, b::Odd) = real(conj(a.c1) * b.c1)
LinearAlgebra.norm(a::Even) = sqrt(abs(dot(a, a)))
LinearAlgebra.norm(a::Odd) = sqrt(abs(dot(a, a)))

#Exponentiation
Base.exp(a::Even) = Even(exp(a.c1))
Expand Down
11 changes: 8 additions & 3 deletions src/core24.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ function Base.promote_rule(::Type{Odd{S}}, ::Type{Odd{T}}) where {S<:Real,T<:Rea
return Odd{promote_type(S, T)}
end

Base.zero(a::Even) = Even(zero(a.m))
Base.zero(a::Odd) = Odd(zero(a.m))
Base.one(a::Even) = Even(one(a.m))
Base.zero(::Type{Even{T}}) where {T} = Even(zero(SMatrix{4,4,Complex{T},16}))
Base.zero(::Type{Odd{T}}) where {T} = Odd(zero(SMatrix{4,4,Complex{T},16}))
Base.one(::Type{Even{T}}) where {T} = Even(one(SMatrix{4,4,Complex{T},16}))
Base.zero(a::Even) = zero(typeof(a))
Base.zero(a::Odd) = zero(typeof(a))
Base.one(a::Even) = one(typeof(a))

#Addition / subtraction
Base.:(-)(a::Even) = Even(-a.m)
Expand Down Expand Up @@ -107,6 +110,8 @@ function LinearAlgebra.dot(a::Odd, b::Odd)
tmp = real(tr(a.m * g2.m * conj(b.m) * g2.m))
return convert(typeof(tmp), tmp / 4)
end
LinearAlgebra.norm(a::Even) = sqrt(abs(dot(a, a)))
LinearAlgebra.norm(a::Odd) = sqrt(abs(dot(a, a)))

#Exponentiation
Base.exp(a::Even) = Even(exp(a.m))
Expand Down
11 changes: 8 additions & 3 deletions src/core30.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,12 @@ end
function Base.promote_rule(::Type{Odd{S}}, ::Type{Odd{T}}) where {S<:Real,T<:Real}
return Odd{promote_type(S, T)}
end
Base.zero(a::Even) = Even(zero(a.w), zero(a.x), zero(a.y), zero(a.z))
Base.zero(a::Odd) = Odd(zero(a.w), zero(a.x), zero(a.y), zero(a.z))
Base.one(a::Even) = Even(one(a.w), zero(a.x), zero(a.y), zero(a.z))
Base.zero(::Type{Even{T}}) where {T} = Even(zero(T), zero(T), zero(T), zero(T))
Base.zero(::Type{Odd{T}}) where {T} = Odd(zero(T), zero(T), zero(T), zero(T))
Base.one(::Type{Even{T}}) where {T} = Even(one(T), zero(T), zero(T), zero(T))
Base.zero(a::Even) = zero(typeof(a))
Base.zero(a::Odd) = zero(typeof(a))
Base.one(a::Even) = one(typeof(a))

# Addition / subtraction
Base.:(-)(a::Even) = Even(-a.w, -a.x, -a.y, -a.z)
Expand Down Expand Up @@ -118,6 +121,8 @@ end
LinearAlgebra.tr(a::Even) = a.w
LinearAlgebra.dot(a::Even, b::Even) = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z
LinearAlgebra.dot(a::Odd, b::Odd) = -a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z
LinearAlgebra.norm(a::Even) = sqrt(abs(dot(a, a)))
LinearAlgebra.norm(a::Odd) = sqrt(abs(dot(a, a)))

# Exponentiation
function SimpleGA.bivector_exp(a::Even)
Expand Down
21 changes: 18 additions & 3 deletions src/core31.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,22 @@ function Base.promote_rule(::Type{Odd{S}}, ::Type{Odd{T}}) where {S<:Real,T<:Rea
return Odd{promote_type(S, T)}
end

Base.zero(a::Even) = Even(zero(a.c1), zero(a.c2), zero(a.c3), zero(a.c4))
Base.zero(a::Odd) = Odd(zero(a.c1), zero(a.c2), zero(a.c3), zero(a.c4))
Base.one(a::Even) = Even(one(a.c1), zero(a.c2), zero(a.c3), one(a.c4))
function Base.zero(::Type{Even{T}}) where {T}
z = zero(Complex{T})
return Even(z, z, z, z)
end
function Base.zero(::Type{Odd{T}}) where {T}
z = zero(Complex{T})
return Odd(z, z, z, z)
end
function Base.one(::Type{Even{T}}) where {T}
o = one(Complex{T})
z = zero(Complex{T})
return Even(o, z, z, o)
end
Base.zero(a::Even) = zero(typeof(a))
Base.zero(a::Odd) = zero(typeof(a))
Base.one(a::Even) = one(typeof(a))

#Addition / subtraction
Base.:(-)(a::Even) = Even(-a.c1, -a.c2, -a.c3, -a.c4)
Expand Down Expand Up @@ -146,6 +159,8 @@ function LinearAlgebra.dot(a::Odd, b::Odd)
)
return convert(typeof(tmp), tmp / 2)
end
LinearAlgebra.norm(a::Even) = sqrt(abs(dot(a, a)))
LinearAlgebra.norm(a::Odd) = sqrt(abs(dot(a, a)))

#Exponentiation
function SimpleGA.bivector_exp(a::Even)
Expand Down
7 changes: 5 additions & 2 deletions src/core3232.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ function Base.promote_rule(
return Multivector{promote_type(S, T)}
end

Base.zero(a::Multivector) = Multivector([basscl], [zero(a.val[1])])
Base.one(a::Multivector) = Multivector([basscl], [one(a.val[1])])
Base.zero(::Type{Multivector{T}}) where {T} = Multivector([basscl], [zero(T)])
Base.one(::Type{Multivector{T}}) where {T} = Multivector([basscl], [one(T)])
Base.zero(a::Multivector) = zero(typeof(a))
Base.one(a::Multivector) = one(typeof(a))

#This avoids rounding error bloating multivectors. Set of FP64
const mvtol = 1e-14
Expand Down Expand Up @@ -173,6 +175,7 @@ function LinearAlgebra.dot(mv1::Multivector, mv2::Multivector)
end
return res
end
LinearAlgebra.norm(a::Multivector) = sqrt(abs(dot(a, a)))

#Exponentiation
function Base.exp(a::Multivector)
Expand Down
20 changes: 17 additions & 3 deletions src/core33.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,21 @@ function Base.promote_rule(::Type{Odd{S}}, ::Type{Odd{T}}) where {S<:Real,T<:Rea
return Odd{promote_type(S, T)}
end

Base.zero(a::Even) = Even(zero(a.p), zero(a.m))
Base.zero(a::Odd) = Odd(zero(a.p), zero(a.m))
Base.one(a::Even) = Even(one(a.p), one(a.m))
function Base.zero(::Type{Even{T}}) where {T}
z = zero(SMatrix{4,4,T,16})
return Even(z, z)
end
function Base.zero(::Type{Odd{T}}) where {T}
z = zero(SMatrix{4,4,T,16})
return Odd(z, z)
end
function Base.one(::Type{Even{T}}) where {T}
o = one(SMatrix{4,4,T,16})
return Even(o, o)
end
Base.zero(a::Even) = zero(typeof(a))
Base.zero(a::Odd) = zero(typeof(a))
Base.one(a::Even) = one(typeof(a))

#Addition / subtraction
Base.:(-)(a::Even) = Even(-a.p, -a.m)
Expand Down Expand Up @@ -112,6 +124,8 @@ function LinearAlgebra.dot(a::Odd, b::Odd)
tmp = tr(a.p * b.m) + tr(a.m * b.p)
return convert(typeof(tmp), tmp / 8)
end
LinearAlgebra.norm(a::Even) = sqrt(abs(dot(a, a)))
LinearAlgebra.norm(a::Odd) = sqrt(abs(dot(a, a)))

#Exponentiation
Base.exp(a::Even) = Even(exp(a.p), exp(a.m))
Expand Down
14 changes: 9 additions & 5 deletions src/core40.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ Work using self-dual and anti-self-dual decomposition, so just use a pair of qua
Useful algebra for projective geometry.
"""

using ..Quaternions

struct Even{T<:Real} <: Number
qp::Quaternion{T}
qm::Quaternion{T}
Expand All @@ -30,9 +28,12 @@ function Base.promote_rule(::Type{Odd{S}}, ::Type{Odd{T}}) where {S<:Real,T<:Rea
return Odd{promote_type(S, T)}
end

Base.zero(a::Even) = Even(zero(a.qp), zero(a.qm))
Base.zero(a::Odd) = Odd(zero(a.qp), zero(a.qm))
Base.one(a::Even) = Even(one(a.qp), one(a.qm))
Base.zero(::Type{Even{T}}) where {T} = Even(zero(Quaternion{T}), zero(Quaternion{T}))
Base.zero(::Type{Odd{T}}) where {T} = Odd(zero(Quaternion{T}), zero(Quaternion{T}))
Base.one(::Type{Even{T}}) where {T} = Even(one(Quaternion{T}), one(Quaternion{T}))
Base.zero(a::Even) = zero(typeof(a))
Base.zero(a::Odd) = zero(typeof(a))
Base.one(a::Even) = one(typeof(a))

#Addition / subtraction
Base.:(-)(a::Even) = Even(-a.qp, -a.qm)
Expand Down Expand Up @@ -100,6 +101,9 @@ function LinearAlgebra.dot(a::Odd, b::Odd)
return convert(typeof(tmp), tmp / 2)
end

LinearAlgebra.norm(a::Even) = sqrt(abs(dot(a, a)))
LinearAlgebra.norm(a::Odd) = sqrt(abs(dot(a, a)))

#Exponentiation
SimpleGA.bivector_exp(a::Even) = Even(bivector_exp(a.qp), bivector_exp(a.qm))

Expand Down
7 changes: 5 additions & 2 deletions src/core44.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ function Base.promote_rule(
) where {S<:Real,T<:Real}
return Multivector{promote_type(S, T)}
end
Base.zero(a::Multivector) = Multivector([0x00], [zero(a.val[1])])
Base.one(a::Multivector) = Multivector([0x00], [one(a.val[1])])
Base.zero(::Type{Multivector{T}}) where {T} = Multivector([0x00], [zero(T)])
Base.one(::Type{Multivector{T}}) where {T} = Multivector([0x00], [one(T)])
Base.zero(a::Multivector) = zero(typeof(a))
Base.one(a::Multivector) = one(typeof(a))

#Addition / subtraction
Base.:(-)(mv::Multivector) = Multivector(mv.bas, -mv.val)
Expand Down Expand Up @@ -139,6 +141,7 @@ function LinearAlgebra.dot(mv1::Multivector, mv2::Multivector)
end
return res
end
LinearAlgebra.norm(a::Multivector) = sqrt(abs(dot(a, a)))

#Exponentiation
function Base.exp(a::Multivector)
Expand Down
21 changes: 18 additions & 3 deletions src/corecga.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,22 @@ end
Even(q1, q2, q3, q4) = Even(promote(q1, q2, q3, q4)...)
Odd(q1, q2, q3, q4) = Odd(promote(q1, q2, q3, q4)...)

Base.zero(a::Even) = Even(zero(a.q1), zero(a.q1), zero(a.q1), zero(a.q1))
Base.zero(a::Odd) = Odd(zero(a.q1), zero(a.q1), zero(a.q1), zero(a.q1))
Base.one(a::Even) = Even(one(a.q1), zero(a.q1), zero(a.q1), one(a.q1))
function Base.zero(::Type{Even{T}}) where {T}
z = zero(Quaternion{T})
return Even(z, z, z, z)
end
function Base.zero(::Type{Odd{T}}) where {T}
z = zero(Quaternion{T})
return Odd(z, z, z, z)
end
function Base.one(::Type{Even{T}}) where {T}
o = one(Quaternion{T})
z = zero(Quaternion{T})
return Even(o, z, z, o)
end
Base.zero(a::Even) = zero(typeof(a))
Base.zero(a::Odd) = zero(typeof(a))
Base.one(a::Even) = one(typeof(a))

function Base.convert(::Type{Even{T}}, a::Even) where {T<:Real}
return Even{T}(
Expand Down Expand Up @@ -149,6 +162,8 @@ function LinearAlgebra.dot(a::Odd, b::Odd)
tmp = -(dot(a.q1, b.q1) - dot(a.q2, b.q3) + dot(a.q4, b.q4) - dot(a.q3, b.q2))
return convert(typeof(tmp), tmp / 2)
end
LinearAlgebra.norm(a::Even) = sqrt(abs(dot(a, a)))
LinearAlgebra.norm(a::Odd) = sqrt(abs(dot(a, a)))

#Exponentiation
#Uses a simple scale and square implementation.
Expand Down
11 changes: 8 additions & 3 deletions src/corepga.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@ function Base.promote_rule(::Type{Odd{S}}, ::Type{Odd{T}}) where {S<:Real,T<:Rea
return Odd{promote_type(S, T)}
end

Base.zero(a::Even) = Even(zero(a.q), zero(a.n))
Base.zero(a::Odd) = Odd(zero(a.q), zero(a.n))
Base.one(a::Even) = Even(one(a.q), zero(a.n))
Base.zero(::Type{Even{T}}) where {T} = Even(zero(Quaternion{T}), zero(Quaternion{T}))
Base.zero(::Type{Odd{T}}) where {T} = Odd(zero(Quaternion{T}), zero(Quaternion{T}))
Base.one(::Type{Even{T}}) where {T} = Even(one(Quaternion{T}), zero(Quaternion{T}))
Base.zero(a::Even) = zero(typeof(a))
Base.zero(a::Odd) = zero(typeof(a))
Base.one(a::Even) = one(typeof(a))

#Addition / subtraction
Base.:(-)(a::Even) = Even(-a.q, -a.n)
Expand Down Expand Up @@ -86,6 +89,8 @@ end
LinearAlgebra.tr(a::Even) = a.q.w
LinearAlgebra.dot(a::Even, b::Even) = dot(a.q, b.q)
LinearAlgebra.dot(a::Odd, b::Odd) = -dot(a.q, b.q)
LinearAlgebra.norm(a::Even) = sqrt(abs(dot(a, a)))
LinearAlgebra.norm(a::Odd) = sqrt(abs(dot(a, a)))

#Exponentiation
function SimpleGA.bivector_exp(a::Even)
Expand Down
21 changes: 18 additions & 3 deletions src/coresta.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,22 @@ function Base.promote_rule(::Type{Odd{S}}, ::Type{Odd{T}}) where {S<:Real,T<:Rea
return Odd{promote_type(S, T)}
end

Base.zero(a::Even) = Even(zero(a.c1), zero(a.c2), zero(a.c3), zero(a.c4))
Base.zero(a::Odd) = Odd(zero(a.c1), zero(a.c2), zero(a.c3), zero(a.c4))
Base.one(a::Even) = Even(one(a.c1), zero(a.c2), zero(a.c3), one(a.c4))
function Base.zero(::Type{Even{T}}) where {T}
z = zero(Complex{T})
return Even(z, z, z, z)
end
function Base.zero(::Type{Odd{T}}) where {T}
z = zero(Complex{T})
return Odd(z, z, z, z)
end
function Base.one(::Type{Even{T}}) where {T}
o = one(Complex{T})
z = zero(Complex{T})
return Even(o, z, z, o)
end
Base.zero(a::Even) = zero(typeof(a))
Base.zero(a::Odd) = zero(typeof(a))
Base.one(a::Even) = one(typeof(a))

#Addition / subtraction
Base.:(-)(a::Even) = Even(-a.c1, -a.c2, -a.c3, -a.c4)
Expand Down Expand Up @@ -149,6 +162,8 @@ function LinearAlgebra.dot(a::Odd, b::Odd)
)
return convert(typeof(tmp), tmp / 2)
end
LinearAlgebra.norm(a::Even) = sqrt(abs(dot(a, a)))
LinearAlgebra.norm(a::Odd) = sqrt(abs(dot(a, a)))

#Exponentiation
function SimpleGA.bivector_exp(a::Even)
Expand Down
10 changes: 10 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
#Test suite for Geometric Algebra

using Aqua
using SimpleGA
using LinearAlgebra
using Test

include("testfuncs.jl")

@testset "GA Tests" begin
@testset "aqua" begin
# NOTE: We run ambiguities separately, since we _only_ want to include methods in this
# package. See the discussion in this thread:
# https://discourse.julialang.org/t/aqua-jl-finds-many-ambiguities-in-core-base/103963
# By passing only our own package, we skip quite a bit of noise from upstream.
Aqua.test_all(SimpleGA; ambiguities=false)
Aqua.detect_ambiguities(SimpleGA)
end

#! format: off
@testset "GA(2, 0)" begin include("test20.jl") end
@testset "GA(3, 0)" begin include("test30.jl") end
Expand Down
2 changes: 2 additions & 0 deletions test/test20.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Test suite for GA 20.
# Test stand-alone results and compares with GA(4,4)

test_type(GA20.Even, GA20.Odd)

bas20 = GA20.basis
e1 = bas20[1]
e2 = bas20[2]
Expand Down
2 changes: 2 additions & 0 deletions test/test24.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#Test suite for GA(2,4).
#Test stand-alone results and compares with GA(2,4)

test_type(GA24.Even, GA24.Odd)

bas24 = GA24.basis
(g0, g1, g2, g3, g4, g5) = (bas24[1], bas24[2], bas24[3], bas24[4], bas24[5], bas24[6])

Expand Down
2 changes: 2 additions & 0 deletions test/test30.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#Test suite for GA(3,0).
#Test stand-alone results and compares with GA(4,4)

test_type(GA30.Even, GA30.Odd)

bas30 = GA30.basis
e1 = bas30[1]
e2 = bas30[2]
Expand Down
Loading

2 comments on commit 428b05a

@tpgillam
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/98306

Tip: Release Notes

Did you know you can add release notes too? Just add markdown formatted text underneath the comment after the text
"Release notes:" and it will be added to the registry PR, and if TagBot is installed it will also be added to the
release that TagBot creates. i.e.

@JuliaRegistrator register

Release notes:

## Breaking changes

- blah

To add them here just re-invoke and the PR will be updated.

Tagging

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.2.1 -m "<description of version>" 428b05a5d9e2de77aaea20564ad9b010b517b42f
git push origin v0.2.1

Please sign in to comment.