diff --git a/experimental/LieAlgebras/src/AbstractLieAlgebra.jl b/experimental/LieAlgebras/src/AbstractLieAlgebra.jl index be4240d1c92e..a6de6661a38d 100644 --- a/experimental/LieAlgebras/src/AbstractLieAlgebra.jl +++ b/experimental/LieAlgebras/src/AbstractLieAlgebra.jl @@ -85,19 +85,6 @@ function root_system(L::LieAlgebra) return L.root_system end -has_root_system_type(L::AbstractLieAlgebra) = - has_root_system(L) && has_root_system_type(L.root_system) - -function root_system_type(L::AbstractLieAlgebra) - @req has_root_system_type(L) "No root system type known." - return root_system_type(root_system(L)) -end - -function root_system_type_string(L::AbstractLieAlgebra) - @req has_root_system_type(L) "No root system type known." - return root_system_type_string(root_system(L)) -end - @doc raw""" chevalley_basis(L::AbstractLieAlgebra{C}) -> NTuple{3,Vector{AbstractLieAlgebraElem{C}}} @@ -128,8 +115,6 @@ function Base.show(io::IO, ::MIME"text/plain", L::AbstractLieAlgebra) io = pretty(io) println(io, "Abstract Lie algebra") println(io, Indent(), "of dimension $(dim(L))", Dedent()) - has_root_system_type(L) && - println(io, Indent(), "of type $(root_system_type_string(L))", Dedent()) print(io, "over ") print(io, Lowercase(), coefficient_ring(L)) end diff --git a/experimental/LieAlgebras/src/CartanMatrix.jl b/experimental/LieAlgebras/src/CartanMatrix.jl index 0858454b9611..fbce231ae372 100644 --- a/experimental/LieAlgebras/src/CartanMatrix.jl +++ b/experimental/LieAlgebras/src/CartanMatrix.jl @@ -79,6 +79,28 @@ function cartan_matrix(fam::Symbol, rk::Int) return mat end +@doc raw""" + cartan_matrix(type::Vector{Tuple{Symbol,Int}}) -> ZZMatrix + +Returns a block diagonal matrix of indecomposable Cartan matrices as defined by type. +For allowed values see `cartan_matrix(fam::Symbol, rk::Int)`. + +# Example +```jldoctest +julia> cartan_matrix([(:A, 2), (:B, 2)]) +[ 2 -1 0 0] +[-1 2 0 0] +[ 0 0 2 -1] +[ 0 0 -2 2] +``` +""" +function cartan_matrix(type::Vector{Tuple{Symbol,Int}}) + @req length(type) > 0 "At least one type is required" + + blocks = [cartan_matrix(t...) for t in type] + return block_diagonal_matrix(blocks) +end + @doc raw""" cartan_matrix(type::Tuple{Symbol,Int}...) -> ZZMatrix @@ -97,8 +119,7 @@ julia> cartan_matrix((:A, 2), (:B, 2)) function cartan_matrix(type::Tuple{Symbol,Int}...) @req length(type) > 0 "At least one type is required" - blocks = [cartan_matrix(t...) for t in type] - return block_diagonal_matrix(blocks) + return cartan_matrix(collect(type)) end @doc raw""" @@ -257,6 +278,9 @@ This function is left inverse to `cartan_matrix`, i.e. in the case of isomorphic the ordering of the roots does matter (see the example below). The keyword argument `check` can be set to `false` to skip verification whether `gcm` is indeed a Cartan matrix of finite type. +The order of returned components is, in general, not unique and might change between versions. +If this function is called with the output of `cartan_matrix(type)`, it will keep the order of `type`. + # Example ```jldoctest julia> cartan_type(ZZ[2 -1; -2 2]) @@ -278,19 +302,17 @@ end Returns the Cartan type of a Cartan matrix `gcm` together with a vector indicating a canonical ordering of the roots in the Dynkin diagram (currently only Cartan matrices of finite type are supported). -The keyword argument `check` can be set to `false` to skip verification whether `gcm` is indeed a Cartan matrix of finite type. +The keyword argument `check` can be set to `false` to skip verification whether `gcm` is indeed a +Cartan matrix of finite type. + +The order of returned components and the ordering is, in general, not unique and might change between versions. +If this function is called with the output of `cartan_matrix(type)`, it will keep the order of `type` and the +returned ordering will be the identity. + # Example ```jldoctest -julia> cartan_matrix(:E, 6) -[ 2 0 -1 0 0 0] -[ 0 2 0 -1 0 0] -[-1 0 2 -1 0 0] -[ 0 -1 -1 2 -1 0] -[ 0 0 0 -1 2 -1] -[ 0 0 0 0 -1 2] - julia> cartan_type_with_ordering(cartan_matrix(:E, 6)) -([(:E, 6)], [1, 3, 4, 2, 5, 6]) +([(:E, 6)], [1, 2, 3, 4, 5, 6]) julia> cartan_type_with_ordering(ZZ[2 0 -1 0; 0 2 0 -2; -2 0 2 0; 0 -1 0 2]) ([(:B, 2), (:C, 2)], [1, 3, 2, 4]) @@ -304,135 +326,133 @@ function cartan_type_with_ordering(gcm::ZZMatrix; check::Bool=true) # global information ord = sizehint!(Int[], rk) # ordering of the roots - adj = [sizehint!(Int[], 3) for _ in 1:rk] # store adjacent roots, adj[i] is ordered asc + adj = [[j for j in 1:rk if i != j && !is_zero_entry(gcm, i, j)] for i in 1:rk] # adjacency list + done = falses(rk) # whether a root is already in a component - # information about current type - num = 0 # number of roots - roots = sizehint!(Int[], rk) + for v0 in 1:rk + done[v0] && continue - # used for traversal - undone = trues(rk) - plan = zeros(Int, 3) # a root is connected to up to 3 others - head = 0 # index up to which we planned (cyclic) - tail = 0 # index of plan which will be done next - - i, j = 1, 2 - while true - while i == j || (j <= rk && is_zero_entry(gcm, i, j)) - j += 1 + # rank 1 + if length(adj[v0]) == 0 + push!(type, (:A, 1)) + push!(ord, v0) + done[v0] = true + continue end - if j == rk + 1 - num += 1 - undone[i] = false - push!(roots, i) - - if tail != head - tail += 1 - if tail == 4 - tail = 1 - end - i = plan[tail] - else # nothing further is planned - offset = length(ord) + 1 - if num == 1 # rank 1 - push!(type, (:A, 1)) - push!(ord, i) - elseif num == 2 # rank 2 - i, j = roots[1], roots[2] - if gcm[i, j] * gcm[j, i] == 1 - push!(type, (:A, 2)) - push!(ord, i, j) - elseif gcm[i, j] == -2 - push!(type, (:C, 2)) - push!(ord, i, j) - elseif gcm[j, i] == -2 - push!(type, (:B, 2)) - push!(ord, i, j) - elseif gcm[i, j] == -3 - push!(type, (:G, 2)) - push!(ord, i, j) - else - push!(type, (:G, 2)) - push!(ord, j, i) - end - else # rank > 2 - # find start of the Dynkin graph - v = 0 - for i in roots - j = adj[i][1] - if length(adj[i]) == 1 && gcm[i, j] * gcm[j, i] == 1 - if length(adj[j]) == 1 || (length(adj[j]) == 2 && gcm[j, adj[j][2]] == -1) - v = i - break - elseif v == 0 - v = i - end - end - end - push!(ord, v) - - n = 1 - adj3 = false # true if found a root with 3 adjacents - while n < num - nv = v - for vv in adj[v] - filter!(x -> x != v, adj[vv]) - push!(ord, vv) - n += 1 - if length(adj[vv]) > 0 - nv = vv - if length(adj[vv]) == 2 # +1 for the predecessor - adj3 = true - end - end - end - v = nv - end - - if adj3 - if isempty(adj[ord[end]]) && isempty(adj[ord[end - 1]]) - push!(type, (:D, num)) - else - push!(type, (:E, num)) - end - elseif num == 4 && - gcm[ord[end - 2], ord[end - 1]] * gcm[ord[end - 1], ord[end - 2]] > 1 - push!(type, (:F, 4)) - elseif gcm[ord[end - 1], ord[end]] * gcm[ord[end], ord[end - 1]] == 1 - push!(type, (:A, num)) - elseif gcm[ord[end - 1], ord[end]] == -1 - push!(type, (:B, num)) - else - push!(type, (:C, num)) - end - end - - # find next component - i = findfirst(undone) - if isnothing(i) - break - end - # reset number of roots - num = 0 - empty!(roots) + # rank 2 + if length(adj[v0]) == 1 && length(adj[only(adj[v0])]) == 1 + v1 = only(adj[v0]) + if gcm[v0, v1] * gcm[v1, v0] == 1 + push!(type, (:A, 2)) + push!(ord, v0, v1) + elseif gcm[v0, v1] == -2 + push!(type, (:C, 2)) + push!(ord, v0, v1) + elseif gcm[v1, v0] == -2 + push!(type, (:B, 2)) + push!(ord, v0, v1) + elseif gcm[v0, v1] == -3 + push!(type, (:G, 2)) + push!(ord, v0, v1) + elseif gcm[v1, v0] == -3 + push!(type, (:G, 2)) + push!(ord, v1, v0) + else + error("unreachable") end - - j = 1 + done[v0] = true + done[v1] = true continue end - # plan to visit j if undone - if undone[j] - head += 1 - if head == 4 - head = 1 + # rank > 2 + # do a DFS to find the whole component + comp = [v0] + todo = [v0] + done[v0] = true + while !isempty(todo) + v = pop!(todo) + for w in adj[v] + if !done[w] + push!(comp, w) + push!(todo, w) + done[w] = true + end end - plan[head] = j end + sort!(comp) + len_comp = length(comp) + + deg3 = findfirst(v -> length(adj[v]) == 3, comp) + if isnothing(deg3) + # case A, B, C, F + + # find start of the Dynkin graph + start = 0 + for v1 in filter(v -> length(adj[v]) == 1, comp) + v2 = only(adj[v1]) + gcm[v1, v2] * gcm[v2, v1] == 1 || continue # discard right end of B and C + if len_comp == 4 + v3 = only(filter(!=(v1), adj[v2])) + gcm[v2, v3] == -1 || continue # discard right end of F + end - push!(adj[i], j) - j += 1 + # found start + start = v1 + break + end + @assert start != 0 + + # find the path + path = [start, only(adj[start])] + for _ in 1:(len_comp - 2) + push!(path, only(filter(!=(path[end - 1]), adj[path[end]]))) + end + # determine type + if len_comp == 4 && gcm[path[3], path[2]] == -2 + push!(type, (:F, 4)) + elseif gcm[path[end - 1], path[end]] == -2 + push!(type, (:C, len_comp)) + elseif gcm[path[end], path[end - 1]] == -2 + push!(type, (:B, len_comp)) + else + push!(type, (:A, len_comp)) + end + append!(ord, path) + else + # case D or E + + # find the three paths + v_deg3 = comp[deg3] + paths = [[v_deg3, v_n] for v_n in adj[v_deg3]] + for path in paths + while length(adj[path[end]]) == 2 + push!(path, only(filter(!=(path[end - 1]), adj[path[end]]))) + end + popfirst!(path) + end + sort!(paths; by=length) + @assert sum(length, paths) + 1 == len_comp + # determine type + if length(paths[2]) == 1 + # case D + push!(type, (:D, len_comp)) + if len_comp == 4 + push!(ord, only(paths[1]), v_deg3, only(paths[2]), only(paths[3])) + else + append!(ord, reverse!(paths[3])) + push!(ord, v_deg3, only(paths[1]), only(paths[2])) + end + elseif length(paths[2]) == 2 + # case E + push!(type, (:E, len_comp)) + push!(ord, paths[2][2], only(paths[1]), paths[2][1], v_deg3) + append!(ord, paths[3]) + else + error("unreachable") + end + end end return type, ord diff --git a/experimental/LieAlgebras/src/DynkinDiagram.jl b/experimental/LieAlgebras/src/DynkinDiagram.jl index 6dc07b6fd6c6..5aea2acc34be 100644 --- a/experimental/LieAlgebras/src/DynkinDiagram.jl +++ b/experimental/LieAlgebras/src/DynkinDiagram.jl @@ -1,3 +1,58 @@ +@doc raw""" + show_dynkin_diagram(cartan_matrix::ZZMatrix) -> Nothing + +Prints a string representation of the Dynkin diagram of the root system +with the given cartan matrix. +The labels of the nodes are the indices of the simple roots. + +Currently, only cartan matrices of finite type are supported. +""" +function show_dynkin_diagram(cartan_matrix::ZZMatrix) + type, label = cartan_type_with_ordering(cartan_matrix) + return show_dynkin_diagram(type, label) +end + +@doc raw""" + show_dynkin_diagram(rs::RootSystem) -> Nothing + +Prints a string representation of the Dynkin diagram of the given root system. +The labels of the nodes are the indices of the simple roots. + +Currently, only root systems of finite type are supported. +""" +function show_dynkin_diagram(rs::RootSystem) + type, label = root_system_type_with_ordering(rs) + return show_dynkin_diagram(type, label) +end + +@doc raw""" + show_dynkin_diagram(type::Vector{Tuple{Symbol,Int}}) -> Nothing + +Prints a string representation of the Dynkin diagram of the root system of +the given cartan type. +""" +function show_dynkin_diagram(type::Vector{Tuple{Symbol,Int}}) + return show_dynkin_diagram(type, 1:sum(t[2] for t in type; init=0)) +end + +@doc raw""" + show_dynkin_diagram(type::Vector{Tuple{Symbol,Int}}, labels::AbstractVector{Int}) -> Nothing + +Prints a string representation of the Dynkin diagram of the root system of +the given cartan type. +""" +function show_dynkin_diagram(type::Vector{Tuple{Symbol,Int}}, labels::AbstractVector{Int}) + @req length(labels) == sum(t[2] for t in type; init=0) "Invalid number of labels" + offset = 0 + for (fam, rk) in type + show_dynkin_diagram(fam, rk, labels[(offset + 1):(offset + rk)]) + offset += rk + println() + println() + end + return nothing +end + @doc raw""" show_dynkin_diagram(fam::Symbol, rk::Int) -> Nothing @@ -5,7 +60,7 @@ Prints a string representation of the Dynkin diagram of the root system of the given cartan type. """ function show_dynkin_diagram(fam::Symbol, rk::Int) - show_dynkin_diagram(fam, rk, 1:rk) + return show_dynkin_diagram(fam, rk, 1:rk) end @doc raw""" @@ -49,4 +104,5 @@ function show_dynkin_diagram(fam::Symbol, rk::Int, labels::AbstractVector{Int}) end isempty(D) && error("Unreachable") print(D) + return nothing end diff --git a/experimental/LieAlgebras/src/LieAlgebras.jl b/experimental/LieAlgebras/src/LieAlgebras.jl index d8c53b55cb19..ac341fa53464 100644 --- a/experimental/LieAlgebras/src/LieAlgebras.jl +++ b/experimental/LieAlgebras/src/LieAlgebras.jl @@ -167,8 +167,9 @@ export positive_root export positive_roots export reduced_expressions export reflect, reflect! -export root_system_type, has_root_system_type export root_system, has_root_system +export root_system_type, has_root_system_type +export root_system_type_with_ordering export show_dynkin_diagram export simple_coroot export simple_coroots @@ -290,8 +291,9 @@ export positive_roots export reduced_expressions export reflect, reflect! export root -export root_system_type, has_root_system_type export root_system, has_root_system +export root_system_type, has_root_system_type +export root_system_type_with_ordering export roots export show_dynkin_diagram export simple_coroot diff --git a/experimental/LieAlgebras/src/RootSystem.jl b/experimental/LieAlgebras/src/RootSystem.jl index 21277ffde10b..247f3d266698 100644 --- a/experimental/LieAlgebras/src/RootSystem.jl +++ b/experimental/LieAlgebras/src/RootSystem.jl @@ -13,6 +13,7 @@ mutable struct RootSystem # optional: type::Vector{Tuple{Symbol,Int}} + type_ordering::Vector{Int} function RootSystem(mat::ZZMatrix) pos_roots, pos_coroots, refl = positive_roots_and_reflections(mat) @@ -28,19 +29,22 @@ mutable struct RootSystem end @doc raw""" - root_system(cartan_matrix::ZZMatrix; check::Bool=true) -> RootSystem - root_system(cartan_matrix::Matrix{Int}; check::Bool=true) -> RootSystem + root_system(cartan_matrix::ZZMatrix; check::Bool=true, detect_type::Bool=true) -> RootSystem + root_system(cartan_matrix::Matrix{Int}; check::Bool=true, detect_type::Bool=true) -> RootSystem Constructs the root system defined by the Cartan matrix. If `check` is `true`, checks that `cartan_matrix` is a generalized Cartan matrix. +Passing `detect_type=false` will skip the detection of the root system type. """ -function root_system(cartan_matrix::ZZMatrix; check::Bool=true) +function root_system(cartan_matrix::ZZMatrix; check::Bool=true, detect_type::Bool=true) @req !check || is_cartan_matrix(cartan_matrix) "Requires a generalized Cartan matrix" - return RootSystem(cartan_matrix) + R = RootSystem(cartan_matrix) + detect_type && is_finite(weyl_group(R)) && set_root_system_type(R, cartan_type_with_ordering(cartan_matrix)...) + return R end -function root_system(cartan_matrix::Matrix{<:Integer}; check::Bool=true) - return root_system(matrix(ZZ, cartan_matrix); check) +function root_system(cartan_matrix::Matrix{<:Integer}; kwargs...) + return root_system(matrix(ZZ, cartan_matrix); kwargs...) end @doc raw""" @@ -50,18 +54,22 @@ Constructs the root system of the given type. See `cartan_matrix(fam::Symbol, rk """ function root_system(fam::Symbol, rk::Int) cartan = cartan_matrix(fam, rk) - R = root_system(cartan; check=false) - R.type = [(fam, rk)] + R = root_system(cartan; check=false, detect_type=false) + set_root_system_type(R, [(fam, rk)]) return R end -function root_system(types::Tuple{Symbol,Int}...) - cartan = cartan_matrix(types...) - R = root_system(cartan; check=false) - R.type = collect(types) +function root_system(type::Vector{Tuple{Symbol,Int}}) + cartan = cartan_matrix(type) + R = root_system(cartan; check=false, detect_type=false) + set_root_system_type(R, type) return R end +function root_system(type::Tuple{Symbol,Int}...) + return root_system(collect(type)) +end + function Base.show(io::IO, ::MIME"text/plain", R::RootSystem) io = pretty(io) println(io, "Root system defined by Cartan matrix") @@ -133,12 +141,8 @@ function fundamental_weights(R::RootSystem) return [fundamental_weight(R, i) for i in 1:rank(R)] end -function has_root_system_type(R::RootSystem) - return isdefined(R, :type) -end - function is_simple(R::RootSystem) - if has_root_system_type(R) + if is_finite(weyl_group(R)) return length(root_system_type(R)) == 1 end error("Not implemented") # TODO: implement is_simple @@ -280,10 +284,30 @@ function rank(R::RootSystem) end function root_system_type(R::RootSystem) - @req has_root_system_type(R) "root system type not defined" + has_root_system_type(R) || error("Root system type not known and cannot be determined") return R.type end +function root_system_type_with_ordering(R::RootSystem) + return R.type, R.type_ordering +end + +function has_root_system_type(R::RootSystem) + return isdefined(R, :type) && isdefined(R, :type_ordering) +end + +function set_root_system_type(R::RootSystem, type::Vector{Tuple{Symbol,Int}}) + return set_root_system_type(R, type, 1:sum(t[2] for t in type; init=0)) +end + +function set_root_system_type( + R::RootSystem, type::Vector{Tuple{Symbol,Int}}, ordering::AbstractVector{Int} +) + R.type = type + R.type_ordering = collect(ordering) + return nothing +end + function root_system_type_string(R::RootSystem) return join([string(t[1]) * string(t[2]) for t in root_system_type(R)], " x ") end @@ -340,10 +364,6 @@ function simple_roots(R::RootSystem) return positive_roots(R)[1:rank(R)] end -function type(R::RootSystem) - return R.type -end - @doc raw""" simple_coroot(R::RootSystem, i::Int) -> RootSpaceElem diff --git a/experimental/LieAlgebras/src/WeylGroup.jl b/experimental/LieAlgebras/src/WeylGroup.jl index 2b0188d5aa7b..e8c6a2a1a058 100644 --- a/experimental/LieAlgebras/src/WeylGroup.jl +++ b/experimental/LieAlgebras/src/WeylGroup.jl @@ -54,19 +54,28 @@ end @doc raw""" weyl_group(fam::Symbol, rk::Int) -> WeylGroup -Returns the Weyl group defined by . +Returns the Weyl group of the given type. See `cartan_matrix(fam::Symbol, rk::Int)` for allowed combinations. """ function weyl_group(fam::Symbol, rk::Int) return weyl_group(root_system(fam, rk)) end @doc raw""" - weyl_group(type::Tuple{Symbol, Int}...) -> WeylGroup + weyl_group(type::Vector{Tuple{Symbol,Int}}) -> WeylGroup -Returns the Weyl group defined by . +Returns the Weyl group of the given type. See `cartan_matrix(fam::Symbol, rk::Int)` for allowed combinations. +""" +function weyl_group(type::Vector{Tuple{Symbol,Int}}) + return weyl_group(root_system(type)) +end + +@doc raw""" + weyl_group(type::Tuple{Symbol,Int}...) -> WeylGroup + +Returns the Weyl group of the given type. See `cartan_matrix(fam::Symbol, rk::Int)` for allowed combinations. """ function weyl_group(type::Tuple{Symbol,Int}...) - return weyl_group(root_system(type...)) + return weyl_group(root_system(collect(type))) end @doc raw""" @@ -175,7 +184,7 @@ function order(::Type{T}, W::WeylGroup) where {T} end ord = T(1) - for (fam, rk) in type(root_system(W)) + for (fam, rk) in root_system_type(root_system(W)) if fam == :A ord *= T(factorial(rk + 1)) elseif fam == :B || fam == :C diff --git a/experimental/LieAlgebras/test/CartanMatrix-test.jl b/experimental/LieAlgebras/test/CartanMatrix-test.jl index 8d53a14c0159..a03474f0a56f 100644 --- a/experimental/LieAlgebras/test/CartanMatrix-test.jl +++ b/experimental/LieAlgebras/test/CartanMatrix-test.jl @@ -121,100 +121,143 @@ @test cartan_bilinear_form(ZZ[2 -4; -1 2]) == ZZ[2 -4; -4 8] end - @testset "cartan_type(gcm::ZZMatrix; check::Bool)" begin - # test if we follow our own conventions - @test cartan_type(cartan_matrix(:A, 3); check=false) == [(:A, 3)] - @test cartan_type(cartan_matrix(:B, 2); check=false) == [(:B, 2)] - @test cartan_type(cartan_matrix(:C, 2); check=false) == [(:C, 2)] - - # tests for irreducibles - @test cartan_type(cartan_matrix(:A, 1); check=false) == [(:A, 1)] - @test cartan_type(cartan_matrix(:A, 2); check=false) == [(:A, 2)] - - @test cartan_type(cartan_matrix(:B, 3); check=false) == [(:B, 3)] - @test cartan_type(ZZ[2 -2 0; -1 2 -1; 0 -1 2]; check=false) == [(:B, 3)] - - # Cn - @test cartan_type(cartan_matrix(:C, 3); check=false) == [(:C, 3)] - @test cartan_type(ZZ[2 -1 0; -2 2 -1; 0 -1 2]; check=false) == [(:C, 3)] - - # Dn - @test cartan_type(cartan_matrix(:D, 4); check=false) == [(:D, 4)] - @test cartan_type(ZZ[2 -1 -1 -1; -1 2 0 0; -1 0 2 0; -1 0 0 2]) == [(:D, 4)] - @test cartan_type(cartan_matrix(:D, 6); check=false) == [(:D, 6)] - - @test cartan_type(cartan_matrix(:E, 6); check=false) == [(:E, 6)] - @test cartan_type(cartan_matrix(:E, 7); check=false) == [(:E, 7)] - @test cartan_type(cartan_matrix(:E, 8); check=false) == [(:E, 8)] - @test cartan_type(cartan_matrix(:F, 4); check=false) == [(:F, 4)] - @test cartan_type(cartan_matrix(:G, 2); check=false) == [(:G, 2)] - - # for F4 and G2 we also allow the transposed Cartan matrix - @test cartan_type(transpose(cartan_matrix(:F, 4))) == [(:F, 4)] - @test cartan_type(transpose(cartan_matrix(:G, 2))) == [(:G, 2)] - - # test decomposable Cartan matrices - @test cartan_type(cartan_matrix((:A, 1), (:A, 2)); check=false) == [(:A, 1), (:A, 2)] - @test cartan_type(cartan_matrix((:A, 1), (:B, 2)); check=false) == [(:A, 1), (:B, 2)] - @test cartan_type(cartan_matrix((:C, 2), (:B, 2)); check=false) == [(:C, 2), (:B, 2)] - @test cartan_type(ZZ[2 0 -1 0; 0 2 0 -2; -2 0 2 0; 0 -1 0 2]; check=false) == - [(:B, 2), (:C, 2)] - end - - @testset "cartan_type_with_ordering(gcm::ZZMatrix; check::Bool)" begin - # we only test the ordering here the type detection is tested in "cartan_type(gcm::ZZMatrix; check::Bool)" - - # An - _, ord = cartan_type_with_ordering(cartan_matrix(:A, 1)) - @test ord == [1] - - _, ord = cartan_type_with_ordering(cartan_matrix(:A, 2)) - @test ord == [1, 2] - - # Bn - _, ord = cartan_type_with_ordering(cartan_matrix(:B, 2)) - @test ord == [1, 2] - - _, ord = cartan_type_with_ordering(cartan_matrix(:B, 3)) - @test ord == [1, 2, 3] - - # Cn - _, ord = cartan_type_with_ordering(cartan_matrix(:C, 2)) - @test ord == [1, 2] - - _, ord = cartan_type_with_ordering(cartan_matrix(:C, 3)) - @test ord == [1, 2, 3] - - # Dn - _, ord = cartan_type_with_ordering(cartan_matrix(:D, 4)) - @test ord == [1, 2, 3, 4] + @testset "cartan_type_with_ordering" begin + function test_cartan_type_with_ordering( + fam::Symbol, n::Int; autos::Vector{PermGroupElem}=[one(symmetric_group(n))] + ) + @req all(aut -> parent(aut) == symmetric_group(n), autos) "Incompatible permutation parent" + cm = cartan_matrix(fam, n) + for perm in symmetric_group(n) + type, ord = cartan_type_with_ordering( + permutation_matrix(ZZ, inv(perm)) * cm * permutation_matrix(ZZ, perm); check=false + ) + @test type == [(fam, n)] + @test ord in [Vector{Int}(aut * perm) for aut in autos] + @test !is_one(perm) || ord == 1:n + end + end - _, ord = cartan_type_with_ordering(ZZ[2 -1 -1 -1; -1 2 0 0; -1 0 2 0; -1 0 0 2]) - @test ord == [2, 1, 3, 4] + @testset "A_n" begin + @testset "A_$n" for n in 1:8 + # automorphism group of Dynkin diagram ≅ S_2 (horizontal reflection) + test_cartan_type_with_ordering( + :A, + n; + autos=[ + cperm(symmetric_group(n), Int[]), + cperm(symmetric_group(n), Vector{Int}[[i, n + 1 - i] for i in 1:div(n, 2)]), + ], + ) + end + end - # En - _, ord = cartan_type_with_ordering(cartan_matrix(:E, 6)) - @test ord == [1, 3, 4, 2, 5, 6] + @testset "B_n" begin + @testset "B_2" begin + n = 2 + # B_2 is isomorphic to C_2; we decide based on the ordering + cm = cartan_matrix(:B, n) + # identity permutation + type, ord = cartan_type_with_ordering(cm; check=false) + @test type == [(:B, n)] + @test ord == [1, 2] + # non-identity permutation + type, ord = cartan_type_with_ordering(transpose(cm); check=false) + @test type == [(:C, 2)] + @test ord == [1, 2] + end + @testset "B_$n" for n in 3:8 + # no automorphisms of Dynkin diagram + test_cartan_type_with_ordering(:B, n) + end + end - _, ord = cartan_type_with_ordering(cartan_matrix(:E, 7)) - @test ord == [1, 3, 4, 2, 5, 6, 7] + @testset "C_n" begin + @testset "C_2" begin + n = 2 + # C_2 is isomorphic to B_2; we decide based on the ordering + cm = cartan_matrix(:C, n) + # identity permutation + type, ord = cartan_type_with_ordering(cm; check=false) + @test type == [(:C, n)] + @test ord == [1, 2] + # non-identity permutation + type, ord = cartan_type_with_ordering(transpose(cm); check=false) + @test type == [(:B, 2)] + @test ord == [1, 2] + end + @testset "C_$n" for n in 3:8 + # no automorphisms of Dynkin diagram + test_cartan_type_with_ordering(:C, n) + end + end - _, ord = cartan_type_with_ordering(cartan_matrix(:E, 8)) - @test ord == [1, 3, 4, 2, 5, 6, 7, 8] + @testset "D_n" begin + @testset "D_$n" for n in 4:8 + if n == 4 + # automorphism group of Dynkin diagram ≅ S_3 + test_cartan_type_with_ordering( + :D, n; autos=(@perm 4 [(), (1, 3), (1, 4), (3, 4), (1, 3, 4), (1, 4, 3)]) + ) + else + # automorphism group of Dynkin diagram ≅ S_2 (vertical reflection) + test_cartan_type_with_ordering( + :D, + n; + autos=[ + cperm(symmetric_group(n), Int[]), cperm(symmetric_group(n), Int[n - 1, n]) + ], + ) + end + end + end - # F4 - _, ord = cartan_type_with_ordering(cartan_matrix(:F, 4)) - @test ord == [1, 2, 3, 4] + @testset "E_n" begin + @testset "E_$n" for n in 6:8 + if n == 6 + # automorphism group of Dynkin diagram ≅ S_2 (horizontal reflection) + test_cartan_type_with_ordering(:E, n; autos=(@perm 6 [(), (1, 6)(3, 5)])) + else + # no automorphisms of Dynkin diagram + test_cartan_type_with_ordering(:E, n) + end + end + end - _, ord = cartan_type_with_ordering(ZZ[2 -1 0 0; -1 2 -2 0; 0 -1 2 -1; 0 0 -1 2]) - @test ord == [4, 3, 2, 1] + @testset "F_4" begin + # no automorphisms of Dynkin diagram + test_cartan_type_with_ordering(:F, 4) + end - # G2 - _, ord = cartan_type_with_ordering(cartan_matrix(:G, 2)) - @test ord == [1, 2] + @testset "G_2" begin + # no automorphisms of Dynkin diagram + test_cartan_type_with_ordering(:G, 2) + end - _, ord = cartan_type_with_ordering(transpose(cartan_matrix(:G, 2))) - @test ord == [2, 1] + @testset "non-simple cases" begin + type, ord = cartan_type_with_ordering(cartan_matrix((:A, 1), (:A, 2)); check=false) + @test type == [(:A, 1), (:A, 2)] + @test ord == 1:3 + + type, ord = cartan_type_with_ordering(cartan_matrix((:A, 1), (:B, 2)); check=false) + @test type == [(:A, 1), (:B, 2)] + @test ord == 1:3 + + type, ord = cartan_type_with_ordering(cartan_matrix((:C, 2), (:B, 2)); check=false) + @test type == [(:C, 2), (:B, 2)] + @test ord == 1:4 + + type, ord = cartan_type_with_ordering( + cartan_matrix((:E, 8), (:A, 5), (:D, 4), (:F, 4), (:B, 8)); check=false + ) + @test type == [(:E, 8), (:A, 5), (:D, 4), (:F, 4), (:B, 8)] + @test ord == 1:(8 + 5 + 4 + 4 + 8) + + type, ord = cartan_type_with_ordering( + ZZ[2 0 -1 0; 0 2 0 -2; -2 0 2 0; 0 -1 0 2]; check=false + ) + @test type == [(:B, 2), (:C, 2)] + @test ord == [1, 3, 2, 4] + end end @testset "is_cartan_type" begin diff --git a/experimental/LieAlgebras/test/DynkinDiagram-test.jl b/experimental/LieAlgebras/test/DynkinDiagram-test.jl index 1f13ccd76e79..d7c899013f65 100644 --- a/experimental/LieAlgebras/test/DynkinDiagram-test.jl +++ b/experimental/LieAlgebras/test/DynkinDiagram-test.jl @@ -231,6 +231,155 @@ julia> show_dynkin_diagram(:F, 4, [105, 2, 99, 300]) julia> show_dynkin_diagram(:G, 2, [412, 5]) 412 <<< 5 ``` + +non-simple diagram with canonical labels + +```jldoctest show_ns_dynkin_diagram.test +julia> using Oscar + +julia> show_dynkin_diagram([(:B, 5), (:B, 5)]) +1 - 2 - 3 - 4 >=> 5 + +6 - 7 - 8 - 9 >=> 10 + +julia> show_dynkin_diagram([(:A, 2), (:B, 3), (:C, 4), (:D, 5), (:E, 6), (:F, 4), (:G, 2)]) +1 - 2 + +3 - 4 >=> 5 + +6 - 7 - 8 <=< 9 + +. 13 + / +10 - 11 - 12 + \ + 14 + +15 - 17 - 18 - 19 - 20 + | + 16 + +21 - 22 >=> 23 - 24 + +25 <<< 26 +``` + +non-simple diagram with non-canonical labels + +```jldoctest show_ns_dynkin_diagram_with_labels.test +julia> using Oscar + +julia> show_dynkin_diagram([(:B, 5), (:B, 5)], [15,3,6,0,1000,23,8,22,65,1]) +15 - 3 - 6 - 0 >=> 1000 + +23 - 8 - 22 - 65 >=> 1 + +julia> show_dynkin_diagram([(:A, 2), (:B, 3), (:C, 4), (:D, 5), (:E, 6), (:F, 4), (:G, 2)], 2*(2+3+4+5+6+4+2):-2:2) +52 - 50 + +48 - 46 >=> 44 + +42 - 40 - 38 <=< 36 + +. 28 + / +34 - 32 - 30 + \ + 26 + +24 - 20 - 18 - 16 - 14 + | + 22 + +12 - 10 >=> 8 - 6 + +4 <<< 2 +``` + +Dynkin diagram from cartan matrix + +```jldoctest show_dynkin_diagram_cartan_matrix.test +julia> using Oscar + +julia> show_dynkin_diagram(cartan_matrix(:A, 3)) +1 - 2 - 3 + +julia> show_dynkin_diagram(cartan_matrix(:B, 4)) +1 - 2 - 3 >=> 4 + +julia> show_dynkin_diagram(cartan_matrix(:C, 5)) +1 - 2 - 3 - 4 <=< 5 + +julia> show_dynkin_diagram(cartan_matrix(:D, 6)) +. 5 + / +1 - 2 - 3 - 4 + \ + 6 + +julia> show_dynkin_diagram(cartan_matrix(:E, 7)) +1 - 3 - 4 - 5 - 6 - 7 + | + 2 + +julia> show_dynkin_diagram(cartan_matrix(:F, 4)) +1 - 2 >=> 3 - 4 + +julia> show_dynkin_diagram(cartan_matrix(:G, 2)) +1 <<< 2 + +julia> show_dynkin_diagram(ZZ[2 0 -1 0; 0 2 0 -2; -2 0 2 0; 0 -1 0 2]) +1 >=> 3 + +2 <=< 4 + +julia> show_dynkin_diagram(transpose(cartan_matrix(:F, 4))) +4 - 3 >=> 2 - 1 + +julia> show_dynkin_diagram(transpose(cartan_matrix(:G, 2))) +2 <<< 1 +``` + +Dynkin diagram from root system + +```jldoctest show_dynkin_diagram_cartan_matrix.test +julia> using Oscar + +julia> show_dynkin_diagram(root_system(:A, 3)) +1 - 2 - 3 + +julia> show_dynkin_diagram(root_system([(:B, 4)])) +1 - 2 - 3 >=> 4 + +julia> show_dynkin_diagram(root_system(cartan_matrix(:C, 5))) +1 - 2 - 3 - 4 <=< 5 + +julia> show_dynkin_diagram(root_system([(:D, 8), (:E, 6), (:F, 4), (:G, 2)])) +. 7 + / +1 - 2 - 3 - 4 - 5 - 6 + \ + 8 + +9 - 11 - 12 - 13 - 14 + | + 10 + +15 - 16 >=> 17 - 18 + +19 <<< 20 + +julia> show_dynkin_diagram(root_system(ZZ[2 0 -1 0; 0 2 0 -2; -2 0 2 0; 0 -1 0 2])) +1 >=> 3 + +2 <=< 4 + +julia> show_dynkin_diagram(root_system(transpose(cartan_matrix(:F, 4)))) +4 - 3 >=> 2 - 1 + +julia> show_dynkin_diagram(root_system(transpose(cartan_matrix(:G, 2)))) +2 <<< 1 +``` """ function dummy_placeholder end diff --git a/experimental/LieAlgebras/test/WeylGroup-test.jl b/experimental/LieAlgebras/test/WeylGroup-test.jl index de2a23738ec5..9ffa1f51dde6 100644 --- a/experimental/LieAlgebras/test/WeylGroup-test.jl +++ b/experimental/LieAlgebras/test/WeylGroup-test.jl @@ -55,6 +55,7 @@ include( ("B4", weyl_group(root_system(:B, 4))), ("D5", weyl_group(cartan_matrix(:D, 5))), ("F4+G2", weyl_group((:F, 4), (:G, 2))), + ("E6+C3", weyl_group([(:E, 6), (:C, 3)])), ("A_1^(1)", weyl_group(ZZ[2 -2; -2 2])), # TODO: replace with cartan_matrix(A_1^(1)), once functionality for affine type is added ( "complicated case 1",