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

Reorganization #71

Merged
merged 4 commits into from
Nov 29, 2023
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
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)

Check warning on line 111 in src/Characters/chars.jl

View check run for this annotation

Codecov / codecov/patch

src/Characters/chars.jl#L110-L111

Added lines #L110 - L111 were not covered by tests
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(

Check warning on line 145 in src/Characters/chars.jl

View check run for this annotation

Codecov / codecov/patch

src/Characters/chars.jl#L145

Added line #L145 was not covered by tests
χ::Character{T,CCl},
) where {T,CCl<:AbstractOrbit{<:AbstractMatrix}}
return Int(χ[1])

Check warning on line 148 in src/Characters/chars.jl

View check run for this annotation

Codecov / codecov/patch

src/Characters/chars.jl#L148

Added line #L148 was not covered by tests
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(χ))

Check warning on line 161 in src/Characters/chars.jl

View check run for this annotation

Codecov / codecov/patch

src/Characters/chars.jl#L160-L161

Added lines #L160 - L161 were not covered by tests
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(χ))

Check warning on line 182 in src/Characters/chars.jl

View check run for this annotation

Codecov / codecov/patch

src/Characters/chars.jl#L179-L182

Added lines #L179 - L182 were not covered by tests
end
return χ

Check warning on line 184 in src/Characters/chars.jl

View check run for this annotation

Codecov / codecov/patch

src/Characters/chars.jl#L184

Added line #L184 was not covered by tests
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
Loading