Skip to content

Commit

Permalink
address comments
Browse files Browse the repository at this point in the history
- provide `all_table_of_marks_names` for computing admissible names
  of tables of marks from the library,
  analogous to (and based on) `all_character_table_names`;
  this is something which GAP does not offer

- improve the documentation of admissible names for character tables,
  refer to this documentation when talking about admissible names for
  tables of marks

- add `is_table_of_marks_name` and `is_character_table_name`

- change the setup for names of tables of marks from the library:
  Use always the name of the corresponding library character table.
  For that, turn `identifier` for tables of marks into an attribute,
  and provide auxiliary functions for translating between the `Identifier`
  values for character tables and tables of marks on the GAP side.
  • Loading branch information
ThomasBreuer committed Jul 11, 2024
1 parent fae5a4f commit 1986b25
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 39 deletions.
1 change: 1 addition & 0 deletions docs/src/Groups/group_characters.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ characteristic(tbl::GAPGroupCharacterTable)
Base.mod(tbl::GAPGroupCharacterTable, p::Int)
quo(tbl::GAPGroupCharacterTable, nclasses::Vector{Int})
all_character_table_names
is_character_table_name
```

## Attributes of group characters
Expand Down
7 changes: 7 additions & 0 deletions docs/src/Groups/tom.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,20 @@ These tables of marks can be fetched via the names of these groups,
which coincide with the names of the character tables of these groups
in the Character Table Library, see [`table_of_marks(id::String)`](@ref).

Like the library of character tables, the library of tables of marks
can be used similar to group libraries (see [Group libraries](@ref))
in the sense that [`all_table_of_marks_names`](@ref) returns descriptions
of all those available tables of marks that have certain properties.

## Construct tables of marks

```@docs
GAPGroupTableOfMarks
table_of_marks(G::Union{GAPGroup, FinGenAbGroup})
table_of_marks(id::String)
Base.show(io::IO, ::MIME"text/plain", tom::GAPGroupTableOfMarks)
all_table_of_marks_names
is_table_of_marks_name
```

## Attributes and operations for tables of marks
Expand Down
2 changes: 2 additions & 0 deletions src/GAP/wrappers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ GAP.@wrap HasMaxes(x::GapObj)::Bool
GAP.@wrap HasMaximalAbelianQuotient(x::Any)::Bool
GAP.@wrap HasSize(x::Any)::Bool
GAP.@wrap Hasfhmethsel(x::GapObj)::Bool
GAP.@wrap Identifier(x::GapObj)::GapObj
GAP.@wrap Identity(x::GapObj)::GapObj
GAP.@wrap Image(x::Any)::GapObj
GAP.@wrap Image(x::Any, y::Any)::GapObj
Expand Down Expand Up @@ -247,6 +248,7 @@ GAP.@wrap IsSyllableAssocWordRep(x::Any)::Bool
GAP.@wrap IsSyllableWordsFamily(x::Any)::Bool
GAP.@wrap IsSymmetricForm(x::Any)::Bool
GAP.@wrap IsSymmetricGroup(x::Any)::Bool
GAP.@wrap IsTableOfMarks(x::Any)::Bool
GAP.@wrap IsTransitive(x::Any)::Bool
GAP.@wrap IsTransitive(x::Any, y::Any)::Bool
GAP.@wrap IsTrivial(x::Any)::Bool
Expand Down
34 changes: 32 additions & 2 deletions src/Groups/group_characters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,17 @@ julia> println(character_table("A5", 2))
julia> println(character_table("J5"))
nothing
```
Several names can be admissible for the same character table from the library.
For example, the alternating group on five points is isomorphic to the
projective special linear groups in dimension 2 over the fields with
four or five elements, and each of the strings `"A5"`, `"L2(4)"`, `"L2(5)"`
is an admissible name for its library character table.
The names are not case sensitive, thus also `"a5"` is admissible.
Use [`all_character_table_names`](@ref) for creating a vector that contains
one admissible name for each available character table,
perhaps filtered by some conditions.
"""
function character_table(id::String, p::Int = 0)
if p != 0
Expand Down Expand Up @@ -461,8 +472,9 @@ true
"""
all_character_table_names(L...; ordered_by = nothing)
Return an vector of strings that contains all those names of character tables
in the character table library that satisfy the conditions in the vector `L`.
Return a vector of strings that contains an admissible name of each
character table in the character table library that satisfies the conditions
in the vector `L`.
# Examples
```
Expand Down Expand Up @@ -495,6 +507,24 @@ function all_character_table_names(L...; ordered_by = nothing)
end


"""
is_character_table_name(name::String)
Return `true` if `character_table(name)` returns a character table,
and `false` otherwise
# Examples
```jldoctest
julia> is_character_table_name("J1")
true
julia> is_character_table_name("J5")
false
```
"""
is_character_table_name(name::String) = GAPWrap.LibInfoCharacterTable(GapObj(name)) !== GAP.Globals.fail


##############################################################################
#
# `print` and `show` character tables
Expand Down
152 changes: 116 additions & 36 deletions src/Groups/tom.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,46 @@ Objects of type `GAPGroupTableOfMarks` support [`get_attribute`](@ref).
isomorphism::Map # isomorphism from `group` to a group in GAP

function GAPGroupTableOfMarks(G::Union{GAPGroup, FinGenAbGroup}, tom::GapObj, iso::Map)
@req GAPWrap.IsTableOfMarks(tom) "tom must be a GAP table of marks"
return new(tom, G, iso)
end

function GAPGroupTableOfMarks(tom::GapObj)
# group and isomorphism are left undefined
@req GAPWrap.IsTableOfMarks(tom) "tom must be a GAP table of marks"
return new(tom)
end
end


# If `tblid` is an admissible name for a library character table
# then translate it to the GAP name of the corresponding
# library table of marks if there is one.
function _table_of_marks_name_in_GAP(tblid::String)
info = GAPWrap.LibInfoCharacterTable(GapObj(tblid))
info === GAP.Globals.fail && return false, ""

tblid = string(info.firstName::GapObj)
info = GAP.Globals.LIBLIST.TOM_TBL_INFO::GapObj
pos = findfirst(isequal(GapObj(lowercase(tblid))), Vector{GapObj}(info[2]))
pos === nothing && return false, ""

return true, string(info[1][pos]::GapObj)
end

# If `tomid` is the GAP name for a library table of marks
# then translate it to the GAP name of the corresponding
# library character table.
# (There is always such a character table.)
function _character_table_name_in_GAP(tomid::String)
info = GAP.Globals.LIBLIST.TOM_TBL_INFO
pos = findfirst(isequal(GapObj(lowercase(tomid))), Vector{GapObj}(info[1]))
pos === nothing && return false, ""
info = GAPWrap.LibInfoCharacterTable(info[2][pos])
return true, string(info.firstName)
end


# access to field values via functions
GapObj(tom::GAPGroupTableOfMarks) = tom.GAPTable

Expand Down Expand Up @@ -69,12 +100,10 @@ Table of marks of Sym(3)
4: 1 1 1 1
```
"""
function table_of_marks(G::Union{GAPGroup, FinGenAbGroup})
return get_attribute!(G, :table_of_marks) do
iso = isomorphism_to_GAP_group(G)
gaptom = GAPWrap.TableOfMarks(codomain(iso))
return GAPGroupTableOfMarks(G, gaptom, iso)
end
@attr GAPGroupTableOfMarks function table_of_marks(G::Union{GAPGroup, FinGenAbGroup})
iso = isomorphism_to_GAP_group(G)
gaptom = GAPWrap.TableOfMarks(codomain(iso))
return GAPGroupTableOfMarks(G, gaptom, iso)
end

# A table of marks constructed from a group is stored in this group.
Expand All @@ -101,24 +130,77 @@ nothing
```
"""
function table_of_marks(id::String)
# normalize `id`
info = GAPWrap.LibInfoCharacterTable(GapObj(id))
if info !== GAP.Globals.fail
id = string(info.firstName)
end
return get!(tables_of_marks_by_id, id) do
tom = GAPWrap.TableOfMarks(GapObj(id))
tom === GAP.Globals.fail && return nothing
flag, tomid =_table_of_marks_name_in_GAP(id)
flag || return nothing
return get!(tables_of_marks_by_id, tomid) do
tom = GAPWrap.TableOfMarks(GapObj(tomid))
@assert tom !== GAP.Globals.fail "no table of marks with name $tomid?"
if GAP.Globals.HasUnderlyingGroup(tom)
G = _oscar_group(GAPWrap.UnderlyingGroup(tom))
iso = isomorphism_to_GAP_group(G)
return GAPGroupTableOfMarks(G, tom, iso)
else
return GAPGroupTableOfMarks(tom)
end
end
end::GAPGroupTableOfMarks
end

"""
all_table_of_marks_names(L...; ordered_by = nothing)
Return a vector of strings that contains an admissible name of each
table of marks in the library of tables of marks that satisfies the
conditions in the vector `L`.
The supported conditions in `L` are the same as for
[`all_character_table_names`](@ref),
and the returned vector contains the subset of those names returned by
`all_character_table_names` with the same input for which a table of marks
is available in the library.
# Examples
```
julia> spor_names = all_table_of_marks_names(is_sporadic_simple => true);
julia> println(spor_names[1:5])
["Co3", "HS", "He", "J1", "J2"]
julia> spor_names = all_table_of_marks_names(is_sporadic_simple;
ordered_by = order);
julia> println(spor_names[1:5])
["M11", "M12", "J1", "M22", "J2"]
julia> length(all_table_of_marks_names(number_of_conjugacy_classes => 5))
4
```
"""
function all_table_of_marks_names(L...; ordered_by = nothing)
names = all_character_table_names(L...; ordered_by = ordered_by)
return filter(x -> _table_of_marks_name_in_GAP(x)[1], names)
end
#TODO: As soon as the character table library provides an *a priori*
# filtering of names for which a table of marks is available,
# use this instead of filtering afterwards.


"""
is_table_of_marks_name(name::String)
Return `true` if `table_of_marks(name)` returns a table of marks,
and `false` otherwise
# Examples
```jldoctest
julia> is_table_of_marks_name("J1")
true
julia> is_table_of_marks_name("J4")
false
```
"""
is_table_of_marks_name(name::String) = _table_of_marks_name_in_GAP(name)[1]


# For tables of marks with stored group, we take the hash value of the group.
# For tables of marks without stored group, we take the table identifier.
Expand Down Expand Up @@ -305,11 +387,20 @@ julia> identifier(table_of_marks("A5"))
julia> identifier(table_of_marks(symmetric_group(3)))
""
!!! warning "Note:"
The `identifier` of a table of marks from the library is equal to
the `identifier` of the corresponding library character table.
In a few cases, this value differs from the `GAP.Globals.Identifier`
value of the underlying `GapObj` of the table of marks.
```
"""
function identifier(tom::GAPGroupTableOfMarks)
GAP.Globals.HasIdentifier(GapObj(tom)) || return ""
return string(GAP.Globals.Identifier(GapObj(tom)))
@attr String function identifier(tom::GAPGroupTableOfMarks)
gaptom = GapObj(tom)
GAPWrap.IsLibTomRep(gaptom) || return ""
flag, id = _character_table_name_in_GAP(string(GAPWrap.Identifier(gaptom)))
@assert flag "no character table for GAP table of marks?"
return id
end


Expand Down Expand Up @@ -535,18 +626,10 @@ julia> character_table(tom) == character_table(g)
true
```
"""
function character_table(tom::GAPGroupTableOfMarks)
tbl = get_attribute!(tom, :character_table) do
if GAPWrap.IsLibTomRep(GapObj(tom))
info = GAP.Globals.LIBLIST.TOM_TBL_INFO
pos = findfirst(isequal(GapObj(lowercase(identifier(tom)))), Vector{GapObj}(info[1]))
pos !== GAP.Globals.fail && return character_table(string(info[2][pos]))
end
return character_table(group(tom))
end

@attr GAPGroupCharacterTable function character_table(tom::GAPGroupTableOfMarks)
GAPWrap.IsLibTomRep(GapObj(tom)) && return character_table(identifier(tom))
tbl = character_table(group(tom))
set_attribute!(tbl, :table_of_marks, tom)

return tbl
end

Expand All @@ -566,14 +649,11 @@ julia> table_of_marks(tbl) == table_of_marks(g)
true
```
"""
function table_of_marks(tbl::GAPGroupCharacterTable)
tom = get_attribute!(tbl, :table_of_marks) do
isdefined(tbl, :group) && return table_of_marks(group(tbl))
return table_of_marks(identifier(tbl))
end

@attr Union{Nothing, GAPGroupTableOfMarks} function table_of_marks(tbl::GAPGroupCharacterTable)
isdefined(tbl, :group) && return table_of_marks(group(tbl))
tom = table_of_marks(identifier(tbl))
tom === nothing && return nothing
set_attribute!(tom, :character_table, tbl)

return tom
end

Expand Down
3 changes: 3 additions & 0 deletions src/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ export all_perfect_groups
export all_primitive_groups
export all_small_groups
export all_subsets_matroid
export all_table_of_marks_names
export all_transitive_groups
export all_triangulations
export allow_unicode
Expand Down Expand Up @@ -745,6 +746,7 @@ export is_canonically_isomorphic
export is_canonically_isomorphic_with_map
export is_cartier
export is_cellular
export is_character_table_name
export is_characteristic_subgroup
export is_closed_embedding
export is_clutter
Expand Down Expand Up @@ -873,6 +875,7 @@ export is_subscheme
export is_subset
export is_supersolvable, has_is_supersolvable, set_is_supersolvable
export is_surjective
export is_table_of_marks_name
export is_ternary
export is_total
export is_transitive
Expand Down
2 changes: 1 addition & 1 deletion test/Groups/tom.jl
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ Test the case where a group has a custom name where the first character
should not be turned into lowercase
```jldoctest tables_of_marks.test
julia> table_of_marks(SL(2,2))
SL(2,2)
Table of marks of SL(2,2)
1: 6
2: 3 1
Expand Down

0 comments on commit 1986b25

Please sign in to comment.