Skip to content

Commit

Permalink
make creation of the underlying gap object of a GroupDoubleCoset lazy
Browse files Browse the repository at this point in the history
  • Loading branch information
simonbrandhorst committed Jul 10, 2024
1 parent f500037 commit fbbc08a
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 43 deletions.
95 changes: 54 additions & 41 deletions src/Groups/cosets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -457,22 +457,42 @@ end
Group double coset.
Two double cosets are equal if, and only if, they contain the same elements.
"""
struct GroupDoubleCoset{T <: GAPGroup, S <: GAPGroupElem}
mutable struct GroupDoubleCoset{T <: GAPGroup, S <: GAPGroupElem}
# T=type of the group, S=type of the element
G::T
H::GAPGroup
K::GAPGroup
repr::S
X::GapObj
size

function GroupDoubleCoset(G::T, H::GAPGroup, K::GAPGroup, representative::S) where {T<: GAPGroup, S<:GAPGroupElem}
D = new{T, S}()
D.G = G
D.H = H
D.K = K
D.repr = representative
return D
end
end

GAP.julia_to_gap(obj::GroupDoubleCoset) = obj.X
function GAP.julia_to_gap(obj::GroupDoubleCoset)
if isdefined(obj,:X)
return obj.X
end
x = GapObj(representative(obj))
H = GapObj(obj.H)
K = GapObj(obj.K)
obj.X = GAP.Globals.DoubleCoset(H, x, K)
return obj.X
end

Base.hash(x::GroupDoubleCoset, h::UInt) = h # FIXME
Base.eltype(::Type{GroupDoubleCoset{T,S}}) where {T,S} = S

function ==(x::GroupDoubleCoset, y::GroupDoubleCoset)
return x.X == y.X
# TODO:can we avoid creation of a gap object here?
return GapObj(x) == GapObj(y)
end

function Base.show(io::IO, ::MIME"text/plain", x::GroupDoubleCoset)
Expand Down Expand Up @@ -526,9 +546,9 @@ Double coset of Sym(3)
"""
function double_coset(G::GAPGroup, g::GAPGroupElem, H::GAPGroup)
#T what if g is in some subgroup of a group of which G, H are also a subgroup?
@req GAPWrap.IsSubset(parent(g).X,G.X) "G is not a subgroup of parent(g)"
@req GAPWrap.IsSubset(parent(g).X,H.X) "H is not a subgroup of parent(g)"
return GroupDoubleCoset(parent(g),G,H,g,GAP.Globals.DoubleCoset(G.X,g.X,H.X))
@req GAPWrap.IsSubset(parent(g).X, G.X) "G is not a subgroup of parent(g)"
@req GAPWrap.IsSubset(parent(g).X, H.X) "H is not a subgroup of parent(g)"
return GroupDoubleCoset(parent(g), G, H, g)
end

Base.:*(H::GAPGroup, g::GAPGroupElem, K::GAPGroup) = double_coset(H,g,K)
Expand Down Expand Up @@ -558,49 +578,42 @@ julia> double_cosets(G,H,K)
```
"""
function double_cosets(G::T, H::GAPGroup, K::GAPGroup; check::Bool=true) where T <: GAPGroup
if !check
dcs = GAP.Globals.DoubleCosetsNC(G.X,H.X,K.X)
else
if check
@assert is_subset(H, G) "H is not a subgroup of G"
@assert is_subset(K, G) "K is not a subgroup of G"
dcs = GAP.Globals.DoubleCosets(G.X,H.X,K.X)
end
res = Vector{GroupDoubleCoset{T,elem_type(T)}}(undef, length(dcs))
for i = 1:length(res)
dc = dcs[i]
g = group_element(G, GAPWrap.Representative(dc))
res[i] = GroupDoubleCoset(G,H,K,g,dc)
dcs = GAP.Globals.DoubleCosetRepsAndSizes(G.X, H.X, K.X)
res = Vector{GroupDoubleCoset{T, elem_type(T)}}(undef, length(dcs))
for i in 1:length(res)
g = group_element(G, dcs[i][1])
C = GroupDoubleCoset(G, H, K, g)
n = dcs[i][2]
C.size = n
res[i] = C
end
return res
#return [GroupDoubleCoset(G,H,K,group_element(G.X,GAPWrap.Representative(dc)),dc) for dc in dcs]
end

raw"""
double_cosets_representatives_and_sizes(G::GAPGroup, H::GAPGroup, K::GAPGroup)
Return representatives of the double coset `H\G/K` and their size.
This function is faster and consumes less memory than [`double_cosets`](@ref)
since no double cosets are created and stored.
"""
function double_cosets_representatives_and_sizes(G::T, H::GAPGroup, K::GAPGroup) where T <: GAPGroup
dcs = GAP.Globals.DoubleCosetRepsAndSizes(G.X,H.X,K.X)
res = Vector{Tuple{elem_type(T), ZZRingElem}}(undef, length(dcs))
for i in 1:length(res)
g = group_element(G, dcs[i][1])
n = ZZ(dcs[i][2])
res[i] = (g,n)
end
return res
return res
end

"""
order(C::Union{GroupCoset,GroupDoubleCoset})
Return the cardinality of the (double) coset `C`.
"""
order(C::Union{GroupCoset,GroupDoubleCoset}) = GAPWrap.Size(C.X)
Base.length(C::Union{GroupCoset,GroupDoubleCoset}) = GAPWrap.Size(C.X)
order(C::Union{GroupCoset,GroupDoubleCoset})

function order(C::GroupCoset)
return GAPWrap.Size(GapObj(C))
end

function order(C::GroupDoubleCoset)
if isdefined(C, :size)
return C.size
end
C.size = GAPWrap.Size(GapObj(C))
return C.size
end

Base.length(C::Union{GroupCoset,GroupDoubleCoset}) = order(C)

"""
rand(rng::Random.AbstractRNG = Random.GLOBAL_RNG, C::Union{GroupCoset,GroupDoubleCoset})
Expand All @@ -611,7 +624,7 @@ using the random number generator `rng`.
Base.rand(C::Union{GroupCoset,GroupDoubleCoset}) = Base.rand(Random.GLOBAL_RNG, C)

function Base.rand(rng::Random.AbstractRNG, C::Union{GroupCoset,GroupDoubleCoset})
s = GAP.Globals.Random(GAP.wrap_rng(rng), C.X)
s = GAP.Globals.Random(GAP.wrap_rng(rng), GapObj(C))
return group_element(C.G, s)
end

Expand All @@ -638,7 +651,7 @@ right_acting_group(C::GroupDoubleCoset) = C.K

Base.IteratorSize(::Type{<:GroupDoubleCoset}) = Base.SizeUnknown()

Base.iterate(G::GroupDoubleCoset) = iterate(G, GAPWrap.Iterator(G.X))
Base.iterate(G::GroupDoubleCoset) = iterate(G, GAPWrap.Iterator(GapObj(G)))

function Base.iterate(G::GroupDoubleCoset, state)
GAPWrap.IsDoneIterator(state) && return nothing
Expand All @@ -658,7 +671,7 @@ function intersect(V::AbstractVector{Union{<: GAPGroup, GroupCoset, GroupDoubleC
else
G = V[1].G
end
l = GAP.Obj([v.X for v in V])
l = GAP.Obj([GapObj(v) for v in V])
ints = GAP.Globals.Intersection(l)
L = Vector{typeof(G)}(undef, length(ints))
for i in 1:length(ints)
Expand Down
2 changes: 0 additions & 2 deletions test/Groups/subgroups_and_cosets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,6 @@ end
@test Set(intersect(lc,H))==Set(H)
lc = left_coset(H,x)
@test intersect(lc,H)==[]
LL = double_cosets_representatives_and_sizes(G,H,K)
@test length(LL)==length(L)
end

@testset "Predicates for groups" begin
Expand Down

0 comments on commit fbbc08a

Please sign in to comment.