Skip to content

Commit

Permalink
feat: group algebras with sparse representation
Browse files Browse the repository at this point in the history
  • Loading branch information
thofma committed Oct 19, 2024
1 parent 2af99ca commit d76c540
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 64 deletions.
12 changes: 6 additions & 6 deletions src/AlgAss/AlgGrp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ group(A::GroupAlgebra) = A.group

has_one(A::GroupAlgebra) = true

function (A::GroupAlgebra{T, S, R})(c::Vector{T}; copy::Bool = false) where {T, S, R}
length(c) != dim(A) && error("Dimensions don't match.")
function (A::GroupAlgebra{T, S, R})(c::Union{Vector{T}, SRow{T}}; copy::Bool = false) where {T, S, R}
c isa Vector && length(c) != dim(A) && error("Dimensions don't match.")
return GroupAlgebraElem{T, typeof(A)}(A, copy ? deepcopy(c) : c)
end

Expand Down Expand Up @@ -64,12 +64,12 @@ end
Returns the group ring $K[G]$.
$G$ may be any set and `op` a group operation on $G$.
"""
group_algebra(K::Ring, G; op = *) = GroupAlgebra(K, G, op = op)
group_algebra(K::Ring, G; op = *, cached::Bool = true, sparse::Bool = false) = GroupAlgebra(K, G; op, sparse, cached)

group_algebra(K::Ring, G::FinGenAbGroup) = GroupAlgebra(K, G)
group_algebra(K::Ring, G::FinGenAbGroup; cached::Bool = true, sparse::Bool = false) = GroupAlgebra(K, G; sparse, cached)

function group_algebra(K::Field, G; op = *)
A = GroupAlgebra(K, G, op = op)
function group_algebra(K::Field, G; op = *, sparse::Bool = false, cached::Bool = true)
A = GroupAlgebra(K, G; op, sparse, cached)
if iszero(characteristic(K))
A.issemisimple = 1
else
Expand Down
123 changes: 93 additions & 30 deletions src/AlgAss/Elem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
#
################################################################################

_is_sparse(a::AbstractAssociativeAlgebraElem) = false

_is_sparse(a::GroupAlgebraElem) = parent(a).sparse

function AbstractAlgebra.promote_rule(U::Type{<:AbstractAssociativeAlgebraElem{T}}, ::Type{S}) where {T, S}
if AbstractAlgebra.promote_rule(T, S) === T
return U
Expand Down Expand Up @@ -90,7 +94,11 @@ function one(A::AbstractAssociativeAlgebra)
if !has_one(A)
error("Algebra does not have a one")
end
return A(deepcopy(A.one)) # deepcopy needed by mul!
if !A.sparse
return A(deepcopy(A.one)) # deepcopy needed by mul!
else
return A(deepcopy(A.sparse_one))
end
end

################################################################################
Expand Down Expand Up @@ -151,20 +159,29 @@ end

function +(a::AbstractAssociativeAlgebraElem{T}, b::AbstractAssociativeAlgebraElem{T}) where {T}
parent(a) != parent(b) && error("Parents don't match.")
v = Vector{T}(undef, dim(parent(a)))
for i = 1:dim(parent(a))
v[i] = coefficients(a, copy = false)[i] + coefficients(b, copy = false)[i]
if !_is_sparse(a)
v = Vector{T}(undef, dim(parent(a)))
for i = 1:dim(parent(a))
v[i] = coefficients(a, copy = false)[i] + coefficients(b, copy = false)[i]
end
return parent(a)(v)
else
vv = a.coeffs_sparse + b.coeffs_sparse
return parent(a)(vv)
end
return parent(a)(v)
end

function -(a::AbstractAssociativeAlgebraElem{T}, b::AbstractAssociativeAlgebraElem{T}) where {T}
parent(a) != parent(b) && error("Parents don't match.")
v = Vector{T}(undef, dim(parent(a)))
for i = 1:dim(parent(a))
v[i] = coefficients(a, copy = false)[i] - coefficients(b, copy = false)[i]
if _is_sparse(a)
return parent(a)(a.coeffs_sparse - b.coeffs_sparse)
else
v = Vector{T}(undef, dim(parent(a)))
for i = 1:dim(parent(a))
v[i] = coefficients(a, copy = false)[i] - coefficients(b, copy = false)[i]
end
return parent(a)(v)
end
return parent(a)(v)
end

function *(a::AssociativeAlgebraElem{T}, b::AssociativeAlgebraElem{T}) where {T}
Expand Down Expand Up @@ -200,25 +217,52 @@ end
function *(a::GroupAlgebraElem{T, S}, b::GroupAlgebraElem{T, S}) where {T, S}
parent(a) != parent(b) && error("Parents don't match.")
A = parent(a)
d = dim(A)
v = Vector{T}(undef, d)
for i in 1:d
v[i] = zero(base_ring(A))
end
t = zero(base_ring(A))
mt = multiplication_table(A, copy = false)
acoeff = coefficients(a, copy = false)
bcoeff = coefficients(b, copy = false)
for i in 1:d
if iszero(acoeff[i])
continue
if !_is_sparse(a)
d = dim(A)
v = Vector{T}(undef, d)
for i in 1:d
v[i] = zero(base_ring(A))
end
for j in 1:d
k = mt[i, j]
v[k] = addmul!(v[k], acoeff[i], bcoeff[j], t)
t = zero(base_ring(A))
mt = multiplication_table(A, copy = false)
acoeff = coefficients(a, copy = false)
bcoeff = coefficients(b, copy = false)
for i in 1:d
if iszero(acoeff[i])
continue
end
for j in 1:d
k = mt[i, j]
v[k] = addmul!(v[k], acoeff[i], bcoeff[j], t)
end
end
return A(v)
else
s = sparse_row(base_ring(A))
for (i, ci) in a.coeffs_sparse
r = sparse_row(base_ring(A), [(__elem_index(A, A.base_to_group[i] * A.base_to_group[j]), ci * cj) for (j, cj) in b.coeffs_sparse])
s += r
end
return A(s)
end
end

################################################################################
#
# Getindex for group algebra elements
#
################################################################################

function getindex(a::GroupAlgebraElem{S, GroupAlgebra{S, T, U}}, g::U) where {S, T, U}
if _is_sparse(a)
if !haskey(parent(a).group_to_base, g)
return zero(base_ring(parent(a)))
else
return a.coeffs_sparse[parent(a).group_to_base[g]]
end
else
return a.coeffs[parent(a).group_to_base[g]]
end
return A(v)
end

################################################################################
Expand Down Expand Up @@ -303,6 +347,9 @@ mul!(c::AbstractAssociativeAlgebraElem{T}, a::Union{ Int, ZZRingElem }, b::Abstr

function mul!(c::GroupAlgebraElem{T, S}, a::GroupAlgebraElem{T, S}, b::GroupAlgebraElem{T, S}) where {T, S}
parent(a) != parent(b) && error("Parents don't match.")
if _is_sparse(a)
return a * b
end
A = parent(a)
d = dim(A)

Expand Down Expand Up @@ -449,7 +496,11 @@ divexact_left(a::AbstractAssociativeAlgebraElem, b::AbstractAssociativeAlgebraEl
################################################################################

function *(a::AbstractAssociativeAlgebraElem{S}, b::S) where {S <: RingElem}
return typeof(a)(parent(a), coefficients(a, copy = false).* Ref(b))
if !_is_sparse(a)
return typeof(a)(parent(a), coefficients(a, copy = false).* Ref(b))
else
return typeof(a)(parent(a), a.coeffs_sparse * b)
end
end

*(b::S, a::AbstractAssociativeAlgebraElem{S}) where {S <: RingElem} = a*b
Expand Down Expand Up @@ -676,10 +727,19 @@ function show(io::IO, a::AbstractAssociativeAlgebraElem)
if get(io, :compact, false)
print(io, coefficients(a, copy = false))
else
print(io, "Element of ")
print(io, parent(a))
print(io, " with coefficients ")
print(io, coefficients(a, copy = false))
if a isa GroupAlgebraElem && parent(a).sparse
sum = Expr(:call, :+)
if !iszero(a)
for (i, ci) in a.coeffs_sparse
push!(sum.args,
Expr(:call, :*, AbstractAlgebra.expressify(ci, context = io),
AbstractAlgebra.expressify(parent(a).base_to_group[i], context = io)))
end
end
print(io, AbstractAlgebra.expr_to_string(AbstractAlgebra.canonicalize(sum)))
else
print(io, coefficients(a, copy = false))
end
end
end

Expand Down Expand Up @@ -963,6 +1023,9 @@ end
isone(a::AbstractAssociativeAlgebraElem) = a == one(parent(a))

function iszero(a::AbstractAssociativeAlgebraElem)
if _is_sparse(a)
return length(a.coeffs_sparse) == 0
end
return all(i -> iszero(i), coefficients(a, copy = false))
end

Expand Down
105 changes: 77 additions & 28 deletions src/AlgAss/Types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -145,16 +145,21 @@ end
center
maps_to_numberfields
maximal_order
sparse::Bool
ind::Int
sparse_one

function GroupAlgebra(K::Ring, G::FinGenAbGroup, cached::Bool = true)
A = GroupAlgebra(K, G, op = +, cached = cached)
A.is_commutative = true
return A
end

function GroupAlgebra(K::Ring, G; op = *, cached = true)
function GroupAlgebra(K::Ring, G; op = *, cached = true, sparse::Bool = false)
return get_cached!(GroupAlgebraID, (K, G, op), cached) do
A = new{elem_type(K), typeof(G), elem_type(G)}()
A.sparse = sparse
A.ind = -1
A.is_commutative = 0
A.is_simple = 0
A.issemisimple = 0
Expand All @@ -163,36 +168,50 @@ end
d = Int(order(G))
A.group_to_base = Dict{elem_type(G), Int}()
A.base_to_group = Vector{elem_type(G)}(undef, d)
A.mult_table = zeros(Int, d, d)

i = 2
for g in collect(G)
if isone(g)
A.group_to_base[deepcopy(g)] = 1
A.base_to_group[1] = deepcopy(g)
continue

if A.sparse
if G isa FinGenAbGroup
el = zero(G)
else
el = one(G)
end
A.group_to_base[deepcopy(g)] = i
A.base_to_group[i] = deepcopy(g)
i += 1
A.group_to_base[el] = 1
A.base_to_group[1] = el
A.sparse_one = sparse_row(K, [1], [one(K)])
A.ind = 1 # index - 1 for the next group element
end

v = Vector{elem_type(K)}(undef, d)
for i in 1:d
v[i] = zero(K)
end
v[1] = one(K)
if !A.sparse
A.mult_table = zeros(Int, d, d)
i = 2
for g in collect(G)
if isone(g)
A.group_to_base[deepcopy(g)] = 1
A.base_to_group[1] = deepcopy(g)
continue
end
A.group_to_base[deepcopy(g)] = i
A.base_to_group[i] = deepcopy(g)
i += 1
end

A.one = v
v = Vector{elem_type(K)}(undef, d)
for i in 1:d
v[i] = zero(K)
end
v[1] = one(K)

A.one = v

for i = 1:d
for j = 1:d
l = op(A.base_to_group[i], A.base_to_group[j])
A.mult_table[i, j] = A.group_to_base[l]
for i = 1:d
for j = 1:d
l = op(A.base_to_group[i], A.base_to_group[j])
A.mult_table[i, j] = A.group_to_base[l]
end
end
end

@assert all(A.mult_table[1, i] == i for i in 1:dim(A))
@assert all(A.mult_table[1, i] == i for i in 1:dim(A))
end

return A
end::GroupAlgebra{elem_type(K), typeof(G), elem_type(G)}
Expand All @@ -204,19 +223,35 @@ const GroupAlgebraID = AbstractAlgebra.CacheDictType{Tuple{Ring, Any, Any}, Grou
mutable struct GroupAlgebraElem{T, S} <: AbstractAssociativeAlgebraElem{T}
parent::S
coeffs::Vector{T}
coeffs_sparse

function GroupAlgebraElem{T, S}(A::S) where {T, S}
z = new{T, S}()
z.parent = A
z.coeffs = Vector{T}(undef, size(A.mult_table, 1))
for i = 1:length(z.coeffs)
z.coeffs[i] = A.base_ring()
if !A.sparse
z.coeffs = Vector{T}(undef, size(A.mult_table, 1))
for i = 1:length(z.coeffs)
z.coeffs[i] = A.base_ring()
end
else
z.coeffs_sparse = sparse_row(base_ring(A))
end
return z
end

function GroupAlgebraElem{T, S}(A::S, g::U) where {T, S, U}
return A[A.group_to_base[g]]
if A.sparse
i = get!(A.group_to_base, g) do
A.ind += 1
A.base_to_group[A.ind] = g
return A.ind
end
a = GroupAlgebraElem{T, S}(A)
a.coeffs_sparse = sparse_row(base_ring(A), [i], [one(base_ring(A))])
return a
else
return A[A.group_to_base[g]]
end
end

# This does not make a copy of coeffs
Expand All @@ -226,8 +261,22 @@ mutable struct GroupAlgebraElem{T, S} <: AbstractAssociativeAlgebraElem{T}
z.coeffs = coeffs
return z
end

function GroupAlgebraElem{T, S}(A::S, coeffs::SRow{T}) where {T, S}
z = new{T, S}()
z.parent = A
z.coeffs_sparse = coeffs
return z
end
end

__elem_index(A, g) = get!(A.group_to_base, g) do
A.ind += 1
A.base_to_group[A.ind] = g
return A.ind
end


################################################################################
#
# AbsAlgAssIdl
Expand Down

0 comments on commit d76c540

Please sign in to comment.