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 stabilizer for G-sets #4206

Merged
merged 2 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/src/Groups/action.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,6 @@ orbits(Omega::T) where T <: GSetByElements{TG} where TG <: GAPGroup
## Stabilizers

```@docs
stabilizer(G::Oscar.GAPGroup, pnt::Any, actfun::Function)
stabilizer(G::GAPGroup, pnt::Any, actfun::Function)
stabilizer(Omega::GSet)
```
2 changes: 2 additions & 0 deletions src/GAP/wrappers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ GAP.@wrap EpimorphismSchurCover(x::GapObj)::GapObj
GAP.@wrap ExponentsOfPcElement(x::GapObj, y::GapObj)::GapObj
GAP.@wrap ExtRepOfObj(x::GapObj)::GapObj
GAP.@wrap ExtRepPolynomialRatFun(x::GapObj)::GapObj
GAP.@wrap FactorCosetAction(x::GapObj, y::GapObj)::GapObj
GAP.@wrap FamilyObj(x::GAP.Obj)::GapObj
GAP.@wrap FamilyPcgs(x::GAP.Obj)::GapObj
GAP.@wrap Field(x::Any)::GapObj
Expand Down Expand Up @@ -342,6 +343,7 @@ GAP.@wrap SizesCentralizers(x::GapObj)::GapObj
GAP.@wrap SizesConjugacyClasses(x::GapObj)::GapObj
GAP.@wrap Source(x::GapObj)::GapObj
GAP.@wrap Sqrt(x::Int64)::GAP.Obj
GAP.@wrap Stabilizer(v::GapObj, w::Any, x::GapObj, y::GapObj, z::GapObj)::GapObj
GAP.@wrap StringViewObj(x::Any)::GapObj
GAP.@wrap StructureConstantsTable(x::GapObj)::GapObj
GAP.@wrap StructureDescription(x::GapObj)::GapObj
Expand Down
43 changes: 22 additions & 21 deletions src/Groups/action.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
julia> m = g[1]
[ [ Z(3), 0*Z(3) ], [ 0*Z(3), Z(3)^0 ] ]

julia> v = m.X[1]
julia> v = GapObj(m)[1]
GAP: [ Z(3), 0*Z(3) ]

julia> v^m
Expand All @@ -32,9 +32,9 @@
```
"""

^(pnt::GAP.Obj, x::GAPGroupElem) = GAP.Globals.:^(pnt, x.X)
^(pnt::GAP.Obj, x::GAPGroupElem) = GAP.Globals.:^(pnt, GapObj(x))

Check warning on line 35 in src/Groups/action.jl

View check run for this annotation

Codecov / codecov/patch

src/Groups/action.jl#L35

Added line #L35 was not covered by tests

*(pnt::GAP.Obj, x::GAPGroupElem) = GAP.Globals.:*(pnt, x.X)
*(pnt::GAP.Obj, x::GAPGroupElem) = GAP.Globals.:*(pnt, GapObj(x))

Check warning on line 37 in src/Groups/action.jl

View check run for this annotation

Codecov / codecov/patch

src/Groups/action.jl#L37

Added line #L37 was not covered by tests


"""
Expand Down Expand Up @@ -72,7 +72,7 @@
(2, 3, 4)
```
"""
on_tuples(tuple::GapObj, x::GAPGroupElem) = GAPWrap.OnTuples(tuple, x.X)
on_tuples(tuple::GapObj, x::GAPGroupElem) = GAPWrap.OnTuples(tuple, GapObj(x))

on_tuples(tuple::Vector{T}, x::GAPGroupElem) where T = T[pnt^x for pnt in tuple]
^(tuple::Vector{T}, x::GAPGroupElem) where T = on_tuples(tuple, x)
Expand Down Expand Up @@ -124,7 +124,7 @@
2
```
"""
on_sets(set::GapObj, x::GAPGroupElem) = GAPWrap.OnSets(set, x.X)
on_sets(set::GapObj, x::GAPGroupElem) = GAPWrap.OnSets(set, GapObj(x))

function on_sets(set::Vector{T}, x::GAPGroupElem) where T
res = T[pnt^x for pnt in set]
Expand Down Expand Up @@ -188,7 +188,7 @@
true
```
"""
on_sets_sets(set::GapObj, x::GAPGroupElem) = GAPWrap.OnSetsSets(set, x.X)
on_sets_sets(set::GapObj, x::GAPGroupElem) = GAPWrap.OnSetsSets(set, GapObj(x))

function on_sets_sets(set::Vector{T}, x::GAPGroupElem) where T
res = T[on_sets(pnt, x) for pnt in set]
Expand Down Expand Up @@ -240,7 +240,7 @@
GAP: [ "c", "a", "b" ]
```
"""
permuted(pnt::GapObj, x::PermGroupElem) = GAPWrap.Permuted(pnt, x.X)
permuted(pnt::GapObj, x::PermGroupElem) = GAPWrap.Permuted(pnt, GapObj(x))

function permuted(pnt::Vector{T}, x::PermGroupElem) where T
invx = inv(x)
Expand Down Expand Up @@ -286,7 +286,7 @@
GAP: x_1*x_3+x_2*x_3
```
"""
on_indeterminates(f::GapObj, p::PermGroupElem) = GAPWrap.OnIndeterminates(f, p.X)
on_indeterminates(f::GapObj, p::PermGroupElem) = GAPWrap.OnIndeterminates(f, GapObj(p))

function on_indeterminates(f::MPolyRingElem, s::PermGroupElem)
G = parent(s)
Expand Down Expand Up @@ -349,7 +349,7 @@
n = nrows(p)
fam = GAPWrap.CoefficientsFamily(GAPWrap.FamilyObj(f))
indets = GapObj([GAPWrap.Indeterminate(fam, i) for i in 1:n])
return GAPWrap.Value(f, indets, p.X * indets)
return GAPWrap.Value(f, indets, GapObj(p) * indets)
end

function on_indeterminates(f::MPolyRingElem{T}, p::MatrixGroupElem{T}) where T
Expand Down Expand Up @@ -413,7 +413,7 @@
(1, 4)
```
"""
on_lines(line::GapObj, x::GAPGroupElem) = GAPWrap.OnLines(line, x.X)
on_lines(line::GapObj, x::GAPGroupElem) = GAPWrap.OnLines(line, GapObj(x))

Check warning on line 416 in src/Groups/action.jl

View check run for this annotation

Codecov / codecov/patch

src/Groups/action.jl#L416

Added line #L416 was not covered by tests

function on_lines(line::AbstractAlgebra.Generic.FreeModuleElem, x::GAPGroupElem)
res = line * x
Expand Down Expand Up @@ -448,17 +448,18 @@
```
"""
function on_subgroups(x::GapObj, g::GAPGroupElem)
return GAPWrap.Image(g.X, x)
return GAPWrap.Image(GapObj(g), x)
end

on_subgroups(x::T, g::GAPGroupElem) where T <: GAPGroup = T(on_subgroups(x.X, g))
on_subgroups(x::T, g::GAPGroupElem) where T <: GAPGroup = T(on_subgroups(GapObj(x), g))

@doc raw"""
stabilizer(G::Oscar.GAPGroup, pnt::Any[, actfun::Function])
stabilizer(G::GAPGroup, pnt::Any[, actfun::Function])

Return the subgroup of `G` that consists of all those elements `g`
that fix `pnt` under the action given by `actfun`,
that is, `actfun(pnt, g) == pnt` holds.
Return `S, emb` where `S` is the subgroup of `G` that consists of
all those elements `g` that fix `pnt` under the action given by `actfun`,
that is, `actfun(pnt, g) == pnt` holds,
and `emb` is the embedding of `S` into `G`.

The default for `actfun` depends on the types of `G` and `pnt`:
If `G` is a `PermGroup` then the default actions on integers,
Expand All @@ -485,10 +486,10 @@
4
```
"""
function stabilizer(G::Oscar.GAPGroup, pnt::Any, actfun::Function)
return Oscar._as_subgroup(G, GAP.Globals.Stabilizer(G.X, pnt,
GapObj([x.X for x in gens(G)]), GapObj(gens(G)),
GAP.WrapJuliaFunc(actfun))::GapObj)
function stabilizer(G::GAPGroup, pnt::Any, actfun::Function)
return Oscar._as_subgroup(G, GAPWrap.Stabilizer(GapObj(G), pnt,
GapObj(gens(G), recursive = true), GapObj(gens(G)),
GapObj(actfun)))
end

# natural stabilizers in permutation groups
Expand Down Expand Up @@ -529,7 +530,7 @@
"""
function right_coset_action(G::GAPGroup, U::GAPGroup)
_check_compatible(G, U)
mp = GAP.Globals.FactorCosetAction(G.X, U.X)
mp = GAPWrap.FactorCosetAction(GapObj(G), GapObj(U))
@req mp !== GAP.Globals.fail "Invalid input"
H = PermGroup(GAPWrap.Range(mp))
return GAPGroupHomomorphism(G, H, mp)
Expand Down
30 changes: 29 additions & 1 deletion src/Groups/gsets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import Hecke.orbit


"""
GSetByElements{T,S} <: GSet{T}
GSetByElements{T,S} <: GSet{T,S}

Objects of this type represent G-sets that are willing to write down
orbits and elements lists as vectors.
Expand Down Expand Up @@ -442,6 +442,34 @@ julia> map(length, orbs)
@attr Vector{GSetByElements{PermGroup, Int}} orbits(G::PermGroup) = orbits(gset(G))


"""
stabilizer(Omega::GSet{T,S})
stabilizer(Omega::GSet{T,S}, omega::S = representative(Omega); check::Bool = true) where {T,S}

Return the subgroup of `G = acting_group(Omega)` that fixes `omega`,
together with the embedding of this subgroup into `G`.
If `check` is `false` then it is not checked whether `omega` is in `Omega`.

# Examples
```jldoctest
julia> Omega = gset(symmetric_group(3));

julia> stabilizer(Omega)
(Permutation group of degree 3 and order 2, Hom: permutation group -> Sym(3))
```
"""
@attr Tuple{sub_type(T), Map{sub_type(T), T}} function stabilizer(Omega::GSet{T,S}) where {T,S}
return stabilizer(Omega, representative(Omega), check = false)
end

function stabilizer(Omega::GSet{T,S}, omega::S; check::Bool = true) where {T,S}
check && @req omega in Omega "omega must be an element of Omega"
G = acting_group(Omega)
gfun = action_function(Omega)
return stabilizer(G, omega, gfun)
end


#############################################################################
##
## `:elements` a vector of points;
Expand Down
33 changes: 31 additions & 2 deletions test/Groups/gsets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
@test ! is_regular(Omega)
@test ! is_semiregular(Omega)
@test collect(Omega) == 1:6 # ordering is kept
@test order(stabilizer(Omega)[1]) * length(Omega) == order(G)

Omega = gset(G, [Set([1, 2])]) # action on unordered pairs
@test isa(Omega, GSet)
@test length(Omega) == 15
@test order(stabilizer(Omega)[1]) * length(Omega) == order(G)
@test length(orbits(Omega)) == 1
@test is_transitive(Omega)
@test ! is_regular(Omega)
Expand All @@ -23,6 +25,7 @@
Omega = gset(G, [[1, 2]]) # action on ordered pairs
@test isa(Omega, GSet)
@test length(Omega) == 30
@test order(stabilizer(Omega)[1]) * length(Omega) == order(G)
@test length(orbits(Omega)) == 1
@test is_transitive(Omega)
@test ! is_regular(Omega)
Expand All @@ -31,15 +34,18 @@
Omega = gset(G, [(1, 2)]) # action on ordered pairs (repres. by tuples)
@test isa(Omega, GSet)
@test length(Omega) == 30
@test order(stabilizer(Omega)[1]) * length(Omega) == order(G)
@test length(orbits(Omega)) == 1
@test is_transitive(Omega)
@test ! is_regular(Omega)
@test ! is_semiregular(Omega)

# constructions by explicit action functions
Omega = gset(G, permuted, [[0,1,0,1,0,1], [1,2,3,4,5,6]])
omega = [0,1,0,1,0,1]
Omega = gset(G, permuted, [omega, [1,2,3,4,5,6]])
@test isa(Omega, GSet)
@test length(Omega) == 740
@test order(stabilizer(Omega, omega)[1]) * length(orbit(Omega, omega)) == order(G)
@test length(orbits(Omega)) == 2
@test ! is_transitive(Omega)
@test ! is_regular(Omega)
Expand All @@ -52,6 +58,7 @@
@test isa(Omega, GSet)
@test length(Omega) == 3
@test length(orbits(Omega)) == 1
@test order(stabilizer(Omega)[1]) * length(orbit(Omega, f)) == order(G)
@test is_transitive(Omega)
@test ! is_regular(Omega)
@test ! is_semiregular(Omega)
Expand Down Expand Up @@ -141,6 +148,14 @@
rep = is_conjugate_with_data(Omega, [0,1,0,1,0,1], [1,2,3,4,5,6])
@test ! rep[1]

# stabilizer
G = symmetric_group(6)
Omega = gset(G, permuted, [[0,1,0,1,0,1], [1,2,3,4,5,6]])
@test_throws ArgumentError stabilizer(Omega, [0,0,0,0,0,0])
omega = representative(Omega)
@test stabilizer(Omega) == stabilizer(Omega, omega)
@test stabilizer(Omega) !== stabilizer(Omega, omega)
@test stabilizer(Omega) === stabilizer(Omega)
end

@testset "natural action of permutation groups" begin
Expand Down Expand Up @@ -210,18 +225,21 @@ end
# natural constructions (determined by the types of the seeds)
G = general_linear_group(2, 3)
V = free_module(base_ring(G), degree(G))
v = gen(V, 1)
Omega = gset(G)
@test isa(Omega, GSet)
@test length(Omega) == 9
@test order(stabilizer(Omega, v)[1]) * length(orbit(Omega, v)) == order(G)
@test length(orbits(Omega)) == 2
@test ! is_transitive(Omega)
@test ! is_regular(Omega)
@test ! is_semiregular(Omega)
@test collect(Omega) == collect(V) # ordering is kept

Omega = orbit(G, gen(V, 1))
Omega = orbit(G, v)
@test isa(Omega, GSet)
@test length(Omega) == 8
@test order(stabilizer(Omega, v)[1]) * length(Omega) == order(G)
@test length(orbits(Omega)) == 1
@test is_transitive(Omega)
@test ! is_regular(Omega)
Expand All @@ -230,6 +248,7 @@ end
Omega = gset(G, [Set(gens(V))]) # action on unordered pairs of vectors
@test isa(Omega, GSet)
@test length(Omega) == 24
@test order(stabilizer(Omega)[1]) * length(Omega) == order(G)
@test length(orbits(Omega)) == 1
@test is_transitive(Omega)
@test ! is_regular(Omega)
Expand All @@ -238,6 +257,7 @@ end
Omega = gset(G, [gens(V)]) # action on ordered pairs of vectors
@test isa(Omega, GSet)
@test length(Omega) == 48
@test order(stabilizer(Omega)[1]) * length(Omega) == order(G)
@test length(orbits(Omega)) == 1
@test is_transitive(Omega)
@test is_regular(Omega)
Expand Down Expand Up @@ -325,6 +345,7 @@ end
@test isa(Omega, GSet)
@test acting_group(Omega) == G
@test length(Omega) == index(G, H)
@test order(stabilizer(Omega)[1]) * length(Omega) == order(G)
@test Omega[end] == Omega[length(Omega)]
@test length(orbits(Omega)) == 1
@test is_transitive(Omega)
Expand Down Expand Up @@ -386,6 +407,7 @@ end
@test isa(Omega, GSet)
@test acting_group(Omega) == G
@test length(Omega) == index(G, H)
@test order(stabilizer(Omega)[1]) * length(Omega) == order(G)
@test Omega[end] == Omega[length(Omega)]
@test length(orbits(Omega)) == 1
@test is_transitive(Omega)
Expand Down Expand Up @@ -439,6 +461,13 @@ end
@test Oscar.action_function(Omega)(x, rep[2]) == y
end

@testset "G-sets of PcGroups" begin
G = small_group(24, 12)
Omega = orbit(G, gen(G, 1))
S, mp = stabilizer(Omega)
@test length(Omega) == index(G, S)
end

@testset "G-sets of FinGenAbGroups" begin
# Define an action on class functions.
function galois_conjugate(chi::Oscar.GAPGroupClassFunction,
Expand Down
Loading