diff --git a/src/GroupRings.jl b/src/GroupRings.jl index 46e7ee5..531f360 100644 --- a/src/GroupRings.jl +++ b/src/GroupRings.jl @@ -10,164 +10,8 @@ using Markdown import Base: convert, show, hash, ==, +, -, *, ^, //, /, length, getindex, setindex!, eltype, one, zero -############################################################################### -# -# GroupRings / GroupRingsElem -# -############################################################################### - -mutable struct GroupRing{Gr<:Group, T<:GroupElem} <: Ring - group::Gr - basis::Vector{T} - basis_dict::Dict{T, Int} - pm::Array{Int,2} - - function GroupRing(G::Gr, basis::Vector{T}; - cachedmul::Bool=false) where {Gr, T} - RG = new{Gr, T}(G, basis, reverse_dict(basis)) - cachedmul && initializepm!(RG) - return RG - end - - function GroupRing(G::Gr, b::Vector{T}, b_d::Dict{T, Int}, pm::Array{Int,2}) where {Gr,T} - return new{Gr, T}(G, b, b_d, pm) - end - - function GroupRing(G::Gr, pm::Array{Int,2}) where {Gr} - RG = new{Gr, elem_type(G)}(G) - RG.pm = pm - return RG - end -end - -mutable struct GroupRingElem{T, A<:AbstractVector, GR<:GroupRing} <: RingElem - coeffs::A - parent::GR - - function GroupRingElem{T, A, GR}(c::AbstractVector{T}, RG::GR, check=true) where {T, A, GR} - if check - if isdefined(RG, :basis) - length(c) == length(RG.basis) || throw( - "Can't create GroupRingElem -- lengths differ: length(c) = - $(length(c)) != $(length(RG.basis)) = length(RG.basis)") - else - @warn("Basis of the GroupRing is not defined.") - end - end - return new{T, A, GR}(c, RG) - end -end - export GroupRing, GroupRingElem, complete!, create_pm, star, aug, supp -############################################################################### -# -# GroupRing / GroupRingElem constructors -# -############################################################################### - -function GroupRingElem(c::AbstractVector, RG::GroupRing) - return GroupRingElem{eltype(c), typeof(c), typeof(RG)}(c, RG) -end - -function GroupRing(G::Generic.PermGroup; cachedmul::Bool=false) - return GroupRing(G, vec(collect(G)), cachedmul=cachedmul) -end - -function GroupRing(G::Group, basis::Vector, pm::Array{Int,2}) - size(pm,1) == size(pm,2) || throw("pm must be square, got $(size(pm))") - eltype(basis) == elem_type(G) || throw("Basis must consist of elements of $G") - return GroupRing(G, basis, reverse_dict(basis), pm) -end - -############################################################################### -# -# Type and parent object methods -# -############################################################################### - -elem_type(::Type{GroupRing}) = GroupRingElem - -eltype(::Type{GroupRingElem{T, A, Gr}}) where {T, A, Gr} = T - -parent(g::GroupRingElem) = g.parent - -parent_type(X::GroupRingElem) = typeof(parent(X)) - -import Base.promote_rule - -promote_rule(::Type{GroupRingElem{T}}, ::Type{GroupRingElem{S}}) where {T,S} = - GroupRingElem{promote_type(T,S)} - -function convert(::Type{T}, X::GroupRingElem) where {T<:Number} - return GroupRingElem(Vector{T}(X.coeffs), parent(X)) -end - -############################################################################### -# -# Parent object call overloads -# -############################################################################### - -# sparse storage: - -zero(RG::GroupRing, T::Type=Int) = RG(T) -one(RG::GroupRing, T::Type=Int) = RG(RG.group(), T) -one(RG::GroupRing{<:MatSpace}, T::Type=Int) = RG(one(RG.group), T) - -function (RG::GroupRing)(T::Type=Int) - isdefined(RG, :basis) || throw("Can not coerce without basis of GroupRing") - return GroupRingElem(spzeros(T,length(RG.basis)), RG) -end - -function (RG::GroupRing)(i::Int, T::Type=Int) - elt = RG(T) - elt[RG.group()] = i - return elt -end - -function (RG::GroupRing{<:MatSpace})(i::Int, T::Type=Int) - elt = RG(T) - elt[one(RG.group)] = i - return elt -end - -function (RG::GroupRing)(g::GroupElem, T::Type=Int) - result = RG(T) - result[RG.group(g)] = one(T) - return result -end - -function (RG::GroupRing{Gr,T})(V::Vector{T}, S::Type=Int) where {Gr<:Group, T<:GroupElem} - res = RG(S) - for g in V - res[g] += one(S) - end - return res -end - -function (RG::GroupRing)(f::Function, X::GroupRingElem{T}) where T - isdefined(RG, :basis) || throw("Can not coerce without basis of GroupRing") - res = RG(T) - for g in supp(X) - res[f(g)] = X[g] - end - return res -end - -# keep storage type - -function (RG::GroupRing)(x::AbstractVector{T}) where T<:Number - isdefined(RG, :basis) || throw("Basis of GroupRing not defined. For advanced use the direct constructor of GroupRingElem is provided.") - length(x) == length(RG.basis) || throw("Can not coerce to $RG: lengths differ") - return GroupRingElem(x, RG) -end - -function (RG::GroupRing)(X::GroupRingElem) - RG == parent(X) || throw("Can not coerce!") - return RG(X.coeffs) -end - ############################################################################### # # Basic manipulation && Array protocol diff --git a/src/types.jl b/src/types.jl new file mode 100644 index 0000000..91eb17f --- /dev/null +++ b/src/types.jl @@ -0,0 +1,161 @@ +############################################################################### +# +# GroupRing & GroupRingElem structs +# +############################################################################### + +mutable struct GroupRing{R<:Ring, Gr<:Group, El<:GroupElem} <: NCRing + base_ring::R + group::Gr + basis::Vector{El} + basis_dict::Dict{El, Int32} + pm::Matrix{Int32} + + function GroupRing(coeffring::Ring, group::Group, basis::Vector{<:GroupElem}; + halfradius_length::Integer=0) + + elem_type(group) == eltype(basis) || + throw(ArgumentError("Basis must consist of elements of $G")) + + RG = new{typeof(coeffring), typeof(group), eltype(basis)}( + coeffring, group, basis, reverse_dict(basis)) + + if halfradius_length > 0 + pm = zeros(Int32, halfradius_length, halfradius_length) + setcache!(RG, pm) + end + + return RG + end + + function GroupRing(coeffring::Ring, group::Group, basis::Vector{<:GroupElem}, + basis_dict::Dict{<:GroupElem,<:Integer}, pm::Matrix{<:Integer}) + size(pm,1) == size(pm,2) || + throw(ArgumentError("Multiplication table must be square, got one of size $(size(pm))")) + elem_type(group) == eltype(basis) || + throw(ArgumentError("Basis must consist of elements of $G")) + + RG = new{typeof(coeffring), typeof(group), eltype(basis)}( + coeffring, group, basis, basis_dict, pm) + + return RG + end + + function GroupRing(coeffring::Ring, group::Group, pm::Matrix{<:Integer}) + size(pm,1) == size(pm,2) || throw(ArgumentError("Multiplication table must be square, got one of size $(size(pm))")) + + RG = new{typeof(coeffring), typeof(group), elem_type(group)}(coeffring, group) + setcache!(RG, pm) + return RG + end +end + +mutable struct GroupRingElem{T, GR<:GroupRing} <: NCRingElem + coeffs::SparseVector{T, Int} + parent::GR + + function GroupRingElem(c::AbstractVector{T}, RG::GR; check::Bool=true) where {T, GR} + if check + T == elem_type(base_ring(RG)) || throw(DomainError(c, "Call parent group ring on the vector to coerce the coefficients.s")) + length(c) == length(RG) || throw(DomainError(c, "Can not coerce vector to $RG -- lengths differ:\n $(length(c)) ≠ $(length(RG))")) + end + return new{eltype(c), GR}(sparse(c), RG) + end +end + +############################################################################### +# +# Constructors & parent object call overloads (NCRing interface) +# +############################################################################### + +(RG::GroupRing)(i::Integer=0)= _coerce_scalar(RG, i) +(RG::GroupRing)(x::RingElem) = _coerce_scalar(RG, x) + +function (RG::GroupRing)(X::GroupRingElem{T}) where {T} + if RG == parent(X) && elem_type(base_ring(RG)) == T + return X + end + if RG.group == parent(X).group + return GroupRingElem(base_ring(RG).(X.coeffs), RG) # we do checks here + end + throw(ArgumentError("Can not coerce to $RG.")) +end + +############################################################################### +# +# Additional Constructors / parent call overloads +# +############################################################################### + +function GroupRing(coeffring::Ring, group::Group, basis::Vector{<:GroupElem}, + pm::Matrix{<:Integer}) + return GroupRing(coeffring, group, basis, reverse_dict(basis), pm) +end + +function (RG::GroupRing)(g::GroupElem, val=one(base_ring(RG))) + v = sparsevec([RG[g]], [base_ring(RG)(val)], length(RG)) + return GroupRingElem(v, RG, check=false) +end + +function (RG::GroupRing{R, G, El})(V::AbstractVector{El}, + vals=[one(base_ring(RG)) for _ in V]) where {R, G, El} + hasbasis(RG) || throw(ArgumentError("Can not embedd without basis of $RG")) + l = length(RG) + nzind = [RG[g] for g in V] + return GroupRingElem(sparsevec(nzind, base_ring(RG).(vals), l), RG, check=false) +end + +function (RG::GroupRing)(f, X::GroupRingElem) + hasbasis(RG) || throw(ArgumentError("Can not embedd without basis of $RG")) + suppX = supp(X) + return RG([f(g) for g in suppX], [X[g] for g in suppX]) +end + +function (RG::GroupRing)(v::AbstractVector; + adjust_length::Bool=false, widen_coefficients::Bool=false) + + if adjust_length + l = length(RG) + if length(v) < l + @warn "Coefficients vector is length-defficient; adjusting." + v = sparse(v) + v = sparse(v.nzind, v.nzval, l) + elseif length(c) > l + throw(DomainError(v, "Can not coerce vector to $RG -- lengths differ:\n $(length(v)) ≠ $(length(RG))")) + end + end + + if widen_coefficients + parent(first(v)) != base_ring(RG) + RG = change_base_ring(RG, parent(first(v))) + return GroupRingElem(v, RG) + else + R = base_ring(RG) + return GroupRingElem(R.(v), RG) + end +end + +function AbstractAlgebra.change_base_ring(RG::GroupRing, R::Ring) + if base_ring(RG) == R + return RG + end + if hasbasis(RG) && cachesmultiplication(RG) + return GroupRing(R, RG.group, RG.basis, RG.basis_dict, RG.pm) + elseif hasbasis(RG) + return GroupRing(R, RG.group, RG.basis, RG.basis_dict) + elseif cachesmultiplication(RG) + return GroupRing(R, RG.group, RG.pm) + end + throw(ArgumentError("Could not change the base ring of $RG to $R")) +end + +function AbstractAlgebra.change_base_ring(X::GroupRingElem, R::Ring) + if base_ring(parent(X)) == R + return X + else + RG = change_base_ring(parent(X), R) + return RG(X.coeffs) + end +end +