Skip to content

Commit

Permalink
Merge pull request #71 from kalmarek/mk/reorganization
Browse files Browse the repository at this point in the history
Reorganization
  • Loading branch information
Marek Kaluba authored Nov 29, 2023
2 parents 3a18e8d + 3366fb2 commit 38d35ee
Show file tree
Hide file tree
Showing 10 changed files with 433 additions and 448 deletions.
2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ GroupsCore = "d5909c97-4eac-4ecc-a3dc-fdd0858a4120"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
PermutationGroups = "8bc5a954-2dfc-11e9-10e6-cd969bffa420"
PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
Primes = "27ebfcd6-29c5-5fa9-bf4b-fb8fc14df3ae"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
StarAlgebras = "0c0c59c1-dc5f-42e9-9a8b-b5dc384a6cd1"
Expand All @@ -18,6 +19,7 @@ Cyclotomics = "0.3"
GroupsCore = "0.4"
PermutationGroups = "0.4.2"
PrecompileTools = "1"
PrettyTables = "2"
Primes = "0.4, 0.5"
StarAlgebras = "0.2"
julia = "1.6"
Expand Down
3 changes: 3 additions & 0 deletions src/Characters/Characters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,8 @@ include("cmmatrix.jl")
include("powermap.jl")
include("character_tables.jl")
include("class_functions.jl")
include("chars.jl")
include("io.jl")

include("dixon.jl")
end
83 changes: 0 additions & 83 deletions src/Characters/character_tables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -162,86 +162,3 @@ function normalize!(chtbl::CharacterTable{<:Group,<:FiniteFields.GF})
end
return chtbl
end

## "fancy" io

function Base.show(io::IO, ::MIME"text/plain", chtbl::CharacterTable)
println(io, "Character table of ", parent(chtbl), " over $(eltype(chtbl))")

if !(get(io, :limit, false)::Bool)
screenheight = screenwidth = typemax(Int)
else
sz = displaysize(io)::Tuple{Int,Int}
screenheight, screenwidth = sz[1] - 4, sz[2]
end

nirr = nirreps(chtbl)
nccl = nconjugacy_classes(chtbl)
pre_width = 1 + length(string(nirr))
sep = ""

if nirr > screenheight - 1
rows_to_print = [1:screenheight-2; nirr]
else
rows_to_print = [1:nirr;]
end

maxpossiblecols = div(screenwidth - pre_width - 3, 3)
if nccl > maxpossiblecols
cols_to_print = [1:maxpossiblecols-1; nccl]
else
cols_to_print = [1:nccl;]
end

A = Base.alignment(
io,
chtbl.values,
rows_to_print,
cols_to_print,
screenwidth,
screenwidth,
2,
)

hellipsis = nccl > length(A) ? "" : ""

print(io, " "^(pre_width), " ")
Base.print_matrix_row(
io,
reshape(cols_to_print, (1, length(cols_to_print))),
A,
1,
cols_to_print,
" ",
)

println(io, hellipsis)
println(
io,
""^pre_width,
"─┬─",
""^(sum(sum, A) + length(A) - 1),
hellipsis,
)

if nirr > screenheight - 1
for i in 1:screenheight-2
print(io, rpad("χ$(FiniteFields.subscriptify(i))", pre_width), sep)
Base.print_matrix_row(io, chtbl.values, A, i, cols_to_print, " ")
println(io, hellipsis)
end
print(io, "", " "^(pre_width - 2), sep)
Base.print_matrix_vdots(io, "", A, " ", 2, 1, false)
println(io)

print(io, rpad("χ$(FiniteFields.subscriptify(nirr))", pre_width), sep)
Base.print_matrix_row(io, chtbl.values, A, nirr, cols_to_print, " ")
print(io, hellipsis)
else
for i in 1:nirr
print(io, rpad("χ$(FiniteFields.subscriptify(i))", pre_width), sep)
Base.print_matrix_row(io, chtbl.values, A, i, cols_to_print, " ")
i != nirr && println(io, hellipsis)
end
end
end
217 changes: 217 additions & 0 deletions src/Characters/chars.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
"""
Character <: AbstractClassFunction
Struct representing (possibly virtual) character of a group.
Characters are backed by `table(χ)::CharacterTable` which actually stores the
character values. The multiplicities (decomposition into the irreducible
summands) of a given character can be obtained by calling `multiplicities(χ)`
which returns a vector of coefficients of `χ` in the basis of
`irreducible_characters(table(χ))`.
It is assumed that equal class functions on the same group will have
**identical** (ie. `===`) character tables.
"""
struct Character{T,S,ChT<:CharacterTable} <: AbstractClassFunction{T}
table::ChT
multips::Vector{S}
end

function Character{R}(
chtbl::CharacterTable{Gr,T},
multips::AbstractVector{S},
) where {R,Gr,T,S}
return Character{R,S,typeof(chtbl)}(chtbl, multips)
end

function Character(chtbl::CharacterTable, multips::AbstractVector)
R = Base._return_type(*, Tuple{eltype(chtbl),eltype(multips)})
@assert R Any
return Character{R}(chtbl, multips)
end

function Character(chtbl::CharacterTable, i::Integer)
return Character{eltype(chtbl)}(chtbl, i)
end

function Character{T}(chtbl::CharacterTable, i::Integer) where {T}
v = zeros(Int, nconjugacy_classes(chtbl))
v[i] = 1
return Character{T,Int,typeof(chtbl)}(chtbl, v)
end

function Character{T}::Character) where {T}
S = eltype(multiplicities(χ))
ChT = typeof(table(χ))
return Character{T,S,ChT}(table(χ), multiplicities(χ))
end

## Accessors
table::Character) = χ.table
multiplicities::Character) = χ.multips

## AbstractClassFunction api
Base.parent::Character) = parent(table(χ))
conjugacy_classes::Character) = conjugacy_classes(table(χ))
function Base.values::Character{T}) where {T}
return T[χ[i] for i in 1:nconjugacy_classes(table(χ))]
end

Base.@propagate_inbounds function Base.getindex(
χ::Character{T},
i::Integer,
) where {T}
i = i < 0 ? table(χ).inv_of[abs(i)] : i
@boundscheck 1 i nconjugacy_classes(table(χ))

return convert(
T,
sum(
c * table(χ)[idx, i] for
(idx, c) in enumerate(multiplicities(χ)) if !iszero(c);
init = zero(T),
),
)
end

## Basic functionality

function Base.:(==)(χ::Character, ψ::Character)
return table(χ) === table(ψ) && multiplicities(χ) == multiplicities(ψ)
end
Base.hash::Character, h::UInt) = hash(table(χ), hash(multiplicities(χ), h))

function Base.deepcopy_internal::Character{T}, d::IdDict) where {T}
haskey(d, χ) && return d[χ]
return Character{T}(table(χ), copy(multiplicities(χ)))
end

## Character arithmetic

for f in (:+, :-)
@eval begin
function Base.$f::Character, ψ::Character)
@assert table(χ) === table(ψ)
return Character(table(χ), $f(multiplicities(χ), multiplicities(ψ)))
end
end
end

Base.:*::Character, c::Number) = Character(table(χ), c .* multiplicities(χ))
Base.:*(c::Number, χ::Character) = χ * c
Base.:/::Character, c::Number) = Character(table(χ), multiplicities(χ) ./ c)

Base.zero::Character) = 0 * χ

function __decompose(T::Type, values::AbstractVector, tbl::CharacterTable)
ψ = ClassFunction(values, conjugacy_classes(tbl), tbl.inv_of)
return decompose(T, ψ, tbl)
end

function decompose(cfun::AbstractClassFunction, tbl::CharacterTable)
return decompose(eltype(cfun), cfun, tbl)
end

function decompose(T::Type, cfun::AbstractClassFunction, tbl::CharacterTable)
vals = Vector{T}(undef, length(conjugacy_classes(tbl)))
return decompose!(vals, cfun, tbl)
end

function decompose!(
vals::AbstractVector,
cfun::AbstractClassFunction,
tbl::CharacterTable,
)
@assert length(vals) == length(conjugacy_classes(tbl))
@assert conjugacy_classes(tbl) === conjugacy_classes(cfun)

for (i, idx) in enumerate(eachindex(vals))
χ = Character(tbl, i)
vals[idx] = dot(χ, cfun)
end
return vals
end

function Base.:*::Character, ψ::Character)
@assert table(χ) == table(ψ)
values = Characters.values(χ) .* Characters.values(ψ)
return Character(table(χ), __decompose(Int, values, table(χ)))
end

Base.:^::Character, n::Integer) = Base.power_by_squaring(χ, n)

## Group-theoretic functions:

PermutationGroups.degree::Character) = Int(χ(one(parent(χ))))
function PermutationGroups.degree(
χ::Character{T,CCl},
) where {T,CCl<:AbstractOrbit{<:AbstractMatrix}}
return Int(χ[1])
end

function Base.conj::Character{T,S}) where {T,S}
vals = collect(values(χ))
all(isreal, vals) && return Character{T}(χ)
tbl = table(χ)
ψ = ClassFunction(vals[tbl.inv_of], conjugacy_classes(tbl), tbl.inv_of)
multips = S[dot(ψ, χ) for χ in irreducible_characters(tbl)]
return Character{T,eltype(multips),typeof(tbl)}(tbl, multips)
end

function isvirtual::Character)
return any(<(0), multiplicities(χ)) || any(!isinteger, multiplicities(χ))
end

function isirreducible::Character)
C = multiplicities(χ)
k = findfirst(!iszero, C)
k !== nothing || return false # χ is zero
isone(C[k]) || return false # muliplicity is ≠ 1
kn = findnext(!iszero, C, k + 1)
kn === nothing && return true # there is only one ≠ 0 entry
return false
end

"""
affordable_real!(χ::Character)
Return either `χ` or `2re(χ)` depending whether `χ` is afforded by a real
representation, modifying `χ` in place.
"""
function affordable_real!::Character)
ι = frobenius_schur(χ)
if ι <= 0 # i.e. χ is complex or quaternionic
χ.multips .+= multiplicities(conj(χ))
end
return χ
end

"""
frobenius_schur(χ::AbstractClassFunction[, pmap::PowerMap])
Return Frobenius-Schur indicator of `χ`, i.e. `Σχ(g²)` where sum is taken over
the whole group.
If χ is an irreducible `Character`, Frobenius-Schur indicator takes values in
`{1, 0, -1}` which correspond to the following situations:
1. `χ` is real-valued and is afforded by an irreducible real representation,
2. `χ` is a complex character which is not afforded by a real representation, and
3. `χ` is quaternionic character, i.e. it is real valued, but is not afforded by a
real representation.
In cases 2. and 3. `2re(χ) = χ + conj(χ)` corresponds to an irreducible character
afforded by a real representation.
"""
function frobenius_schur::Character)
@assert isirreducible(χ)

pmap = powermap(table(χ))
ι = sum(
length(c) * χ[pmap[i, 2]] for (i, c) in enumerate(conjugacy_classes(χ))
)

ι_int = Int(ι)
ordG = sum(length, conjugacy_classes(χ))
d, r = divrem(ι_int, ordG)
@assert r == 0 "Non integral Frobenius Schur Indicator: $(ι_int) = $d * $ordG + $r"
return d
end

Base.isreal::Character) = frobenius_schur(χ) > 0
Loading

0 comments on commit 38d35ee

Please sign in to comment.