Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add letters function for PcGroupElem #4202

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
63 changes: 62 additions & 1 deletion src/Groups/pcgroup.jl
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,6 @@ function _GAP_collector_from_the_left(c::GAP_Collector)
return cGAP::GapObj
end


# Create the collector on the GAP side on demand
function underlying_gap_object(c::GAP_Collector)
if ! isdefined(c, :X)
Expand Down Expand Up @@ -365,3 +364,65 @@ function pc_group(c::GAP_Collector)
end
end

"""
letters(g::Union{PcGroupElem, SubPcGroupElem})

Return the letters of `g` as a list of integers, each entry corresponding to
a group generator.
Copy link
Member

@fingolfin fingolfin Nov 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we can also produce negative numbers: e.g. -3 means "inverse of 3rd generator". This should be explained, and perhaps an example added showing that. E.g. based on this:

julia> x = (gg[1]*gg[2]*gg[3])^-2
g1*g2^-2*g3^3

Perhaps also add something like this (and then mirror it in the other function)

See also [`syllables`](@ref).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a small example with some brief explanation to letters for this. However I am unsure if the example is good as I was not able to get elements with negative exponents and test.


# Examples
```jldoctest
julia> c = collector(2, Int);

julia> Oscar.set_relative_orders!(c, [2, 3])

julia> Oscar.set_conjugate!(c, 2, 1, [2 => 2])

julia> gg = pc_group(c)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The interface for construction collectors is quite advanced and currently not even fully documented, so using it for an example is maybe not optimal. I suggest to use the small groups library to get a suitable example group instead, i.e. here we can just do this:

Suggested change
julia> c = collector(2, Int);
julia> Oscar.set_relative_orders!(c, [2, 3])
julia> Oscar.set_conjugate!(c, 2, 1, [2 => 2])
julia> gg = pc_group(c)
julia> gg = small_group(6,1)

and then I think the rest of the example stays unchanged.

Same remark applies below.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect, no worries! I have now updated the examples with this replacement.

Pc group of order 6

julia> letters(gg[1]^5*gg[2]^-4)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example is not quite obvious for a reader. Better to show the intermediate result, that should make the connection to the output of letters "obvious" :-)

Suggested change
julia> letters(gg[1]^5*gg[2]^-4)
julia> x = gg[1]^5*gg[2]^-4
f1*f2^2
julia> letters(x)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea! I have updated the example in both syllables and letters to make this output clearer.

3-element Vector{Int64}:
1
2
2
```
"""
function letters(g::Union{PcGroupElem, SubPcGroupElem})
w = GAPWrap.UnderlyingElement(GapObj(g))
return Vector{Int}(GAPWrap.LetterRepAssocWord(w))
end

function syllables(g::Union{PcGroupElem, SubPcGroupElem})
l = GAPWrap.ExtRepOfObj(GapObj(g))
@assert iseven(length(l))
return Pair{Int, ZZRingElem}[l[i-1] => l[i] for i = 2:2:length(l)]
end

# Convert syllables in canonical form into exponent vector
#Thomas
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#Thomas

function _exponent_vector(sylls::Vector{Pair{Int64, ZZRingElem}}, n)
res = zeros(ZZRingElem, n)
for pair in sylls
@assert res[pair.first] == 0 #just to make sure
res[pair.first] = pair.second
end
return res
end

# Convert syllables in canonical form into group element
fingolfin marked this conversation as resolved.
Show resolved Hide resolved
#Thomas
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#Thomas

function (G::PcGroup)(sylls::Vector{Pair{Int64, ZZRingElem}}, check::Bool=true)
lgoettgens marked this conversation as resolved.
Show resolved Hide resolved
# check if the syllables are in canonical form
if check
indices = map(p -> p.first, sylls)
unq_indices = unique(indices) # maintains order
@req length(indices) == length(unq_indices) "given syllables have repeating generators"
@req issorted(unq_indices) "given syllables must be in ascending order"
lgoettgens marked this conversation as resolved.
Show resolved Hide resolved
end

e = _exponent_vector(sylls, ngens(G))
pcgs = Oscar.GAPWrap.FamilyPcgs(GapObj(G))
x = Oscar.GAPWrap.PcElementByExponentsNC(pcgs, GapObj(e, true))
return Oscar.group_element(G, x)
end
45 changes: 45 additions & 0 deletions test/Groups/pcgroup.jl
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,48 @@ end
@test GAP.Globals.IsMutable(cgg)
@test cgg !== c.X
end

@testset "generate letters from polycyclic group element" begin

# finite polycyclic groups
c = collector(2, Int);
set_relative_order!(c, 1, 2)
set_relative_order!(c, 2, 3)
set_power!(c, 1, [2 => 1])
gg = pc_group(c)
@test letters(gg[1]^5*gg[2]^-4) == [1, 2]
@test letters(gg[1]^5*gg[2]^4) == [1] # all positive exp
@test letters(gg[1]^-5*gg[2]^-7) == [1, 2, 2] # all negative exp
@test letters(gg[1]^2*gg[2]^3) == [2] # both identity elements

# finite polycyclic subgroup
gg = pc_group(symmetric_group(4))
G = derived_subgroup(gg)[1]
@test letters(G[1]^2) == [2, 2]
@test letters(G[1]^2*G[2]^3*G[3]^3) == [2, 2, 3, 4]
@test letters(G[1]^-2*G[2]^-3*G[3]^-3) == [2, 3, 4]
end

@testset "create polycyclic group element from syllables" begin

# finite polycyclic groups
c = collector(2, Int);
set_relative_order!(c, 1, 2)
set_relative_order!(c, 2, 3)
set_power!(c, 1, [2 => 1])
gg = pc_group(c)

element = gg[1]^5*gg[2]^-4
sylls = syllables(element)
@test sylls == [1 => ZZ(1), 2 => ZZ(1)] # check general usage
@test gg(sylls) == element # this will pass the check

sylls = [1 => ZZ(1), 2 => ZZ(2), 1 => ZZ(3)]
@test_throws ArgumentError gg(sylls) # repeating generators

sylls = [2 => ZZ(1), 1 => ZZ(2)]
@test_throws ArgumentError gg(sylls) # not in ascending order

sylls = [2 => ZZ(1), 1 => ZZ(2), 1 => ZZ(3)] # both conditions
@test_throws ArgumentError gg(sylls)
end
lgoettgens marked this conversation as resolved.
Show resolved Hide resolved
lgoettgens marked this conversation as resolved.
Show resolved Hide resolved