Hi @jlapeyre, I think the problem with your singleton implementation is that you’re hitting dynamic dispatch, which is very expensive. If you’re only interested in groups that only have multiplication, not addition then your look-up table approach is probably best, (though it’ll be faster if you can enforce bounds checking. You also might want to replace your integers with Enums for stylistic reasons.
If you’re interested in algebraic structures that also have addition, such Clifford algebras, things get a bit more complicated. What we really want, is a sort of hybrid approach where we hoist as much of the computation to compile time as possible without hitting dynamic dispatch. @chakravala achieves this sort of hoisting in his Grassmann.jl package by abusing Base.@pure
, but I’ve found it’s possible to get great performance using generated functions as well.
For example, if you imagine a real clifford algebra in 2D, there are 4 elements, id, γ1, γ2, γ1γ2
. If you represent some general multivector a*id + b*γ1 + c*γ2 + d*γ1γ2
as a tuple (a, b, c, d)
then you can generate an implicit multiplication table inside a @generated
function such that the multiplication
(a*id + b*γ1 + c*γ2 + d*γ1γ2) * (e*id + f*γ1 + g*γ2 + h*γ1γ2)
lowers to just
((a*e + b*f + c*g - d*h),
(a*f + b*e - c*h + d*g),
(a*g + e*c + b*h - d*f),
(a*h + d*e + b*g - c*f))
That is, you want to unroll the loop over the multiplication table at compile time, so that the only thing that happens at runtime is the multiplication of coefficients, with no looping. If you’d like, I can give an example of doing this in a generated function.