Skip to content

Commit

Permalink
hmmm
Browse files Browse the repository at this point in the history
  • Loading branch information
thofma committed Oct 21, 2024
1 parent d76c540 commit d4cbc4f
Show file tree
Hide file tree
Showing 10 changed files with 181 additions and 44 deletions.
1 change: 1 addition & 0 deletions docs/src/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export default defineConfig({
{ text: 'Introduction', link: 'manual/algebras/intro'},
{ text: 'Basics', link: 'manual/algebras/basics'},
{ text: 'Structure constant algebras', link: 'manual/algebras/structureconstant'},
{ text: 'Group algebras', link: 'manual/algebras/groupalgebras'},
{ text: 'Ideals', link: 'manual/algebras/ideals'},
]
},
Expand Down
70 changes: 70 additions & 0 deletions docs/src/manual/algebras/groupalgebras.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Group algebras

```@meta
CurrentModule = Hecke
DocTestSetup = quote
using Hecke
end
```

As is natural, the basis of a group algebra $K[G]$ correspond to the elements of $G$ with respect
to some arbitrary ordering.

## Creation

```@docs
group_algebra(::Field, ::Group)
```

Note that by default, this construction requires enumerating all elements of
the group and thus is inefficient for large groups. Using the optional argument `sparse = true`,
the algebra can be constructed with a different internal model. This allows for much larger groups,
but not all functionality is available in this case.

```jldoctest
julia> G = abelian_group([2 for i in 1:10]) # group of order 2^10
(Z/2)^10
julia> QG = group_algebra(QQ, G; sparse = true);
```

## Elements

Given a group algebra `A` and an element of a group `g`, the corresponding group algebra element
can be constructed using the syntax `A(g)`.

```jldoctest
julia> G = abelian_group([2, 2]); a = G([0, 1]);
julia> QG = group_algebra(QQ, G);
sparse = false
julia> x = QG(a)
[0, 0, 1, 0]
```

Vice versa, one can obtain the coefficient of a group algebra element `x` with respect to a group
element `a` using the syntax `x[a]`.

```jldoctest
julia> G = abelian_group([2, 2]); a = G([0, 1]);
julia> QG = group_algebra(QQ, G);
julia> x = QG(a)
[0, 0, 1, 0]
julia> x[a]
1
```

It is also possible to create elements from dictionaries:

```jldoctest
julia> G = abelian_group([2, 2]); a = G([0, 1]);
julia> QG = group_algebra(QQ, G);
julia> QG(Dict(a => 2, zero(G) => 1)) == 2 * QG(a) + 1 * QG(zero(G))
true
```
15 changes: 15 additions & 0 deletions src/AlgAss/AbsAlgAss.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
################################################################################
#
# Internal thingy
#
################################################################################

# check if elements are represented using a sparse row

_is_sparse(A::AbstractAssociativeAlgebra) = false

_is_sparse(A::GroupAlgebra) = A.sparse

# because we are lazy
_is_dense(A::AbstractAssociativeAlgebra) = !_is_sparse(A)

_base_ring(A::AbstractAssociativeAlgebra) = base_ring(A)

@doc raw"""
Expand Down
38 changes: 18 additions & 20 deletions src/AlgAss/AlgGrp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,25 @@ end
################################################################################

@doc raw"""
group_algebra(K::Ring, G; op = *) -> GroupAlgebra
group_algebra(K::Ring, G::Group; sparse::Bool = false,
cached::Bool = true) -> GroupAlgebra
Returns the group ring $K[G]$.
$G$ may be any set and `op` a group operation on $G$.
"""
group_algebra(K::Ring, G; op = *, cached::Bool = true, sparse::Bool = false) = GroupAlgebra(K, G; op, sparse, cached)
Return the group algebra of the group $G$ over the ring $R$.
group_algebra(K::Ring, G::FinGenAbGroup; cached::Bool = true, sparse::Bool = false) = GroupAlgebra(K, G; sparse, cached)
# Examples
function group_algebra(K::Field, G; op = *, sparse::Bool = false, cached::Bool = true)
A = GroupAlgebra(K, G; op, sparse, cached)
```jldoctest
julia> QG = group_algebra(QQ, small_group(8, 5))
Group algebra
of generic group of order 8 with multiplication table
over rational field
```
"""
function group_algebra(K::Ring, G; op = *, sparse::Bool = false, cached::Bool = true)
A = GroupAlgebra(K, G; op = op , sparse = sparse, cached = cached)
if !(K isa Field)
return A
end
if iszero(characteristic(K))
A.issemisimple = 1
else
Expand All @@ -78,18 +86,8 @@ function group_algebra(K::Field, G; op = *, sparse::Bool = false, cached::Bool =
return A
end

function group_algebra(K::Field, G::FinGenAbGroup)
A = group_algebra(K, G, op = +)
A.is_commutative = true
return A
end

@doc raw"""
(K::Ring)[G::Group] -> GroupAlgebra
(K::Ring)[G::FinGenAbGroup] -> GroupAlgebra
group_algebra(K::Ring, G::FinGenAbGroup; cached::Bool = true, sparse::Bool = false) = GroupAlgebra(K, G, cached, sparse)

Returns the group ring $K[G]$.
"""
getindex(K::Ring, G::Group) = group_algebra(K, G)
getindex(K::Ring, G::FinGenAbGroup) = group_algebra(K, G)

Expand Down Expand Up @@ -629,7 +627,7 @@ const _reps = [(i=24,j=12,n=5,dims=(1,1,2,3,3),
#
################################################################################

mutable struct AbsAlgAssMorGen{S, T, U, V} <: Map{S, T, HeckeMap, AbsAlgAssMorGen}
mutable struct AbsAlgAssMorGen{S, T, U, V} <: Map{S, T, HeckeMap, Any}#AbsAlgAssMorGen}
domain::S
codomain::T
tempdomain::U
Expand Down
34 changes: 26 additions & 8 deletions src/AlgAss/Elem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
#
################################################################################

_is_sparse(a::AbstractAssociativeAlgebraElem) = false
_is_sparse(a::AbstractAssociativeAlgebraElem) = _is_sparse(parent(a))

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

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

function (A::GroupAlgebra{T, S, R})(c::R) where {T, S, R}
return GroupAlgebraElem{T, typeof(A)}(A, deepcopy(c))
return GroupAlgebraElem{T, typeof(A)}(A, c)
end

function (A::GroupAlgebra{T, S, R})(d::Dict{R, <: Any}) where {T, S, R}
K = base_ring(A)
dd = sparse_row(base_ring(A), [(__elem_index(A, g), K(i)) for (g, i) in d])
if _is_dense(A)
return GroupAlgebraElem{T, typeof(A)}(A, Vector(dd, dim(A)))
else
return GroupAlgebraElem{T, typeof(A)}(A, dd)
end
end

# Generic.Mat needs it
Expand Down Expand Up @@ -727,18 +737,22 @@ function show(io::IO, a::AbstractAssociativeAlgebraElem)
if get(io, :compact, false)
print(io, coefficients(a, copy = false))
else
if a isa GroupAlgebraElem && parent(a).sparse
if _is_sparse(a)
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)))
AbstractAlgebra.expressify(parent(a).base_to_group[i], context = IOContext(io, :compact => true))))
end
end
print(io, AbstractAlgebra.expr_to_string(AbstractAlgebra.canonicalize(sum)))
else
print(io, coefficients(a, copy = false))
ve = Expr(:vect)
for ci in coefficients(a, copy = false)
push!(ve.args, AbstractAlgebra.expressify(ci, context = io))
end
print(io, AbstractAlgebra.expr_to_string(AbstractAlgebra.canonicalize(ve)))
end
end
end
Expand Down Expand Up @@ -781,7 +795,11 @@ end

function ==(a::AbstractAssociativeAlgebraElem{T}, b::AbstractAssociativeAlgebraElem{T}) where {T}
parent(a) != parent(b) && return false
return coefficients(a, copy = false) == coefficients(b, copy = false)
if !_is_sparse(a)
return coefficients(a, copy = false) == coefficients(b, copy = false)
else
return a.coeffs_sparse == b.coeffs_sparse
end
end

################################################################################
Expand Down
41 changes: 26 additions & 15 deletions src/AlgAss/Types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,13 @@ end
@attributes mutable struct GroupAlgebra{T, S, R} <: AbstractAssociativeAlgebra{T}
base_ring::Ring
group::S
# We represent elements using a coefficient vector,
# so all we have to keep track of is which group element corresponds to
# which basis element of the algebra
# This is what group_to_base, base_to_group are for. They realize the map
# G -> {1,...,n}
# {1,...n} -> G

group_to_base::Dict{R, Int}
base_to_group::Vector{R}
one::Vector{T}
Expand All @@ -145,18 +152,21 @@ end
center
maps_to_numberfields
maximal_order

# For the sparse presentation
sparse::Bool
ind::Int
sparse_one
ind::Int # This is the number of group elements currently stored in
# group_to_base and base_to_group.
sparse_one # Store the sparse row for the one element

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

function GroupAlgebra(K::Ring, G; op = *, cached = true, sparse::Bool = false)
return get_cached!(GroupAlgebraID, (K, G, op), cached) do
function GroupAlgebra(K::Ring, G; op = *, cached::Bool = true, sparse::Bool = false)
return get_cached!(GroupAlgebraID, (K, G, op, sparse), cached) do
A = new{elem_type(K), typeof(G), elem_type(G)}()
A.sparse = sparse
A.ind = -1
Expand All @@ -165,9 +175,14 @@ end
A.issemisimple = 0
A.base_ring = K
A.group = G
d = Int(order(G))
A.group_to_base = Dict{elem_type(G), Int}()
A.base_to_group = Vector{elem_type(G)}(undef, d)
if !sparse
@assert is_finite(G)
d = order(Int, G)
A.base_to_group = Vector{elem_type(G)}(undef, d)
else
A.base_to_group = Vector{elem_type(G)}(undef, 1)
end

if A.sparse
if G isa FinGenAbGroup
Expand Down Expand Up @@ -218,7 +233,7 @@ end
end
end

const GroupAlgebraID = AbstractAlgebra.CacheDictType{Tuple{Ring, Any, Any}, GroupAlgebra}()
const GroupAlgebraID = AbstractAlgebra.CacheDictType{Tuple{Ring, Any, Any, Bool}, GroupAlgebra}()

mutable struct GroupAlgebraElem{T, S} <: AbstractAssociativeAlgebraElem{T}
parent::S
Expand All @@ -241,11 +256,7 @@ mutable struct GroupAlgebraElem{T, S} <: AbstractAssociativeAlgebraElem{T}

function GroupAlgebraElem{T, S}(A::S, g::U) where {T, S, U}
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
i = __elem_index(A, g)
a = GroupAlgebraElem{T, S}(A)
a.coeffs_sparse = sparse_row(base_ring(A), [i], [one(base_ring(A))])
return a
Expand All @@ -272,11 +283,11 @@ end

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


################################################################################
#
# AbsAlgAssIdl
Expand Down
6 changes: 5 additions & 1 deletion src/Grp/GenGrp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ end
#
################################################################################

is_finite(::MultTableGroup) = true

elem_type(::Type{MultTableGroup}) = MultTableGroupElem

Base.hash(G::MultTableGroupElem, h::UInt) = Base.hash(G.i, h)
Expand Down Expand Up @@ -256,10 +258,12 @@ end
#
################################################################################

function order(G::MultTableGroup)
function order(::Type{Int}, G::MultTableGroup)
return size(G.mult_table, 1)
end

order(G::MultTableGroup) = order(Int, G)

length(G::MultTableGroup) = order(G)

################################################################################
Expand Down
2 changes: 2 additions & 0 deletions src/GrpAb/GrpAbFinGen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,8 @@ function order(A::FinGenAbGroup)
return prod(elementary_divisors(A))
end

order(::Type{Int}, A::FinGenAbGroup) = Int(order(A))

################################################################################
#
# Exponent
Expand Down
11 changes: 11 additions & 0 deletions test/AlgAss/AlgGrp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,15 @@
end
end
end

# abelian groups

QG = group_algebra(QQ, abelian_group([2, 2]))
@test QG isa GroupAlgebra
@test QG !== group_algebra(QQ, abelian_group([2, 2]); cached = false)
@test QG !== group_algebra(QQ, abelian_group([2, 2]); sparse = true)

QG = group_algebra(QQ, abelian_group([2 for i in 1:10]); sparse = true)
@test QG isa GroupAlgebra
@test QG !== group_algebra(QQ, abelian_group([2 for i in 1:10]); sparse = true, cached = false)
end
7 changes: 7 additions & 0 deletions test/AlgAss/Elem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,11 @@
Hecke.add!(b,b)
@test b == A(matrix(QQ, [6 8; 10 12]))
end

# fancy group algebra element constructor
G = abelian_group([2, 2]); a = G([0, 1]);
QG = group_algebra(QQ, G);
@test QG(Dict(a => 2, zero(G) => 1)) == 2 * QG(a) + 1 * QG(zero(G))
QG = group_algebra(QQ, G; sparse = true);
@test QG(Dict(a => 2, zero(G) => 1)) == 2 * QG(a) + 1 * QG(zero(G))
end

0 comments on commit d4cbc4f

Please sign in to comment.