diff --git a/src/Groups/GAPGroups.jl b/src/Groups/GAPGroups.jl index 735fa85106d4..7621b3f79fdc 100644 --- a/src/Groups/GAPGroups.jl +++ b/src/Groups/GAPGroups.jl @@ -531,22 +531,45 @@ end # ################################################################################ -struct GAPGroupConjClass{T<:GAPGroup, S<:Union{GAPGroupElem,GAPGroup}} <: GroupConjClass{T, S} +@attributes mutable struct GAPGroupConjClass{T<:GAPGroup, S<:Union{GAPGroupElem,GAPGroup}} <: GroupConjClass{T, S} X::T repr::S CC::GapObj + + function GAPGroupConjClass(G::T, obj::S, C::GapObj) where T<:GAPGroup where S<:Union{GAPGroupElem, GAPGroup} + return new{T, S}(G, obj, C, Dict{Symbol,Any}()) + end end Base.eltype(::Type{GAPGroupConjClass{T,S}}) where {T,S} = S Base.hash(x::GAPGroupConjClass, h::UInt) = h # FIXME -function Base.show(io::IO, x::GAPGroupConjClass) - print(io, String(GAPWrap.StringViewObj(x.repr.X)), - " ^ ", - String(GAPWrap.StringViewObj(x.X.X))) +function Base.show(io::IO, ::MIME"text/plain", x::GAPGroupConjClass) + println(io, "Conjugacy class of") + io = pretty(io) + print(io, Indent()) + println(io, Lowercase(), x.repr, " in") + print(io, Lowercase(), x.X) + print(io, Dedent()) +end + +function Base.show(io::IO, x::GAPGroupConjClass{T, S}) where T where S + if get(io, :supercompact, false) + if S <: GAPGroupElem + print(io, "Conjugacy class of group elements") + else + print(io, "Conjugacy class of subgroups") + end + else + print(io, "Conjugacy class of ") + io = pretty(io) + print(IOContext(io, :supercompact => true), Lowercase(), x.repr, " in ", Lowercase(), x.X) + end end +action_function(C::GAPGroupConjClass) = ^ + ==(a::GAPGroupConjClass{T, S}, b::GAPGroupConjClass{T, S}) where S where T = a.CC == b.CC function Base.length(::Type{T}, C::GAPGroupConjClass) where T <: IntegerUnion @@ -554,6 +577,38 @@ function Base.length(::Type{T}, C::GAPGroupConjClass) where T <: IntegerUnion end Base.length(C::GroupConjClass) = length(ZZRingElem, C) +Base.lastindex(C::GroupConjClass) = length(C) + +Base.keys(C::GroupConjClass) = keys(1:length(C)) + +is_transitive(C::GroupConjClass) = true + +orbit(G::GAPGroup, g::T) where T<: Union{GAPGroupElem, GAPGroup} = conjugacy_class(G, g) + +orbits(C::GAPGroupConjClass) = [C] + +function permutation(C::GAPGroupConjClass, g::GAPGroupElem) + pi = GAP.Globals.Permutation(g.X, C.CC, GAP.Globals.OnPoints)::GapObj + sym = get_attribute!(C, :action_range) do + return symmetric_group(length(Int, C)) + end + return group_element(sym, pi) +end + +@attr GAPGroupHomomorphism{T, PermGroup} function action_homomorphism(C::GAPGroupConjClass{T, S}) where T where S + G = C.X + acthom = GAP.Globals.ActionHomomorphism(G.X, C.CC, GAP.Globals.OnPoints)::GapObj + + # See the comment about `SetJuliaData` in the `action_homomorphism` method + # for `GSetByElements`. + GAP.Globals.SetJuliaData(acthom, GAP.Obj([C, G])) + + sym = get_attribute!(C, :action_range) do + return symmetric_group(length(Int, C)) + end + return GAPGroupHomomorphism(G, sym, acthom) +end + """ representative(C::GroupConjClass) @@ -565,11 +620,12 @@ Return a representative of the conjugacy class `C`. julia> G = symmetric_group(4); julia> C = conjugacy_class(G, G([2, 1, 3, 4])) -(1,2) ^ Sym( [ 1 .. 4 ] ) +Conjugacy class of + (1,2) in + Sym(4) julia> representative(C) (1,2) - ``` """ representative(C::GroupConjClass) = C.repr @@ -584,11 +640,12 @@ Return the acting group of `C`. julia> G = symmetric_group(4); julia> C = conjugacy_class(G, G([2, 1, 3, 4])) -(1,2) ^ Sym( [ 1 .. 4 ] ) +Conjugacy class of + (1,2) in + Sym(4) julia> acting_group(C) === G true - ``` """ acting_group(C::GroupConjClass) = C.X @@ -605,8 +662,9 @@ Return the conjugacy class `cc` of `g` in `G`, where `g` = `representative`(`cc` julia> G = symmetric_group(4); julia> C = conjugacy_class(G, G([2, 1, 3, 4])) -(1,2) ^ Sym( [ 1 .. 4 ] ) - +Conjugacy class of + (1,2) in + Sym(4) ``` """ function conjugacy_class(G::GAPGroup, g::GAPGroupElem) @@ -621,6 +679,25 @@ function Base.rand(rng::Random.AbstractRNG, C::GAPGroupConjClass{S,T}) where S w return group_element(C.X, GAP.Globals.Random(GAP.wrap_rng(rng), C.CC)::GapObj) end +Base.in(g::GAPGroupElem, C::GAPGroupConjClass) = GapObj(g) in C.CC +Base.in(G::GAPGroup, C::GAPGroupConjClass) = GapObj(G) in C.CC + +Base.IteratorSize(::Type{<:GAPGroupConjClass}) = Base.SizeUnknown() + +Base.iterate(cc::GAPGroupConjClass) = iterate(cc, GAPWrap.Iterator(cc.CC)) + +function Base.iterate(cc::GAPGroupConjClass{S,T}, state::GapObj) where {S,T} + if GAPWrap.IsDoneIterator(state) + return nothing + end + i = GAPWrap.NextIterator(state)::GapObj + if T <: GAPGroupElem + return group_element(cc.X, i), state + else + return _as_subgroup(cc.X, i)[1], state + end +end + """ number_conjugacy_classes(G::GAPGroup) @@ -705,11 +782,10 @@ Sym(3) julia> conjugacy_classes_subgroups(G) 4-element Vector{GAPGroupConjClass{PermGroup, PermGroup}}: - Group(()) ^ Sym( [ 1 .. 3 ] ) - Group([ (2,3) ]) ^ Sym( [ 1 .. 3 ] ) - Group([ (1,2,3) ]) ^ Sym( [ 1 .. 3 ] ) - Group([ (1,2,3), (2,3) ]) ^ Sym( [ 1 .. 3 ] ) - + Conjugacy class of permutation group in Sym(3) + Conjugacy class of permutation group in Sym(3) + Conjugacy class of permutation group in Sym(3) + Conjugacy class of permutation group in Sym(3) ``` """ function conjugacy_classes_subgroups(G::GAPGroup) @@ -760,9 +836,8 @@ julia> G = symmetric_group(3); julia> conjugacy_classes_maximal_subgroups(G) 2-element Vector{GAPGroupConjClass{PermGroup, PermGroup}}: - Group([ (1,2,3) ]) ^ Sym( [ 1 .. 3 ] ) - Group([ (2,3) ]) ^ Sym( [ 1 .. 3 ] ) - + Conjugacy class of permutation group in Sym(3) + Conjugacy class of permutation group in Sym(3) ``` """ function conjugacy_classes_maximal_subgroups(G::GAPGroup) @@ -1009,23 +1084,6 @@ end # END subgroups conjugation -# START iterator -Base.IteratorSize(::Type{<:GAPGroupConjClass}) = Base.SizeUnknown() - -Base.iterate(cc::GAPGroupConjClass) = iterate(cc, GAPWrap.Iterator(cc.CC)) - -function Base.iterate(cc::GAPGroupConjClass{S,T}, state::GapObj) where {S,T} - if GAPWrap.IsDoneIterator(state) - return nothing - end - i = GAPWrap.NextIterator(state)::GapObj - if T <: GAPGroupElem - return group_element(cc.X, i), state - else - return _as_subgroup(cc.X, i)[1], state - end -end - ################################################################################ # # Normal Structure diff --git a/src/Groups/gsets.jl b/src/Groups/gsets.jl index 4af0dbdec4e6..85f60ba88df9 100644 --- a/src/Groups/gsets.jl +++ b/src/Groups/gsets.jl @@ -42,7 +42,7 @@ abstract type GSet{T} end function GSetByElements(G::T, fun::Function, seeds; closed::Bool = false) where T<:GAPGroup @assert ! isempty(seeds) Omega = new{T}(G, fun, seeds, Dict{Symbol,Any}()) - closed && set_attribute!(Omega, :elements => collect(seeds)) + closed && set_attribute!(Omega, :elements => unique!(collect(seeds))) return Omega end end diff --git a/test/Groups/conjugation.jl b/test/Groups/conjugation.jl index 872699c74417..8ee33ad3997b 100644 --- a/test/Groups/conjugation.jl +++ b/test/Groups/conjugation.jl @@ -116,6 +116,20 @@ end +@testset "Conjugacy classes as G-sets" begin + G = symmetric_group(4) + x = G(cperm([3, 4])) + y = G(cperm([1, 4, 2])) + C = conjugacy_class(G, x) + @test x in C + @test orbits(C) == [C] + @test C == orbit(G, x) + mp = action_homomorphism(C) + @test permutation(C, y) == mp(y) + @test length(C) == 6 + @test order(image(mp)[1]) == 24 +end + function TestConjCentr(G,x) Cx = centralizer(G,x)[1] cc = conjugacy_class(G,x)