133 lines
3.8 KiB
Julia
133 lines
3.8 KiB
Julia
struct DirectPower{Gr,N,GEl<:GroupsCore.GroupElement} <: GroupsCore.Group
|
|
group::Gr
|
|
|
|
function DirectPower{N}(G::GroupsCore.Group) where {N}
|
|
@assert N > 1
|
|
return new{typeof(G),N,eltype(G)}(G)
|
|
end
|
|
end
|
|
|
|
struct DirectPowerElement{GEl,N,Gr<:GroupsCore.Group} <: GroupsCore.GroupElement
|
|
elts::NTuple{N,GEl}
|
|
parent::DirectPower{Gr,N,GEl}
|
|
end
|
|
|
|
function DirectPowerElement(
|
|
elts::AbstractVector{<:GroupsCore.GroupElement},
|
|
G::DirectPower,
|
|
)
|
|
return DirectPowerElement(ntuple(i -> elts[i], _nfold(G)), G)
|
|
end
|
|
|
|
_nfold(::DirectPower{Gr,N}) where {Gr,N} = N
|
|
|
|
function Base.one(G::DirectPower)
|
|
return DirectPowerElement(ntuple(_ -> one(G.group), _nfold(G)), G)
|
|
end
|
|
|
|
function Base.eltype(::Type{<:DirectPower{Gr,N,GEl}}) where {Gr,N,GEl}
|
|
return DirectPowerElement{GEl,N,Gr}
|
|
end
|
|
|
|
function Base.iterate(G::DirectPower)
|
|
itr = Iterators.ProductIterator(ntuple(i -> G.group, _nfold(G)))
|
|
res = iterate(itr)
|
|
@assert res !== nothing
|
|
elt = DirectPowerElement(first(res), G)
|
|
return elt, (iterator = itr, state = last(res))
|
|
end
|
|
|
|
function Base.iterate(G::DirectPower, state)
|
|
itr, st = state.iterator, state.state
|
|
res = iterate(itr, st)
|
|
res === nothing && return nothing
|
|
elt = DirectPowerElement(first(res), G)
|
|
return elt, (iterator = itr, state = last(res))
|
|
end
|
|
|
|
function Base.IteratorSize(::Type{<:DirectPower{Gr,N}}) where {Gr,N}
|
|
Base.IteratorSize(Gr) isa Base.HasLength && return Base.HasShape{N}()
|
|
Base.IteratorSize(Gr) isa Base.HasShape && return Base.HasShape{N}()
|
|
return Base.IteratorSize(Gr)
|
|
end
|
|
|
|
Base.size(G::DirectPower) = ntuple(_ -> length(G.group), _nfold(G))
|
|
|
|
function GroupsCore.order(::Type{I}, G::DirectPower) where {I<:Integer}
|
|
return convert(I, order(I, G.group)^_nfold(G))
|
|
end
|
|
|
|
GroupsCore.ngens(G::DirectPower) = _nfold(G) * ngens(G.group)
|
|
|
|
function GroupsCore.gens(G::DirectPower, i::Integer)
|
|
k = ngens(G.group)
|
|
ci = CartesianIndices((k, _nfold(G)))
|
|
@boundscheck checkbounds(ci, i)
|
|
r, c = Tuple(ci[i])
|
|
tup = ntuple(j -> j == c ? gens(G.group, r) : one(G.group), _nfold(G))
|
|
return DirectPowerElement(tup, G)
|
|
end
|
|
|
|
function GroupsCore.gens(G::DirectPower)
|
|
N = _nfold(G)
|
|
S = gens(G.group)
|
|
tups = [ntuple(j -> (i == j ? s : one(s)), N) for i in 1:N for s in S]
|
|
|
|
return [DirectPowerElement(elts, G) for elts in tups]
|
|
end
|
|
|
|
Base.isfinite(G::DirectPower) = isfinite(G.group)
|
|
|
|
function Base.rand(
|
|
rng::Random.AbstractRNG,
|
|
rs::Random.SamplerTrivial{<:DirectPower},
|
|
)
|
|
G = rs[]
|
|
return DirectPowerElement(rand(rng, G.group, _nfold(G)), G)
|
|
end
|
|
|
|
GroupsCore.parent(g::DirectPowerElement) = g.parent
|
|
|
|
function Base.:(==)(g::DirectPowerElement, h::DirectPowerElement)
|
|
return (parent(g) === parent(h) && g.elts == h.elts)
|
|
end
|
|
|
|
Base.hash(g::DirectPowerElement, h::UInt) = hash(g.elts, hash(parent(g), h))
|
|
|
|
function Base.deepcopy_internal(g::DirectPowerElement, stackdict::IdDict)
|
|
return DirectPowerElement(
|
|
Base.deepcopy_internal(g.elts, stackdict),
|
|
parent(g),
|
|
)
|
|
end
|
|
|
|
Base.inv(g::DirectPowerElement) = DirectPowerElement(inv.(g.elts), parent(g))
|
|
|
|
function Base.:(*)(g::DirectPowerElement, h::DirectPowerElement)
|
|
@assert parent(g) === parent(h)
|
|
return DirectPowerElement(g.elts .* h.elts, parent(g))
|
|
end
|
|
|
|
function GroupsCore.order(::Type{I}, g::DirectPowerElement) where {I<:Integer}
|
|
return convert(I, reduce(lcm, (order(I, h) for h in g.elts); init = one(I)))
|
|
end
|
|
|
|
Base.isone(g::DirectPowerElement) = all(isone, g.elts)
|
|
|
|
function Base.show(io::IO, G::DirectPower)
|
|
n = _nfold(G)
|
|
nn = n == 1 ? "1-st" : n == 2 ? "2-nd" : n == 3 ? "3-rd" : "$n-th"
|
|
return print(io, "Direct $(nn) power of $(G.group)")
|
|
end
|
|
function Base.show(io::IO, g::DirectPowerElement)
|
|
return print(io, "( ", join(g.elts, ", "), " )")
|
|
end
|
|
|
|
# convienience:
|
|
Base.@propagate_inbounds function Base.getindex(
|
|
g::DirectPowerElement,
|
|
i::Integer,
|
|
)
|
|
return g.elts[i]
|
|
end
|