AdditiveGroup <: Group ?
Is there a good reason to keep these separated?
I can think that one wants to separate the use of zero vs one, but one can do something like
one(::AdditativeGroup) = error("blabla")
if one would like to.
Was a decision on this reached after discussion of the Group interface?
Currently I believe Group is for multiplicative groups and mathematically speaking an AdditiveGroup is not a MultiplicativeGroup.
Perhaps it would make more sense to have AdditiveGroup <: Group and MultiplicativeGroup <: Group. But I am not sure this is actually useful. I'm not a computational group theorist, so don't have a good conception of this stuff.
On Mon, Apr 26, 2021 at 02:37:02AM -0700, wbhart wrote:
Was a decision on this reached after discussion of the Group interface?
Currently I believe Group is for multiplicative groups and mathematically speaking an AdditiveGroup is not a MultiplicativeGroup.
Perhaps it would make more sense to have AdditiveGroup <: Group and MultiplicativeGroup <: Group. But I am not sure this is actually useful. I'm not a computational group theorist, so don't have a good conception of this stuff.
The problem is that any generic group algorithm that uses * will fail on any group that uses + In Magma, in the generic, this is handled by using "op" for both cases...
-- You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub: https://github.com/Nemocas/AbstractAlgebra.jl/issues/795#issuecomment-826678782
In that spirit, can one define a fake-interface for additive group inside of generic group functions? The point would be to avoid code duplication, while still exposing all generic functions also for additive groups, where it makes sense. The compiler should figure this out through aggressive inline, which the Julia compiler usually performs, so no runtime implications.
With Julia as opposed to Oscar type conventions:
abstract type AGrp end
abstract type MGrp end
const Grp = Union{AGrp, MGrp}
grp_ops(::Type{G}) where {G <: AGrp} = (zero,+,-)
grp_ops(::Type{G}) where {G <: MGrp} = (one,*,inv)
struct A <: AGrp
a :: Int
end
Base.zero(::Type{A}) = A(0)
Base.:+(a1::A, a2::A) = A(a1.a+a2.a)
Base.:-(a::A) = A(-a.a)
struct M <: MGrp
a :: Int
end
Base.one(::Type{M}) = M(0)
Base.:*(a1::M, a2::M) = M(a1.a+a2.a)
Base.inv(a::M) = M(-a.a)
function commutator(a::G, b::G) where {G <: Grp}
(one,*,inv) = grp_ops(G)
return a * b * inv(b*a)
end
commutator(A(1), A(2))
commutator(M(1), M(2))