diff --git a/src/AlgAss/AlgGrp.jl b/src/AlgAss/AlgGrp.jl index 1e1517f7ef..5569d2be57 100644 --- a/src/AlgAss/AlgGrp.jl +++ b/src/AlgAss/AlgGrp.jl @@ -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 @@ -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 diff --git a/src/AlgAss/Elem.jl b/src/AlgAss/Elem.jl index 976dbfc966..712d87c90a 100644 --- a/src/AlgAss/Elem.jl +++ b/src/AlgAss/Elem.jl @@ -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 @@ -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 ################################################################################ @@ -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} @@ -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 ################################################################################ @@ -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) @@ -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 @@ -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 @@ -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 diff --git a/src/AlgAss/Types.jl b/src/AlgAss/Types.jl index d69398e353..254d402a0f 100644 --- a/src/AlgAss/Types.jl +++ b/src/AlgAss/Types.jl @@ -145,6 +145,9 @@ 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) @@ -152,9 +155,11 @@ end 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 @@ -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)} @@ -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 @@ -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