From 9e026a924d8d197d0a9366cfa3f97f87f9222a59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Mon, 26 Aug 2024 10:47:46 +0200 Subject: [PATCH 01/18] Add `isomorphism(FPGroup, ::WeylGroup)` --- experimental/LieAlgebras/src/CoxeterGroup.jl | 37 +++++++++++-------- experimental/LieAlgebras/src/LieAlgebras.jl | 2 + experimental/LieAlgebras/src/WeylGroup.jl | 32 ++++++++++++++++ .../LieAlgebras/test/WeylGroup-test.jl | 35 ++++++++++++++++-- 4 files changed, 87 insertions(+), 19 deletions(-) diff --git a/experimental/LieAlgebras/src/CoxeterGroup.jl b/experimental/LieAlgebras/src/CoxeterGroup.jl index 1d1799050343..8cf3a6aeae37 100644 --- a/experimental/LieAlgebras/src/CoxeterGroup.jl +++ b/experimental/LieAlgebras/src/CoxeterGroup.jl @@ -7,26 +7,31 @@ Return the Coxeter matrix $m$ associated to the Cartan matrix `gcm`. If there is then this will be expressed by $m_{ij} = 0$ (instead of the usual convention $m_{ij} = \infty$). The keyword argument `check` can be set to `false` to skip verification whether `gcm` is indeed a generalized Cartan matrix. """ -function coxeter_from_cartan_matrix(gcm; check::Bool=true) +function coxeter_from_cartan_matrix(gcm::ZZMatrix; check::Bool=true) @req !check || is_cartan_matrix(gcm) "requires a generalized Cartan matrix" - cm = identity_matrix(gcm) rk, _ = size(gcm) - for i in 1:rk, j in 1:rk - if i == j - continue - end + cm = matrix( + ZZ, [coxeter_matrix_entry_from_cartan_matrix(gcm, i, j) for i in 1:rk, j in 1:rk] + ) - if gcm[i, j] == 0 - cm[i, j] = 2 - elseif gcm[i, j] == -1 - cm[i, j] = 3 - elseif gcm[i, j] == -2 - cm[i, j] = 4 - elseif gcm[i, j] == -3 - cm[i, j] = 6 - end + return cm +end + +function coxeter_matrix_entry_from_cartan_matrix(gcm::ZZMatrix, i::Int, j::Int) + if i == j + return 1 end - return cm + if gcm[i, j] * gcm[j, i] == 0 + return 2 + elseif gcm[i, j] * gcm[j, i] == 1 + return 3 + elseif gcm[i, j] * gcm[j, i] == 2 + return 4 + elseif gcm[i, j] * gcm[j, i] == 3 + return 6 + else + return 0 + end end diff --git a/experimental/LieAlgebras/src/LieAlgebras.jl b/experimental/LieAlgebras/src/LieAlgebras.jl index e9b4fb490e45..ad7059f93341 100644 --- a/experimental/LieAlgebras/src/LieAlgebras.jl +++ b/experimental/LieAlgebras/src/LieAlgebras.jl @@ -43,6 +43,7 @@ import ..Oscar: elem_type, expressify, exterior_power, + fp_group, gen, gens, height, @@ -62,6 +63,7 @@ import ..Oscar: is_simple, is_solvable, is_welldefined, + isomorphism, kernel, lower_central_series, matrix, diff --git a/experimental/LieAlgebras/src/WeylGroup.jl b/experimental/LieAlgebras/src/WeylGroup.jl index accc823ddf8f..22bd942c3d19 100644 --- a/experimental/LieAlgebras/src/WeylGroup.jl +++ b/experimental/LieAlgebras/src/WeylGroup.jl @@ -442,6 +442,38 @@ function word(x::WeylGroupElem) return x.word end +function fp_group(W::WeylGroup; set_properties::Bool=true) + return codomain(isomorphism(FPGroup, W; set_properties)) +end + +function isomorphism(::Type{FPGroup}, W::WeylGroup; set_properties::Bool=true) + R = root_system(W) + F = free_group(rank(R)) + + gcm = cartan_matrix(R) + rels = [ + (gen(F, i) * gen(F, j))^coxeter_matrix_entry_from_cartan_matrix(gcm, i, j) for + i in 1:rank(R) for j in i:rank(R) + ] + + G, _ = quo(F, rels) + + if set_properties + set_is_finite(G, is_finite(W)) + is_finite(W) && set_order(G, order(W)) + end + + iso = function (w::WeylGroupElem) + return G([i => 1 for i in word(w)]) + end + + isoinv = function (g::FPGroupElem) + return W(abs.(letters(g))) + end + + return MapFromFunc(W, G, iso, isoinv) +end + ############################################################################### # ReducedExpressionIterator diff --git a/experimental/LieAlgebras/test/WeylGroup-test.jl b/experimental/LieAlgebras/test/WeylGroup-test.jl index 7bf2ed5a240c..76178206bce4 100644 --- a/experimental/LieAlgebras/test/WeylGroup-test.jl +++ b/experimental/LieAlgebras/test/WeylGroup-test.jl @@ -50,7 +50,7 @@ include( @test_throws ArgumentError weyl_group((:B, 2), (:G, 4)) end - @testset "WeylGroup Group conformace test for $(Gname)" for (Gname, G) in [ + @testset "WeylGroup Group conformace test for $(Wname)" for (Wname, W) in [ ("A1", weyl_group(:A, 1)), ("B4", weyl_group(root_system(:B, 4))), ("D5", weyl_group(cartan_matrix(:D, 5))), @@ -87,8 +87,37 @@ include( ), ] # TODO: @felix-roehrich make this work - # test_Group_interface(G) - # test_GroupElem_interface(rand(G, 2)...) + # test_Group_interface(W) + # test_GroupElem_interface(rand(W, 2)...) + + @testset "isomorphism(FPGroup, ::WeylGroup; set_properties=$set_properties)" for set_properties in + [ + false, true + ] + G = fp_group(W; set_properties) + if (is_finite(W) && ngens(W) < 6) || set_properties #= for sane runtime =# + @test is_finite(G) == is_finite(W) + is_finite(W) && @test order(G) == order(W) + end + + iso = isomorphism(FPGroup, W; set_properties) + @test W == domain(iso) + G = codomain(iso) + if (is_finite(W) && ngens(W) < 6) || set_properties #= for sane runtime =# + @test is_finite(G) == is_finite(W) + is_finite(W) && @test order(G) == order(W) + if ngens(W) < 10 #= for sane runtime =# + for _ in 1:5 + if is_finite(W) # remove once rand(W) is implemented for infinite groups + w = rand(W) + @test w == inv(iso)(iso(w)) + end + g = rand_pseudo(G) + @test g == iso(inv(iso)(g)) + end + end + end + end end @testset "<(x::WeylGroupElem, y::WeylGroupElem)" begin From c98f49cb9e7812b716d5c6425035747d3e34ef0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Mon, 26 Aug 2024 12:26:25 +0200 Subject: [PATCH 02/18] Add root/weight conversion --- experimental/LieAlgebras/src/RootSystem.jl | 50 +++++++++++++++++++ experimental/LieAlgebras/src/Types.jl | 26 +++++----- .../LieAlgebras/test/RootSystem-test.jl | 40 +++++++++++++++ 3 files changed, 102 insertions(+), 14 deletions(-) diff --git a/experimental/LieAlgebras/src/RootSystem.jl b/experimental/LieAlgebras/src/RootSystem.jl index a41b441dcf69..02f1115d8687 100644 --- a/experimental/LieAlgebras/src/RootSystem.jl +++ b/experimental/LieAlgebras/src/RootSystem.jl @@ -88,6 +88,18 @@ function cartan_matrix(R::RootSystem) return R.cartan_matrix end +@attr QQMatrix function cartan_matrix_inv(R::RootSystem) + return inv(matrix(QQ, cartan_matrix(R))) +end + +@attr QQMatrix function cartan_matrix_inv_tr(R::RootSystem) + return transpose(cartan_matrix_inv(R)) +end + +@attr ZZMatrix function cartan_matrix_tr(R::RootSystem) + return transpose(cartan_matrix(R)) +end + @attr Vector{ZZRingElem} function cartan_symmetrizer(R::RootSystem) return cartan_symmetrizer(cartan_matrix(R); check=false) end @@ -406,6 +418,20 @@ end # ############################################################################### +function RootSpaceElem(root_system::RootSystem, vec::Vector{<:RationalUnion}) + return RootSpaceElem(root_system, matrix(QQ, 1, length(vec), vec)) +end + +function RootSpaceElem(R::RootSystem, w::WeightLatticeElem) + @req root_system(w) === R "Root system mismatch" + coeffs = transpose!(cartan_matrix_inv(R) * coefficients(w)) + return RootSpaceElem(R, matrix(QQ, coeffs)) +end + +function RootSpaceElem(w::WeightLatticeElem) + return RootSpaceElem(root_system(w), w) +end + function Base.:(*)(q::RationalUnion, r::RootSpaceElem) return RootSpaceElem(root_system(r), q * r.vec) end @@ -560,6 +586,10 @@ end # ############################################################################### +function DualRootSpaceElem(root_system::RootSystem, vec::Vector{<:RationalUnion}) + return DualRootSpaceElem(root_system, matrix(QQ, 1, length(vec), vec)) +end + function Base.:(*)(q::RationalUnion, r::DualRootSpaceElem) return DualRootSpaceElem(root_system(r), q * r.vec) end @@ -697,6 +727,26 @@ end # ############################################################################### +@doc raw""" + WeightLatticeElem(R::RootSystem, v::Vector{IntegerUnion}) -> WeightLatticeElem + +Return the weight defined by the coefficients `v` of the fundamental weights with respect to the root system `R`. +""" +function WeightLatticeElem(R::RootSystem, v::Vector{<:IntegerUnion}) + return WeightLatticeElem(R, matrix(ZZ, rank(R), 1, v)) +end + +function WeightLatticeElem(R::RootSystem, r::RootSpaceElem) + @req root_system(r) === R "Root system mismatch" + coeffs = transpose!(coefficients(r) * cartan_matrix_tr(R)) + @req all(is_integer, coeffs) "RootSpaceElem does not correspond to a weight" + return WeightLatticeElem(R, matrix(ZZ, coeffs)) +end + +function WeightLatticeElem(r::RootSpaceElem) + return WeightLatticeElem(root_system(r), r) +end + function Base.:(*)(n::IntegerUnion, w::WeightLatticeElem) return WeightLatticeElem(root_system(w), n * w.vec) end diff --git a/experimental/LieAlgebras/src/Types.jl b/experimental/LieAlgebras/src/Types.jl index 05b887df77e5..7144089ed6f8 100644 --- a/experimental/LieAlgebras/src/Types.jl +++ b/experimental/LieAlgebras/src/Types.jl @@ -45,33 +45,31 @@ end mutable struct RootSpaceElem root_system::RootSystem vec::QQMatrix # the coordinate (row) vector with respect to the simple roots -end -function RootSpaceElem(root_system::RootSystem, vec::Vector{<:RationalUnion}) - return RootSpaceElem(root_system, matrix(QQ, 1, length(vec), vec)) + function RootSpaceElem(root_system::RootSystem, vec::QQMatrix) + @req size(vec) == (1, rank(root_system)) "Invalid dimension" + return new(root_system, vec) + end end mutable struct DualRootSpaceElem root_system::RootSystem vec::QQMatrix # the coordinate (row) vector with respect to the simple coroots -end -function DualRootSpaceElem(root_system::RootSystem, vec::Vector{<:RationalUnion}) - return DualRootSpaceElem(root_system, matrix(QQ, 1, length(vec), vec)) + function DualRootSpaceElem(root_system::RootSystem, vec::QQMatrix) + @req size(vec) == (1, rank(root_system)) "Invalid dimension" + return new(root_system, vec) + end end mutable struct WeightLatticeElem root_system::RootSystem vec::ZZMatrix # the coordinate (column) vector with respect to the fundamental weights -end - -@doc raw""" - WeightLatticeElem(R::RootSystem, v::Vector{IntegerUnion}) -> WeightLatticeElem -Return the weight defined by the coefficients `v` of the fundamental weights with respect to the root system `R`. -""" -function WeightLatticeElem(R::RootSystem, v::Vector{<:IntegerUnion}) - return WeightLatticeElem(R, matrix(ZZ, rank(R), 1, v)) + function WeightLatticeElem(root_system::RootSystem, vec::ZZMatrix) + @req size(vec) == (rank(root_system), 1) "Invalid dimension" + return new(root_system, vec) + end end ############################################################################### diff --git a/experimental/LieAlgebras/test/RootSystem-test.jl b/experimental/LieAlgebras/test/RootSystem-test.jl index e047d7ceb39c..3c894181f54a 100644 --- a/experimental/LieAlgebras/test/RootSystem-test.jl +++ b/experimental/LieAlgebras/test/RootSystem-test.jl @@ -70,6 +70,7 @@ @test all(is_positive_root, simple_roots(R)) @test all(!is_negative_root, simple_roots(R)) @test all(iszero, positive_roots(R) + negative_roots(R)) + @test all(r -> r == RootSpaceElem(WeightLatticeElem(r)), simple_roots(R)) n_roots(R) >= 1 && for _ in 1:10 r = root(R, rand(1:n_roots(R))) w = rand(W) @@ -121,6 +122,11 @@ 2, 1:n_roots(R), ) + + @test length(fundamental_weights(R)) == rank(R) + @test all(i -> fundamental_weight(R, i) == fundamental_weights(R)[i], 1:rk) + @test all(w -> w == WeightLatticeElem(RootSpaceElem(w)), fundamental_weights(R)) + end @testset "Serialization" begin @@ -231,4 +237,38 @@ @test root_system(w) === R end + + @testset "Root/weight conversion" begin + let R = root_system(:A, 2) # from Hum72, Ch. 13.1 + @test WeightLatticeElem(simple_root(R, 1)) == WeightLatticeElem(R, [2, -1]) + @test WeightLatticeElem(simple_root(R, 2)) == WeightLatticeElem(R, [-1, 2]) + @test RootSpaceElem(fundamental_weight(R, 1)) == RootSpaceElem(R, (1//3) .* [2, 1]) + @test RootSpaceElem(fundamental_weight(R, 2)) == RootSpaceElem(R, (1//3) .* [1, 2]) + end + + let R = root_system(:E, 6) # from Hum72, Ch. 13.1, Table 1 + @test RootSpaceElem(fundamental_weight(R, 1)) == + RootSpaceElem(R, (1//3) .* [4, 3, 5, 6, 4, 2]) + @test RootSpaceElem(fundamental_weight(R, 2)) == RootSpaceElem(R, [1, 2, 2, 3, 2, 1]) + @test RootSpaceElem(fundamental_weight(R, 3)) == + RootSpaceElem(R, (1//3) .* [5, 6, 10, 12, 8, 4]) + @test RootSpaceElem(fundamental_weight(R, 4)) == RootSpaceElem(R, [2, 3, 4, 6, 4, 2]) + @test RootSpaceElem(fundamental_weight(R, 5)) == + RootSpaceElem(R, (1//3) .* [4, 6, 8, 12, 10, 5]) + @test RootSpaceElem(fundamental_weight(R, 6)) == + RootSpaceElem(R, (1//3) .* [2, 3, 4, 6, 5, 4]) + end + + let R = root_system(:F, 4) # from Hum72, Ch. 13.1, Table 1 + @test RootSpaceElem(fundamental_weight(R, 1)) == RootSpaceElem(R, [2, 3, 4, 2]) + @test RootSpaceElem(fundamental_weight(R, 2)) == RootSpaceElem(R, [3, 6, 8, 4]) + @test RootSpaceElem(fundamental_weight(R, 3)) == RootSpaceElem(R, [2, 4, 6, 3]) + @test RootSpaceElem(fundamental_weight(R, 4)) == RootSpaceElem(R, [1, 2, 3, 2]) + end + + let R = root_system(:G, 2) # from Hum72, Ch. 13.1, Table 1 + @test RootSpaceElem(fundamental_weight(R, 1)) == RootSpaceElem(R, [2, 1]) + @test RootSpaceElem(fundamental_weight(R, 2)) == RootSpaceElem(R, [3, 2]) + end + end end From 1c04c5832e3a7ec2606044e3b749932e7382dc55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Mon, 26 Aug 2024 15:07:03 +0200 Subject: [PATCH 03/18] Allow arithmetics between roots and weights --- experimental/LieAlgebras/src/RootSystem.jl | 48 ++++++++++++++++------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/experimental/LieAlgebras/src/RootSystem.jl b/experimental/LieAlgebras/src/RootSystem.jl index 02f1115d8687..0c8e14cb9101 100644 --- a/experimental/LieAlgebras/src/RootSystem.jl +++ b/experimental/LieAlgebras/src/RootSystem.jl @@ -432,23 +432,23 @@ function RootSpaceElem(w::WeightLatticeElem) return RootSpaceElem(root_system(w), w) end -function Base.:(*)(q::RationalUnion, r::RootSpaceElem) +function Base.:*(q::RationalUnion, r::RootSpaceElem) return RootSpaceElem(root_system(r), q * r.vec) end -function Base.:(+)(r::RootSpaceElem, r2::RootSpaceElem) +function Base.:+(r::RootSpaceElem, r2::RootSpaceElem) @req root_system(r) === root_system(r2) "parent root system mismatch" return RootSpaceElem(root_system(r), r.vec + r2.vec) end -function Base.:(-)(r::RootSpaceElem, r2::RootSpaceElem) +function Base.:-(r::RootSpaceElem, r2::RootSpaceElem) @req root_system(r) === root_system(r2) "parent root system mismatch" return RootSpaceElem(root_system(r), r.vec - r2.vec) end -function Base.:(-)(r::RootSpaceElem) +function Base.:-(r::RootSpaceElem) return RootSpaceElem(root_system(r), -r.vec) end @@ -590,23 +590,23 @@ function DualRootSpaceElem(root_system::RootSystem, vec::Vector{<:RationalUnion} return DualRootSpaceElem(root_system, matrix(QQ, 1, length(vec), vec)) end -function Base.:(*)(q::RationalUnion, r::DualRootSpaceElem) +function Base.:*(q::RationalUnion, r::DualRootSpaceElem) return DualRootSpaceElem(root_system(r), q * r.vec) end -function Base.:(+)(r::DualRootSpaceElem, r2::DualRootSpaceElem) +function Base.:+(r::DualRootSpaceElem, r2::DualRootSpaceElem) @req root_system(r) === root_system(r2) "parent root system mismatch" return DualRootSpaceElem(root_system(r), r.vec + r2.vec) end -function Base.:(-)(r::DualRootSpaceElem, r2::DualRootSpaceElem) +function Base.:-(r::DualRootSpaceElem, r2::DualRootSpaceElem) @req root_system(r) === root_system(r2) "parent root system mismatch" return DualRootSpaceElem(root_system(r), r.vec - r2.vec) end -function Base.:(-)(r::DualRootSpaceElem) +function Base.:-(r::DualRootSpaceElem) return DualRootSpaceElem(root_system(r), -r.vec) end @@ -747,23 +747,23 @@ function WeightLatticeElem(r::RootSpaceElem) return WeightLatticeElem(root_system(r), r) end -function Base.:(*)(n::IntegerUnion, w::WeightLatticeElem) +function Base.:*(n::IntegerUnion, w::WeightLatticeElem) return WeightLatticeElem(root_system(w), n * w.vec) end -function Base.:(+)(w::WeightLatticeElem, w2::WeightLatticeElem) +function Base.:+(w::WeightLatticeElem, w2::WeightLatticeElem) @req root_system(w) === root_system(w2) "parent weight lattics mismatch" return WeightLatticeElem(root_system(w), w.vec + w2.vec) end -function Base.:(-)(w::WeightLatticeElem, w2::WeightLatticeElem) +function Base.:-(w::WeightLatticeElem, w2::WeightLatticeElem) @req root_system(w) === root_system(w2) "parent weight lattics mismatch" return WeightLatticeElem(root_system(w), w.vec - w2.vec) end -function Base.:(-)(w::WeightLatticeElem) +function Base.:-(w::WeightLatticeElem) return WeightLatticeElem(root_system(w), -w.vec) end @@ -905,6 +905,30 @@ end ############################################################################### # more functions +function Base.:+(r::RootSpaceElem, w::WeightLatticeElem) + @req root_system(r) === root_system(w) "parent root system mismatch" + + return WeightLatticeElem(r) + w +end + +function Base.:+(w::WeightLatticeElem, r::RootSpaceElem) + @req root_system(w) === root_system(r) "parent root system mismatch" + + return w + WeightLatticeElem(r) +end + +function Base.:-(r::RootSpaceElem, w::WeightLatticeElem) + @req root_system(r) === root_system(w) "parent root system mismatch" + + return WeightLatticeElem(r) - w +end + +function Base.:-(w::WeightLatticeElem, r::RootSpaceElem) + @req root_system(w) === root_system(r) "parent root system mismatch" + + return w - WeightLatticeElem(r) +end + function dot(r::RootSpaceElem, w::WeightLatticeElem) @req root_system(r) === root_system(w) "parent root system mismatch" From d8720f99e9878481afef4d3211f46bde53cbcb1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Mon, 26 Aug 2024 15:07:30 +0200 Subject: [PATCH 04/18] Add `dot(::WeightLatticeElem, ::WeightLatticeElem)` with tests --- experimental/LieAlgebras/src/RootSystem.jl | 21 +++++++--- .../LieAlgebras/test/RootSystem-test.jl | 41 ++++++++++++++++++- 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/experimental/LieAlgebras/src/RootSystem.jl b/experimental/LieAlgebras/src/RootSystem.jl index 0c8e14cb9101..f2e3e6f62efd 100644 --- a/experimental/LieAlgebras/src/RootSystem.jl +++ b/experimental/LieAlgebras/src/RootSystem.jl @@ -104,6 +104,10 @@ end return cartan_symmetrizer(cartan_matrix(R); check=false) end +@attr ZZMatrix function _cartan_symmetrizer_mat(R::RootSystem) + return diagonal_matrix(cartan_symmetrizer(R)) +end + @doc raw""" coroot(R::RootSystem, i::Int) -> RootSpaceElem @@ -866,6 +870,15 @@ function conjugate_dominant_weight_with_elem(w::WeightLatticeElem) return wt, weyl_group(R)(reverse!(word); normalize=false) end +function dot(w1::WeightLatticeElem, w2::WeightLatticeElem) + @req root_system(w1) === root_system(w2) "parent weight lattices mismatch" + R = root_system(w1) + + return dot( + coefficients(w1), cartan_matrix_inv_tr(R) * _cartan_symmetrizer_mat(R), coefficients(w2) + ) +end + function expressify(w::WeightLatticeElem, s=:w; context=nothing) sum = Expr(:call, :+) for i in 1:length(w.vec) @@ -931,13 +944,9 @@ end function dot(r::RootSpaceElem, w::WeightLatticeElem) @req root_system(r) === root_system(w) "parent root system mismatch" + R = root_system(r) - symmetrizer = cartan_symmetrizer(root_system(r)) - return sum( - r[i] * symmetrizer[i] * w[i] for - i in 1:rank(root_system(r)); - init=zero(QQ), - ) + return dot(coefficients(r), _cartan_symmetrizer_mat(R), coefficients(w)) end function dot(w::WeightLatticeElem, r::RootSpaceElem) diff --git a/experimental/LieAlgebras/test/RootSystem-test.jl b/experimental/LieAlgebras/test/RootSystem-test.jl index 3c894181f54a..278000c23b73 100644 --- a/experimental/LieAlgebras/test/RootSystem-test.jl +++ b/experimental/LieAlgebras/test/RootSystem-test.jl @@ -126,7 +126,10 @@ @test length(fundamental_weights(R)) == rank(R) @test all(i -> fundamental_weight(R, i) == fundamental_weights(R)[i], 1:rk) @test all(w -> w == WeightLatticeElem(RootSpaceElem(w)), fundamental_weights(R)) - + @test all( + dot(simple_root(R, i), fundamental_weight(R, j)) == + (i == j ? cartan_symmetrizer(R)[i] : 0) for i in 1:rk, j in 1:rk + ) end @testset "Serialization" begin @@ -271,4 +274,40 @@ @test RootSpaceElem(fundamental_weight(R, 2)) == RootSpaceElem(R, [3, 2]) end end + + @testset "dot" begin + @testset "$Rname" for (Rname, R) in [ + ("A5", root_system(:A, 5)), + ("B3", root_system(:B, 3)), + ("D4", root_system(:D, 4)), + ("F4", root_system(:F, 4)), + ("G2", root_system(:G, 2)), + ] + R = root_system(:B, 3) + r1 = RootSpaceElem(R, rand(-10:10, 3)) + r2 = RootSpaceElem(R, rand(-10:10, 3)) + w1 = WeightLatticeElem(R, rand(-10:10, 3)) + w2 = WeightLatticeElem(R, rand(-10:10, 3)) + + result = @inferred dot(r1, r2) + @test result == @inferred dot(r1, WeightLatticeElem(r2)) + @test result == @inferred dot(WeightLatticeElem(r1), r2) + @test result == @inferred dot(WeightLatticeElem(r1), WeightLatticeElem(r2)) + + result = @inferred dot(r1, w2) + @test result == @inferred dot(r1, RootSpaceElem(w2)) + @test result == @inferred dot(WeightLatticeElem(r1), w2) + @test result == @inferred dot(WeightLatticeElem(r1), RootSpaceElem(w2)) + + result = @inferred dot(w1, r2) + @test result == @inferred dot(w1, WeightLatticeElem(r2)) + @test result == @inferred dot(RootSpaceElem(w1), r2) + @test result == @inferred dot(RootSpaceElem(w1), WeightLatticeElem(r2)) + + result = @inferred dot(w1, w2) + @test result == @inferred dot(w1, RootSpaceElem(w2)) + @test result == @inferred dot(RootSpaceElem(w1), w2) + @test result == @inferred dot(RootSpaceElem(w1), RootSpaceElem(w2)) + end + end end From 143a322a335c2984f4e21b1cc8d5906e5191c138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Mon, 26 Aug 2024 19:50:01 +0200 Subject: [PATCH 05/18] Add `dominant_weights` --- docs/oscar_references.bib | 12 ++++ .../LieAlgebras/src/LieAlgebraModule.jl | 50 +++++++++++++ experimental/LieAlgebras/src/LieAlgebras.jl | 6 ++ experimental/LieAlgebras/src/RootSystem.jl | 71 +++++++++++++++++++ 4 files changed, 139 insertions(+) diff --git a/docs/oscar_references.bib b/docs/oscar_references.bib index 21d4e03c6cb0..3e4463c66139 100644 --- a/docs/oscar_references.bib +++ b/docs/oscar_references.bib @@ -1766,6 +1766,18 @@ @Misc{MNP24 url = {https://gap-packages.github.io/tomlib/} } +@Article{MP82, + author = {Moody, R. V. and Patera, J.}, + title = {Fast recursion formula for weight multiplicities}, + journal = {Bull. Amer. Math. Soc. (N.S.)}, + fjournal = {American Mathematical Society. Bulletin. New Series}, + volume = {7}, + number = {1}, + pages = {237--242}, + year = {1982}, + doi = {10.1090/S0273-0979-1982-15021-2} +} + @Article{MR20, author = {Markwig, Thomas and Ren, Yue}, title = {Computing tropical varieties over fields with valuation}, diff --git a/experimental/LieAlgebras/src/LieAlgebraModule.jl b/experimental/LieAlgebras/src/LieAlgebraModule.jl index 6b16d2b3b1c0..c52d5bbace2b 100644 --- a/experimental/LieAlgebras/src/LieAlgebraModule.jl +++ b/experimental/LieAlgebras/src/LieAlgebraModule.jl @@ -1430,6 +1430,56 @@ function dim_of_simple_module(L::LieAlgebra, hw::Vector{<:IntegerUnion}) return dim_of_simple_module(Int, L, hw) end +@doc raw""" + dominant_weights([T,] L::LieAlgebra{C}, hw::Vector{<:IntegerUnion}) -> Vector{T} + +Computes the dominant weights occurring in the simple module of the Lie algebra `L` with highest weight `hw`, +sorted ascendingly by the total height of roots needed to reach them from `hw`. + +When supplying `T = Vector{Int}`, the weights are returned as vectors of integers. + +See [MP82](@cite) for details and the implemented algorithm. + +# Example +```jldoctest +julia> L = lie_algebra(QQ, :B, 3); + +julia> dominant_weights(L, [1, 0, 3]) +7-element Vector{Vector{Int64}}: + [1, 0, 3] + [1, 1, 1] + [2, 0, 1] + [0, 0, 3] + [0, 1, 1] + [1, 0, 1] + [0, 0, 1] +``` +""" +function dominant_weights(T::Type, L::LieAlgebra, hw::Vector{<:IntegerUnion}) + if has_root_system(L) + R = root_system(L) + return dominant_weights(T, R, hw) + else # TODO: remove branch once root system detection is implemented + @req is_dominant_weight(hw) "Not a dominant weight." + return first.( + sort!( + collect( + T(w) => d for (w, d) in + zip( + GAP.Globals.DominantWeights( + GAP.Globals.RootSystem(codomain(Oscar.iso_oscar_gap(L))), + GAP.Obj(hw; recursive=true), + )..., + ) + ); by=last) + ) + end +end + +function dominant_weights(L::LieAlgebra, hw::Vector{<:IntegerUnion}) + return dominant_weights(Vector{Int}, L, hw) +end + @doc raw""" dominant_character(L::LieAlgebra{C}, hw::Vector{Int}) -> Dict{Vector{Int}, Int} diff --git a/experimental/LieAlgebras/src/LieAlgebras.jl b/experimental/LieAlgebras/src/LieAlgebras.jl index ad7059f93341..917b4a44b0b1 100644 --- a/experimental/LieAlgebras/src/LieAlgebras.jl +++ b/experimental/LieAlgebras/src/LieAlgebras.jl @@ -110,6 +110,9 @@ function number_of_simple_roots end @alias n_roots number_of_roots @alias n_simple_roots number_of_simple_roots +# TODO: move me +export dominant_weights + include("Types.jl") include("Combinatorics.jl") include("Util.jl") @@ -140,6 +143,9 @@ include("serialization.jl") end # module LieAlgebras +# TODO: move me +export dominant_weights + using .LieAlgebras include("exports.jl") diff --git a/experimental/LieAlgebras/src/RootSystem.jl b/experimental/LieAlgebras/src/RootSystem.jl index f2e3e6f62efd..d001a9b7a328 100644 --- a/experimental/LieAlgebras/src/RootSystem.jl +++ b/experimental/LieAlgebras/src/RootSystem.jl @@ -995,6 +995,77 @@ function dim_of_simple_module(R::RootSystem, hw::WeightLatticeElem) return dim_of_simple_module(Int, R, hw) end +@doc raw""" + dominant_weights([T = WeightLatticeElem,] R::RootSystem, hw::WeightLatticeElem) -> Vector{T} + dominant_weights([T = WeightLatticeElem,] R::RootSystem, hw::Vector{<:IntegerUnion}) -> Vector{T} + +Computes the dominant weights occurring in the simple module of the Lie algebra defined by the root system `R` +with highest weight `hw`, +sorted ascendingly by the total height of roots needed to reach them from `hw`. + +When supplying `T = Vector{Int}`, the weights are returned as vectors of integers. + +See [MP82](@cite) for details and the implemented algorithm. + +# Example +```jldoctest +julia> R = root_system(:B, 3); + +julia> dominant_weights(Vector{Int}, R, [3, 0, 1]) +7-element Vector{Vector{Int64}}: + [3, 0, 1] + [1, 1, 1] + [0, 0, 3] + [2, 0, 1] + [0, 1, 1] + [1, 0, 1] + [0, 0, 1] +``` +""" +function dominant_weights(R::RootSystem, hw::WeightLatticeElem) + return dominant_weights(WeightLatticeElem, R, hw) +end + +function dominant_weights(R::RootSystem, hw::Vector{<:IntegerUnion}) + return dominant_weights(R, WeightLatticeElem(R, hw)) +end + +function dominant_weights(::Type{WeightLatticeElem}, R::RootSystem, hw::WeightLatticeElem) + @req root_system(hw) === R "parent root system mismatch" + @req is_dominant(hw) "not a dominant weight" + + pos_roots = positive_roots(R) + pos_roots_w = WeightLatticeElem.(positive_roots(R)) + + ws_with_level = Dict(hw => 0) + todo = [hw] + while !isempty(todo) + new_todo = empty(todo) + for w in todo + for (alpha, alpha_w) in zip(pos_roots, pos_roots_w) + w_sub_alpha = w - alpha_w + if is_dominant(w_sub_alpha) && !haskey(ws_with_level, w_sub_alpha) + push!(new_todo, w_sub_alpha) + push!(ws_with_level, w_sub_alpha => ws_with_level[w] + Int(height(alpha))) + end + end + end + todo = new_todo + end + return first.(sort!(collect(ws_with_level); by=last)) # order by level needed for dominant_character +end + +function dominant_weights(T::Type, R::RootSystem, hw::Vector{<:IntegerUnion}) + return dominant_weights(T, R, WeightLatticeElem(R, hw)) +end + +function dominant_weights( + T::Type{<:Vector{<:IntegerUnion}}, R::RootSystem, hw::WeightLatticeElem +) + weights = dominant_weights(WeightLatticeElem, R, hw) + return [T(_vec(coefficients(w))) for w in weights] +end + ############################################################################### # internal helpers From 73d4ea5ed3e116144aedebf57ad93a57c41ddc4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Mon, 26 Aug 2024 19:50:25 +0200 Subject: [PATCH 06/18] Typos --- experimental/LieAlgebras/src/LieAlgebraModule.jl | 4 ++-- experimental/LieAlgebras/src/RootSystem.jl | 9 +++++---- experimental/LieAlgebras/test/LieAlgebraModule-test.jl | 1 + 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/experimental/LieAlgebras/src/LieAlgebraModule.jl b/experimental/LieAlgebras/src/LieAlgebraModule.jl index c52d5bbace2b..9ad4a9516394 100644 --- a/experimental/LieAlgebras/src/LieAlgebraModule.jl +++ b/experimental/LieAlgebras/src/LieAlgebraModule.jl @@ -1398,10 +1398,10 @@ function simple_module(L::LieAlgebra, hw::Vector{Int}) end @doc raw""" - dim_of_simple_module([T = Int], L::LieAlgebra{C}, hw::Vector{<:IntegerUnion}) -> T + dim_of_simple_module([T = Int,] L::LieAlgebra{C}, hw::Vector{<:IntegerUnion}) -> T Compute the dimension of the simple module of the Lie algebra `L` with highest weight `hw` - using Weyl's dimension formula. +using Weyl's dimension formula. The return value is of type `T`. # Example diff --git a/experimental/LieAlgebras/src/RootSystem.jl b/experimental/LieAlgebras/src/RootSystem.jl index d001a9b7a328..fb36458e4874 100644 --- a/experimental/LieAlgebras/src/RootSystem.jl +++ b/experimental/LieAlgebras/src/RootSystem.jl @@ -875,7 +875,8 @@ function dot(w1::WeightLatticeElem, w2::WeightLatticeElem) R = root_system(w1) return dot( - coefficients(w1), cartan_matrix_inv_tr(R) * _cartan_symmetrizer_mat(R), coefficients(w2) + coefficients(w1), + cartan_matrix_inv_tr(R) * (_cartan_symmetrizer_mat(R) * coefficients(w2)), ) end @@ -954,7 +955,7 @@ function dot(w::WeightLatticeElem, r::RootSpaceElem) end @doc raw""" - dim_of_simple_module([T = Int], R::RootSystem, hw::WeightLatticeElem -> T + dim_of_simple_module([T = Int], R::RootSystem, hw::WeightLatticeElem) -> T dim_of_simple_module([T = Int], R::RootSystem, hw::Vector{<:IntegerUnion}) -> T Compute the dimension of the simple module of the Lie algebra defined by the root system `R` @@ -973,11 +974,11 @@ function dim_of_simple_module(T::Type, R::RootSystem, hw::WeightLatticeElem) @req root_system(hw) === R "parent root system mismatch" @req is_dominant(hw) "not a dominant weight" rho = weyl_vector(R) - hw_rho = hw + rho + hw_plus_rho = hw + rho num = one(ZZ) den = one(ZZ) for alpha in positive_roots(R) - num *= ZZ(dot(hw_rho, alpha)) + num *= ZZ(dot(hw_plus_rho, alpha)) den *= ZZ(dot(rho, alpha)) end return T(div(num, den)) diff --git a/experimental/LieAlgebras/test/LieAlgebraModule-test.jl b/experimental/LieAlgebras/test/LieAlgebraModule-test.jl index f96aa25a4510..5eb3de2a8cf4 100644 --- a/experimental/LieAlgebras/test/LieAlgebraModule-test.jl +++ b/experimental/LieAlgebras/test/LieAlgebraModule-test.jl @@ -484,6 +484,7 @@ end end end + @testset "so_n correctness regression" begin function lie_algebra_module_struct_const( L::LieAlgebra{C}, V::LieAlgebraModule{C} From 90ca8c34f2215e022bd4f06d1a6658b9168ca16e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Mon, 26 Aug 2024 19:53:43 +0200 Subject: [PATCH 07/18] Reimplement `dominant_character` --- .../LieAlgebras/src/LieAlgebraModule.jl | 27 +++-- experimental/LieAlgebras/src/RootSystem.jl | 103 +++++++++++++++++- .../LieAlgebras/test/LieAlgebraModule-test.jl | 46 +++++++- src/Groups/gsets.jl | 2 +- 4 files changed, 163 insertions(+), 15 deletions(-) diff --git a/experimental/LieAlgebras/src/LieAlgebraModule.jl b/experimental/LieAlgebras/src/LieAlgebraModule.jl index 9ad4a9516394..eb44150780af 100644 --- a/experimental/LieAlgebras/src/LieAlgebraModule.jl +++ b/experimental/LieAlgebras/src/LieAlgebraModule.jl @@ -1481,11 +1481,15 @@ function dominant_weights(L::LieAlgebra, hw::Vector{<:IntegerUnion}) end @doc raw""" - dominant_character(L::LieAlgebra{C}, hw::Vector{Int}) -> Dict{Vector{Int}, Int} + dominant_character(L::LieAlgebra{C}, hw::Vector{<:IntegerUnion}) -> Dict{Vector{Int}, Int} Computes the dominant weights occurring in the simple module of the Lie algebra `L` with highest weight `hw`, together with their multiplicities. +The return type may change in the future. + +This function uses an optimized version of the Freudenthal formula, see [MP82](@cite) for details. + # Example ```jldoctest julia> L = lie_algebra(QQ, :A, 3); @@ -1498,12 +1502,21 @@ Dict{Vector{Int64}, Int64} with 4 entries: [0, 2, 0] => 1 ``` """ -function dominant_character(L::LieAlgebra, hw::Vector{Int}) - @req is_dominant_weight(hw) "Not a dominant weight." - return Dict{Vector{Int},Int}( - Vector{Int}(w) => d for (w, d) in - zip(GAPWrap.DominantCharacter(codomain(Oscar.iso_oscar_gap(L)), GAP.Obj(hw))...) - ) +function dominant_character(L::LieAlgebra, hw::Vector{<:IntegerUnion}) + if has_root_system(L) + R = root_system(L) + return dominant_character(R, hw) + else # TODO: remove branch once root system detection is implemented + @req is_dominant_weight(hw) "Not a dominant weight." + return Dict{Vector{Int},Int}( + Vector{Int}(w) => d for (w, d) in + zip( + GAPWrap.DominantCharacter( + codomain(Oscar.iso_oscar_gap(L)), GAP.Obj(hw; recursive=true) + )..., + ) + ) + end end @doc raw""" diff --git a/experimental/LieAlgebras/src/RootSystem.jl b/experimental/LieAlgebras/src/RootSystem.jl index fb36458e4874..519c54cbcdc3 100644 --- a/experimental/LieAlgebras/src/RootSystem.jl +++ b/experimental/LieAlgebras/src/RootSystem.jl @@ -105,7 +105,7 @@ end end @attr ZZMatrix function _cartan_symmetrizer_mat(R::RootSystem) - return diagonal_matrix(cartan_symmetrizer(R)) + return diagonal_matrix(ZZ, cartan_symmetrizer(R)) end @doc raw""" @@ -1067,6 +1067,107 @@ function dominant_weights( return [T(_vec(coefficients(w))) for w in weights] end +function _action_matrices_on_weights(W::WeylGroup) + R = root_system(W) + return map(1:rank(R)) do i + x = gen(W, i) + transpose!( + matrix( + ZZ, reduce(hcat, coefficients(x * fundamental_weight(R, j)) for j in 1:rank(R)) + ), + ) + end +end + +@doc raw""" + dominant_character(R::RootSystem, hw::WeightLatticeElem) -> Dict{Vector{Int}, Int} + dominant_character(R::RootSystem, hw::Vector{<:IntegerUnion}) -> Dict{Vector{Int}, Int}} + +Computes the dominant weights occurring in the simple module of the Lie algebra defined by the root system `R` +with highest weight `hw`, together with their multiplicities. + +The return type may change in the future. + +This function uses an optimized version of the Freudenthal formula, see [MP82](@cite) for details. + +# Example +```jldoctest +julia> R = root_system(:B, 3); + +julia> dominant_character(R, [2, 0, 1]) +Dict{Vector{Int64}, Int64} with 4 entries: + [1, 0, 1] => 3 + [0, 0, 1] => 6 + [2, 0, 1] => 1 + [0, 1, 1] => 1 +``` +""" +function dominant_character(R::RootSystem, hw::WeightLatticeElem) + T = Int + @req root_system(hw) === R "parent root system mismatch" + @req is_dominant(hw) "not a dominant weight" + W = weyl_group(R) + rho = weyl_vector(R) + hw_plus_rho = hw + rho + dot_how_plus_rho = dot(hw_plus_rho, hw_plus_rho) + + pos_roots = positive_roots(R) + pos_roots_w = WeightLatticeElem.(positive_roots(R)) + pos_roots_w_coeffs = transpose.(coefficients.(pos_roots_w)) + + char = Dict(hw => T(1)) + + todo = dominant_weights(R, hw) + all_orbs = Dict{Vector{Int},Vector{Tuple{WeightLatticeElem,Int}}}() + action_matrices_on_weights = _action_matrices_on_weights(W) + + for w in Iterators.drop(todo, 1) + stab_inds = [i for (i, ci) in enumerate(coefficients(w)) if iszero(ci)] + orbs = get!(all_orbs, stab_inds) do + gens = action_matrices_on_weights[stab_inds] + push!(gens, -identity_matrix(ZZ, rank(R))) + G = matrix_group(gens) + O = orbits(gset(G, *, [pos_roots_w_coeffs; -pos_roots_w_coeffs])) + [ + ( + WeightLatticeElem( + R, + transpose(first(intersect(elements(o)::Vector{ZZMatrix}, pos_roots_w_coeffs))), + ), + length(o), + ) for o in O + ] + end + + accum = sum( + data -> begin + rep, len = data + accum2 = 0 + w_plus_i_rep = w + rep + while true + w_plus_i_rep_conj = conjugate_dominant_weight(w_plus_i_rep) + haskey(char, w_plus_i_rep_conj) || break + accum2 += char[w_plus_i_rep_conj] * dot(w_plus_i_rep, rep) + w_plus_i_rep += rep + end + len * accum2 + end, orbs; init=zero(QQ)) + if !iszero(accum) + w_plus_rho = w + rho + denom = dot_how_plus_rho - dot(w_plus_rho, w_plus_rho) + if !iszero(denom) + char[w] = T(ZZ(div(accum, denom))) + end + end + end + # return char + return Dict(Int.(_vec(coefficients(w))) => m for (w, m) in char) +end + +function dominant_character(R::RootSystem, hw::Vector{<:IntegerUnion}) + return dominant_character(R, WeightLatticeElem(R, hw)) +end + ############################################################################### # internal helpers diff --git a/experimental/LieAlgebras/test/LieAlgebraModule-test.jl b/experimental/LieAlgebras/test/LieAlgebraModule-test.jl index 5eb3de2a8cf4..2c5ee40d26b0 100644 --- a/experimental/LieAlgebras/test/LieAlgebraModule-test.jl +++ b/experimental/LieAlgebras/test/LieAlgebraModule-test.jl @@ -782,16 +782,29 @@ @testset "dominant_character" begin is_dominant_weight = Oscar.LieAlgebras.is_dominant_weight - function check_dominant_character(L::LieAlgebra, hw::Vector{Int}) - domchar = @inferred dominant_character(L, hw) - @test domchar[hw] == 1 + function check_dominant_character( + LR::Union{LieAlgebra,RootSystem}, hw::Vector{<:Oscar.IntegerUnion} + ) + domchar = @inferred dominant_character(LR, hw) + @test domchar[Int.(hw)] == 1 + @test issetequal(keys(domchar), dominant_weights(Vector{Int}, LR, hw)) @test all(w -> is_dominant_weight(w), keys(domchar)) @test all(>=(1), values(domchar)) return domchar end # All concrete test results have been computed using the LiE CAS (http://wwwmathlabo.univ-poitiers.fr/~maavl/LiE/) v2.2.2 - let L = lie_algebra(QQ, :A, 3), hw = [1, 1, 1] + let R = root_system(Tuple{Symbol,Int}[]), hw = Int[] + domchar = check_dominant_character(R, hw) + @test domchar == Dict(Int[] => 1) + end + + let L = lie_algebra(QQ, :A, 2), hw = [0, 0] + domchar = check_dominant_character(L, hw) + @test domchar == Dict([0, 0] => 1) + end + + let L = lie_algebra(QQ, :A, 3), hw = ZZ.([1, 1, 1]) domchar = check_dominant_character(L, hw) @test domchar == Dict([1, 1, 1] => 1, [2, 0, 0] => 2, [0, 0, 2] => 2, [0, 1, 0] => 4) end @@ -834,8 +847,8 @@ ) end - let L = lie_algebra(QQ, :E, 6), hw = [1, 0, 1, 0, 1, 0] - domchar = check_dominant_character(L, hw) + let R = root_system(:E, 6), hw = [1, 0, 1, 0, 1, 0] + domchar = check_dominant_character(R, hw) @test domchar == Dict( [1, 0, 1, 0, 1, 0] => 1, [0, 0, 0, 1, 1, 0] => 2, @@ -872,6 +885,27 @@ [0, 0] => 10, ) end + + let L = special_linear_lie_algebra(QQ, 2), hw = [7] # type A_1 but without known root system + domchar = check_dominant_character(L, hw) + @test domchar == Dict( + [7] => 1, + [5] => 1, + [3] => 1, + [1] => 1, + ) + end + + let L = special_orthogonal_lie_algebra(QQ, 5), hw = ZZ.([1, 2]) # type B_2 but without known root system + domchar = check_dominant_character(L, hw) + @test domchar == Dict( + [1, 2] => 1, + [2, 0] => 1, + [0, 2] => 2, + [1, 0] => 3, + [0, 0] => 3, + ) + end end @testset "character" begin diff --git a/src/Groups/gsets.jl b/src/Groups/gsets.jl index 3df318bbb371..7e902ee2e1ef 100644 --- a/src/Groups/gsets.jl +++ b/src/Groups/gsets.jl @@ -787,7 +787,7 @@ end acting_domain(Omega::GSet) = acting_group(Omega) -Base.length(Omega::GSetByElements) = length(elements(Omega)) +Base.length(Omega::GSetByElements) = length(elements(Omega))::Int Base.length(::Type{T}, Omega::GSetByElements) where T <: IntegerUnion = T(length(elements(Omega))) representative(Omega::GSetByElements) = first(Omega.seeds) From 8d46710a324da801e8df3f31829d3942fbf8df86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Tue, 27 Aug 2024 17:46:18 +0200 Subject: [PATCH 08/18] Reimplement `character` --- .../LieAlgebras/src/LieAlgebraModule.jl | 38 +++++++++------ experimental/LieAlgebras/src/RootSystem.jl | 48 +++++++++++++++++++ .../LieAlgebras/test/LieAlgebraModule-test.jl | 46 ++++++++++++++---- 3 files changed, 109 insertions(+), 23 deletions(-) diff --git a/experimental/LieAlgebras/src/LieAlgebraModule.jl b/experimental/LieAlgebras/src/LieAlgebraModule.jl index eb44150780af..1852a0f6e390 100644 --- a/experimental/LieAlgebras/src/LieAlgebraModule.jl +++ b/experimental/LieAlgebras/src/LieAlgebraModule.jl @@ -1520,10 +1520,13 @@ function dominant_character(L::LieAlgebra, hw::Vector{<:IntegerUnion}) end @doc raw""" - character(L::LieAlgebra{C}, hw::Vector{Int}) -> Dict{Vector{Int}, Int} + character(L::LieAlgebra{C}, hw::Vector{<:IntegerUnion}) -> Dict{Vector{Int}, Int} Computes all weights occurring in the simple module of the Lie algebra `L` with highest weight `hw`, together with their multiplicities. +This is achieved by acting with the Weyl group on the [`dominant_character`](@ref dominant_character(::LieAlgebra, ::Vector{<:IntegerUnion})). + +The return type may change in the future. # Example ```jldoctest @@ -1531,30 +1534,35 @@ julia> L = lie_algebra(QQ, :A, 3); julia> character(L, [2, 0, 0]) Dict{Vector{Int64}, Int64} with 10 entries: - [0, 1, 0] => 1 [0, -2, 2] => 1 + [0, 1, 0] => 1 [0, 0, -2] => 1 - [-1, 1, -1] => 1 [-2, 2, 0] => 1 + [-1, 1, -1] => 1 [1, -1, 1] => 1 - [-1, 0, 1] => 1 [1, 0, -1] => 1 - [0, -1, 0] => 1 + [-1, 0, 1] => 1 [2, 0, 0] => 1 + [0, -1, 0] => 1 ``` """ -function character(L::LieAlgebra, hw::Vector{Int}) - @req is_dominant_weight(hw) "Not a dominant weight." - dc = dominant_character(L, hw) - c = Dict{Vector{Int},Int}() - W = GAPWrap.WeylGroup(GAPWrap.RootSystem(codomain(Oscar.iso_oscar_gap(L)))) - for (w, d) in dc - it = GAPWrap.WeylOrbitIterator(W, GAP.Obj(w)) - while !GAPWrap.IsDoneIterator(it) - push!(c, Vector{Int}(GAPWrap.NextIterator(it)) => d) +function character(L::LieAlgebra, hw::Vector{<:IntegerUnion}) + if has_root_system(L) + R = root_system(L) + return character(R, hw) + else # TODO: remove branch once root system detection is implemented + @req is_dominant_weight(hw) "Not a dominant weight." + dc = dominant_character(L, hw) + c = Dict{Vector{Int},Int}() + W = GAPWrap.WeylGroup(GAPWrap.RootSystem(codomain(Oscar.iso_oscar_gap(L)))) + for (w, d) in dc + it = GAPWrap.WeylOrbitIterator(W, GAP.Obj(w)) + while !GAPWrap.IsDoneIterator(it) + push!(c, Vector{Int}(GAPWrap.NextIterator(it)) => d) + end end + return c end - return c end @doc raw""" diff --git a/experimental/LieAlgebras/src/RootSystem.jl b/experimental/LieAlgebras/src/RootSystem.jl index 519c54cbcdc3..c8e9afa83a8c 100644 --- a/experimental/LieAlgebras/src/RootSystem.jl +++ b/experimental/LieAlgebras/src/RootSystem.jl @@ -1168,6 +1168,54 @@ function dominant_character(R::RootSystem, hw::Vector{<:IntegerUnion}) return dominant_character(R, WeightLatticeElem(R, hw)) end +@doc raw""" + character(R::RootSystem, hw::WeightLatticeElem) -> Vector{T} + character(R::RootSystem, hw::Vector{<:IntegerUnion}) -> Vector{T} + +Computes all weights occurring in the simple module of the Lie algebra defined by the root system `R` +with highest weight `hw`, together with their multiplicities. +This is achieved by acting with the Weyl group on the [`dominant_character`](@ref dominant_character(::RootSystem, ::WeightLatticeElem)). + +The return type may change in the future. + +# Example +```jldoctest +julia> R = root_system(:B, 3); + +julia> character(R, [0, 0, 1]) +Dict{Vector{Int64}, Int64} with 8 entries: + [0, 1, -1] => 1 + [-1, 1, -1] => 1 + [0, 0, 1] => 1 + [1, -1, 1] => 1 + [-1, 0, 1] => 1 + [0, -1, 1] => 1 + [0, 0, -1] => 1 + [1, 0, -1] => 1 +``` +""" +function character(R::RootSystem, hw::WeightLatticeElem) + T = Int + @req root_system(hw) === R "parent root system mismatch" + @req is_dominant(hw) "not a dominant weight" + dom_char = dominant_character(R, hw) + char = Dict{WeightLatticeElem,T}() + + for (w_, m) in dom_char + w = WeightLatticeElem(R, w_) + for w_conj in weyl_orbit(w) + push!(char, w_conj => m) + end + end + + # return char + return Dict(Int.(_vec(coefficients(w))) => m for (w, m) in char) +end + +function character(R::RootSystem, hw::Vector{<:IntegerUnion}) + return character(R, WeightLatticeElem(R, hw)) +end + ############################################################################### # internal helpers diff --git a/experimental/LieAlgebras/test/LieAlgebraModule-test.jl b/experimental/LieAlgebras/test/LieAlgebraModule-test.jl index 2c5ee40d26b0..0d06bab63513 100644 --- a/experimental/LieAlgebras/test/LieAlgebraModule-test.jl +++ b/experimental/LieAlgebras/test/LieAlgebraModule-test.jl @@ -909,18 +909,30 @@ end @testset "character" begin - function check_character(L::LieAlgebra, hw::Vector{Int}) - char = @inferred character(L, hw) - @test char[hw] == 1 + function check_character( + LR::Union{LieAlgebra,RootSystem}, hw::Vector{<:Oscar.IntegerUnion} + ) + char = @inferred character(LR, hw) + @test char[Int.(hw)] == 1 @test all(>=(1), values(char)) - @test sum(values(char)) == dim_of_simple_module(L, hw) - domchar = @inferred dominant_character(L, hw) + @test sum(values(char)) == dim_of_simple_module(LR, hw) + domchar = @inferred dominant_character(LR, hw) @test all(w -> domchar[w] == char[w], keys(domchar)) return char end # All concrete test results have been computed using the LiE CAS (http://wwwmathlabo.univ-poitiers.fr/~maavl/LiE/) v2.2.2 - let L = lie_algebra(QQ, :A, 3), hw = [1, 1, 0] + let R = root_system(Tuple{Symbol,Int}[]), hw = Int[] + domchar = check_character(R, hw) + @test domchar == Dict(Int[] => 1) + end + + let L = lie_algebra(QQ, :A, 2), hw = [0, 0] + domchar = check_character(L, hw) + @test domchar == Dict([0, 0] => 1) + end + + let L = lie_algebra(QQ, :A, 3), hw = ZZ.([1, 1, 0]) char = check_character(L, hw) @test char == Dict( [1, 1, 0] => 1, @@ -946,8 +958,8 @@ char = check_character(L, hw) end - let L = lie_algebra(QQ, :D, 4), hw = [0, 3, 1, 0] - char = check_character(L, hw) + let R = root_system(:D, 4), hw = [0, 3, 1, 0] + char = check_character(R, hw) end let L = lie_algebra(QQ, :E, 6), hw = [1, 0, 1, 0, 1, 0] @@ -957,6 +969,24 @@ let L = lie_algebra(QQ, :G, 2), hw = [3, 2] char = check_character(L, hw) end + + let L = special_linear_lie_algebra(QQ, 2), hw = [7] # type A_1 but without known root system + char = check_character(L, hw) + @test char == Dict( + [7] => 1, + [5] => 1, + [3] => 1, + [1] => 1, + [-1] => 1, + [-3] => 1, + [-5] => 1, + [-7] => 1, + ) + end + + let L = special_orthogonal_lie_algebra(QQ, 5), hw = ZZ.([1, 2]) # type B_2 but without known root system + char = check_character(L, hw) + end end @testset "tensor_product_decomposition" begin From 9d281a249c27eacfc68df0950b2225e68afacd40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Wed, 28 Aug 2024 16:07:31 +0200 Subject: [PATCH 09/18] Reimplement `tensor_product_decomposition` --- .../LieAlgebras/src/LieAlgebraModule.jl | 31 ++++++--- experimental/LieAlgebras/src/RootSystem.jl | 69 +++++++++++++++++++ .../LieAlgebras/test/LieAlgebraModule-test.jl | 50 +++++++++++--- 3 files changed, 130 insertions(+), 20 deletions(-) diff --git a/experimental/LieAlgebras/src/LieAlgebraModule.jl b/experimental/LieAlgebras/src/LieAlgebraModule.jl index 1852a0f6e390..efb892152875 100644 --- a/experimental/LieAlgebras/src/LieAlgebraModule.jl +++ b/experimental/LieAlgebras/src/LieAlgebraModule.jl @@ -1566,10 +1566,13 @@ function character(L::LieAlgebra, hw::Vector{<:IntegerUnion}) end @doc raw""" - tensor_product_decomposition(L::LieAlgebra, hw1::Vector{Int}, hw2::Vector{Int}) -> MSet{Vector{Int}} + tensor_product_decomposition(L::LieAlgebra, hw1::Vector{<:IntegerUnion}, hw2::Vector{<:IntegerUnion}) -> MSet{Vector{Int}} Computes the decomposition of the tensor product of the simple modules of the Lie algebra `L` with highest weights `hw1` and `hw2` into simple modules with their multiplicities. +This function uses Klymik's formula. + +The return type may change in the future. # Example ```jldoctest @@ -1589,13 +1592,21 @@ MSet{Vector{Int64}} with 6 elements: [0, 3] ``` """ -function tensor_product_decomposition(L::LieAlgebra, hw1::Vector{Int}, hw2::Vector{Int}) - @req is_dominant_weight(hw1) && is_dominant_weight(hw2) "Both weights must be dominant." - return multiset( - Tuple{Vector{Vector{Int}},Vector{Int}}( - GAPWrap.DecomposeTensorProduct( - codomain(Oscar.iso_oscar_gap(L)), GAP.Obj(hw1), GAP.Obj(hw2) - ), - )..., - ) +function tensor_product_decomposition( + L::LieAlgebra, hw1::Vector{<:IntegerUnion}, hw2::Vector{<:IntegerUnion} +) + if has_root_system(L) + R = root_system(L) + return tensor_product_decomposition(R, hw1, hw2) + else # TODO: remove branch once root system detection is implemented + @req is_dominant_weight(hw1) && is_dominant_weight(hw2) "Both weights must be dominant." + return multiset( + Tuple{Vector{Vector{Int}},Vector{Int}}( + GAPWrap.DecomposeTensorProduct( + codomain(Oscar.iso_oscar_gap(L)), GAP.Obj(hw1; recursive=true), + GAP.Obj(hw2; recursive=true) + ), + )..., + ) + end end diff --git a/experimental/LieAlgebras/src/RootSystem.jl b/experimental/LieAlgebras/src/RootSystem.jl index c8e9afa83a8c..acf5e4e25af2 100644 --- a/experimental/LieAlgebras/src/RootSystem.jl +++ b/experimental/LieAlgebras/src/RootSystem.jl @@ -1216,6 +1216,75 @@ function character(R::RootSystem, hw::Vector{<:IntegerUnion}) return character(R, WeightLatticeElem(R, hw)) end +@doc raw""" + tensor_product_decomposition(R::RootSystem, hw1::WeightLatticeElem, hw2::WeightLatticeElem) -> MSet{Vector{Int}} + tensor_product_decomposition(R::RootSystem, hw1::Vector{<:IntegerUnion}, hw2::Vector{<:IntegerUnion}) -> MSet{Vector{Int}} + +Computes the decomposition of the tensor product of the simple modules of the Lie algebra defined by the root system `R` +with highest weights `hw1` and `hw2` into simple modules with their multiplicities. +This function uses Klymik's formula. + +The return type may change in the future. + +# Example +```jldoctest +julia> R = root_system(:B, 2); + +julia> tensor_product_decomposition(R, [1, 0], [0, 1]) +MSet{Vector{Int64}} with 2 elements: + [1, 1] + [0, 1] + +julia> tensor_product_decomposition(R, [1, 1], [1, 1]) +MSet{Vector{Int64}} with 10 elements: + [0, 0] + [0, 4] + [2, 0] + [0, 2] : 2 + [1, 0] + [2, 2] + [3, 0] + [1, 2] : 2 +``` +""" +function tensor_product_decomposition( + R::RootSystem, hw1::WeightLatticeElem, hw2::WeightLatticeElem +) + @req root_system(hw1) === R "parent root system mismatch" + @req root_system(hw2) === R "parent root system mismatch" + @req is_dominant(hw1) "not a dominant weight" + @req is_dominant(hw2) "not a dominant weight" + + W = weyl_group(R) + rho = weyl_vector(R) + + mults = multiset(WeightLatticeElem) + for (w_, m) in dominant_character(R, hw1) + for w1 in weyl_orbit(WeightLatticeElem(R, w_)) + w = w1 + hw2 + rho + w_dom, x = conjugate_dominant_weight_with_elem(w) + if all(!iszero, coefficients(w_dom)) + w_dom -= rho + coeff = m * (-1)^length(x) + push!(mults, w_dom, coeff) + end + end + end + + # return mults + return multiset( + Dict(Int.(_vec(coefficients(w))) => multiplicity(mults, w) for w in unique(mults)) + ) +end + +function tensor_product_decomposition( + R::RootSystem, hw1::Vector{<:IntegerUnion}, hw2::Vector{<:IntegerUnion} +) + return tensor_product_decomposition( + R, WeightLatticeElem(R, hw1), WeightLatticeElem(R, hw2) + ) +end + ############################################################################### # internal helpers diff --git a/experimental/LieAlgebras/test/LieAlgebraModule-test.jl b/experimental/LieAlgebras/test/LieAlgebraModule-test.jl index 0d06bab63513..705008f7144e 100644 --- a/experimental/LieAlgebras/test/LieAlgebraModule-test.jl +++ b/experimental/LieAlgebras/test/LieAlgebraModule-test.jl @@ -991,18 +991,24 @@ @testset "tensor_product_decomposition" begin function test_tensor_product_decomposition( - L::LieAlgebra, hw1::Vector{Int}, hw2::Vector{Int} + LR::Union{LieAlgebra,RootSystem}, hw1::Vector{<:Oscar.IntegerUnion}, + hw2::Vector{<:Oscar.IntegerUnion} ) - dec = @inferred tensor_product_decomposition(L, hw1, hw2) - @test dec == @inferred tensor_product_decomposition(L, hw2, hw1) - @test multiplicity(dec, hw1 + hw2) == 1 - dim_prod = dim_of_simple_module(L, hw1) * dim_of_simple_module(L, hw2) - dim_dec = sum(multiplicity(dec, w) * dim_of_simple_module(L, w) for w in unique(dec)) + dec = @inferred tensor_product_decomposition(LR, hw1, hw2) + @test dec == @inferred tensor_product_decomposition(LR, hw2, hw1) + @test multiplicity(dec, Int.(hw1 + hw2)) == 1 + dim_prod = dim_of_simple_module(LR, hw1) * dim_of_simple_module(LR, hw2) + dim_dec = sum(multiplicity(dec, w) * dim_of_simple_module(LR, w) for w in unique(dec)) @test dim_prod == dim_dec return dec end # All concrete test results have been computed using the LiE CAS (http://wwwmathlabo.univ-poitiers.fr/~maavl/LiE/) v2.2.2 + let R = root_system(Tuple{Symbol,Int}[]), hw = Int[] + dec = test_tensor_product_decomposition(R, hw, hw) + @test dec == multiset(Dict(Int[] => 1)) + end + let L = lie_algebra(QQ, :A, 3), hw1 = [2, 1, 2], hw2 = [1, 0, 1] dec = test_tensor_product_decomposition(L, hw1, hw2) @test dec == multiset( @@ -1046,7 +1052,7 @@ ) end - let L = lie_algebra(QQ, :C, 2), hw1 = [2, 2], hw2 = [2, 0] + let L = lie_algebra(QQ, :C, 2), hw1 = [2, 2], hw2 = ZZ.([2, 0]) dec = test_tensor_product_decomposition(L, hw1, hw2) @test dec == multiset( Dict( @@ -1063,16 +1069,40 @@ ) end - let L = lie_algebra(QQ, :D, 5), hw1 = [1, 1, 3, 0, 2], hw2 = [2, 1, 0, 2, 0] + let L = lie_algebra(QQ, :D, 5), hw1 = ZZ.([1, 1, 3, 0, 2]), hw2 = [2, 1, 0, 2, 0] dec = test_tensor_product_decomposition(L, hw1, hw2) end - let L = lie_algebra(QQ, :E, 6), hw1 = [1, 1, 0, 0, 1, 2], hw2 = [2, 0, 1, 1, 0, 0] + let R = root_system(:E, 6), hw1 = [1, 1, 0, 0, 1, 2], hw2 = [2, 0, 1, 1, 0, 0] + dec = test_tensor_product_decomposition(R, hw1, hw2) + end + + let R = root_system(:G, 2), hw1 = [1, 3], hw2 = [5, 2] + dec = test_tensor_product_decomposition(R, hw1, hw2) + end + + let L = special_linear_lie_algebra(QQ, 2), hw1 = [7], hw2 = [2] # type A_1 but without known root system dec = test_tensor_product_decomposition(L, hw1, hw2) + @test dec == multiset(Dict([9] => 1, + [7] => 1, + [5] => 1, + )) end - let L = lie_algebra(QQ, :G, 2), hw1 = [1, 3], hw2 = [5, 2] + let L = special_orthogonal_lie_algebra(QQ, 5), hw1 = ZZ.([1, 2]), hw2 = ZZ.([1, 1]) # type B_2 but without known root system dec = test_tensor_product_decomposition(L, hw1, hw2) + @test dec == multiset( + Dict( + [2, 3] => 1, + [3, 1] => 1, + [0, 5] => 1, + [1, 3] => 2, + [2, 1] => 2, + [0, 3] => 2, + [1, 1] => 2, + [0, 1] => 1, + ), + ) end end end From de18baa68aa8673842ba4ef22b5d3d8412beb18a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Wed, 28 Aug 2024 17:22:10 +0200 Subject: [PATCH 10/18] Optimize --- .../LieAlgebras/src/LieAlgebraModule.jl | 5 +- experimental/LieAlgebras/src/LieAlgebras.jl | 3 + experimental/LieAlgebras/src/RootSystem.jl | 60 +++++++++++++------ experimental/LieAlgebras/src/WeylGroup.jl | 2 +- .../LieAlgebras/test/LieAlgebraModule-test.jl | 5 +- 5 files changed, 52 insertions(+), 23 deletions(-) diff --git a/experimental/LieAlgebras/src/LieAlgebraModule.jl b/experimental/LieAlgebras/src/LieAlgebraModule.jl index efb892152875..000936a8029d 100644 --- a/experimental/LieAlgebras/src/LieAlgebraModule.jl +++ b/experimental/LieAlgebras/src/LieAlgebraModule.jl @@ -1603,8 +1603,9 @@ function tensor_product_decomposition( return multiset( Tuple{Vector{Vector{Int}},Vector{Int}}( GAPWrap.DecomposeTensorProduct( - codomain(Oscar.iso_oscar_gap(L)), GAP.Obj(hw1; recursive=true), - GAP.Obj(hw2; recursive=true) + codomain(Oscar.iso_oscar_gap(L)), + GAP.Obj(hw1; recursive=true), + GAP.Obj(hw2; recursive=true), ), )..., ) diff --git a/experimental/LieAlgebras/src/LieAlgebras.jl b/experimental/LieAlgebras/src/LieAlgebras.jl index 917b4a44b0b1..018a6a35d9d4 100644 --- a/experimental/LieAlgebras/src/LieAlgebras.jl +++ b/experimental/LieAlgebras/src/LieAlgebras.jl @@ -21,6 +21,7 @@ import ..Oscar: _iso_oscar_gap, _vec, action, + add!, basis_matrix, basis, canonical_injection, @@ -67,6 +68,7 @@ import ..Oscar: kernel, lower_central_series, matrix, + neg!, normalizer, number_of_generators, ngens, @@ -76,6 +78,7 @@ import ..Oscar: root, roots, sub, + sub!, symbols, symmetric_power, tensor_product, diff --git a/experimental/LieAlgebras/src/RootSystem.jl b/experimental/LieAlgebras/src/RootSystem.jl index acf5e4e25af2..e77a4c641904 100644 --- a/experimental/LieAlgebras/src/RootSystem.jl +++ b/experimental/LieAlgebras/src/RootSystem.jl @@ -771,6 +771,25 @@ function Base.:-(w::WeightLatticeElem) return WeightLatticeElem(root_system(w), -w.vec) end +function add!(wr::WeightLatticeElem, w1::WeightLatticeElem, w2::WeightLatticeElem) + add!(wr.vec, w1.vec, w2.vec) + return wr +end + +add!(w1::WeightLatticeElem, w2::WeightLatticeElem) = add!(w1, w1, w2) + +function neg!(w::WeightLatticeElem) + neg!(w.vec) + return w +end + +function sub!(wr::WeightLatticeElem, w1::WeightLatticeElem, w2::WeightLatticeElem) + sub!(wr.vec, w1.vec, w2.vec) + return wr +end + +sub!(w1::WeightLatticeElem, w2::WeightLatticeElem) = sub!(w1, w1, w2) + function Base.:(==)(w::WeightLatticeElem, w2::WeightLatticeElem) return w.root_system === w2.root_system && w.vec == w2.vec end @@ -824,22 +843,23 @@ end Return the unique dominant weight conjugate to `w`. """ function conjugate_dominant_weight(w::WeightLatticeElem) - # conj will be the dominant weight conjugate to w - conj = deepcopy(w) + return conjugate_dominant_weight!(deepcopy(w)) +end - # conj will be dominant once all fundamental weights have a positive coefficient, +function conjugate_dominant_weight!(w::WeightLatticeElem) + # w will be dominant once all fundamental weights have a positive coefficient, # so search for negative coefficients and make them positive by applying the corresponding reflection. s = 1 while s <= rank(root_system(w)) - if conj.vec[s] < 0 - reflect!(conj, s) + if w[s] < 0 + reflect!(w, s) s = 1 else s += 1 end end - return conj + return w end @doc raw""" @@ -849,16 +869,20 @@ Returns the unique dominant weight `dom` conjugate to `w` and a Weyl group eleme such that `x*w == dom`. """ function conjugate_dominant_weight_with_elem(w::WeightLatticeElem) + return conjugate_dominant_weight_with_elem!(deepcopy(w)) +end + +function conjugate_dominant_weight_with_elem!(w::WeightLatticeElem) R = root_system(w) - wt = deepcopy(w) # determine the Weyl group element taking w to the fundamental chamber - word = sizehint!(UInt8[], count(<(0), coefficients(wt))^2) + word = UInt8[] + #sizehint!(word, count(<(0), coefficients(w))^2) s = 1 while s <= rank(R) - if wt[s] < 0 + if w[s] < 0 push!(word, UInt8(s)) - reflect!(wt, s) + reflect!(w, s) s = 1 else s += 1 @@ -866,8 +890,8 @@ function conjugate_dominant_weight_with_elem(w::WeightLatticeElem) end # reversing word means it is in short revlex normal form - # and it is the element taking w to wt - return wt, weyl_group(R)(reverse!(word); normalize=false) + # and it is the element taking original w to new w + return w, weyl_group(R)(reverse!(word); normalize=false) end function dot(w1::WeightLatticeElem, w2::WeightLatticeElem) @@ -1148,7 +1172,7 @@ function dominant_character(R::RootSystem, hw::WeightLatticeElem) w_plus_i_rep_conj = conjugate_dominant_weight(w_plus_i_rep) haskey(char, w_plus_i_rep_conj) || break accum2 += char[w_plus_i_rep_conj] * dot(w_plus_i_rep, rep) - w_plus_i_rep += rep + add!(w_plus_i_rep, rep) end len * accum2 end, orbs; init=zero(QQ)) @@ -1255,16 +1279,16 @@ function tensor_product_decomposition( @req is_dominant(hw1) "not a dominant weight" @req is_dominant(hw2) "not a dominant weight" - W = weyl_group(R) rho = weyl_vector(R) + hw2_plus_rho = hw2 + rho mults = multiset(WeightLatticeElem) for (w_, m) in dominant_character(R, hw1) - for w1 in weyl_orbit(WeightLatticeElem(R, w_)) - w = w1 + hw2 + rho - w_dom, x = conjugate_dominant_weight_with_elem(w) + for w in weyl_orbit(WeightLatticeElem(R, w_)) + add!(w, hw2_plus_rho) + w_dom, x = conjugate_dominant_weight_with_elem!(w) if all(!iszero, coefficients(w_dom)) - w_dom -= rho + sub!(w_dom, rho) coeff = m * (-1)^length(x) push!(mults, w_dom, coeff) end diff --git a/experimental/LieAlgebras/src/WeylGroup.jl b/experimental/LieAlgebras/src/WeylGroup.jl index 22bd942c3d19..58c002ba490e 100644 --- a/experimental/LieAlgebras/src/WeylGroup.jl +++ b/experimental/LieAlgebras/src/WeylGroup.jl @@ -669,7 +669,7 @@ end function Base.iterate(iter::WeylOrbitIterator) (wt, _), data = iterate(iter.nocopy) # wt is already a copy, so here we don't need to make one - return wt, data + return deepcopy(wt), data end function Base.iterate(iter::WeylOrbitIterator, state::WeylIteratorNoCopyState) diff --git a/experimental/LieAlgebras/test/LieAlgebraModule-test.jl b/experimental/LieAlgebras/test/LieAlgebraModule-test.jl index 705008f7144e..28abe42dee2f 100644 --- a/experimental/LieAlgebras/test/LieAlgebraModule-test.jl +++ b/experimental/LieAlgebras/test/LieAlgebraModule-test.jl @@ -991,8 +991,9 @@ @testset "tensor_product_decomposition" begin function test_tensor_product_decomposition( - LR::Union{LieAlgebra,RootSystem}, hw1::Vector{<:Oscar.IntegerUnion}, - hw2::Vector{<:Oscar.IntegerUnion} + LR::Union{LieAlgebra,RootSystem}, + hw1::Vector{<:Oscar.IntegerUnion}, + hw2::Vector{<:Oscar.IntegerUnion}, ) dec = @inferred tensor_product_decomposition(LR, hw1, hw2) @test dec == @inferred tensor_product_decomposition(LR, hw2, hw1) From ea5aef00ea2965c6b18bf7379a9f396651604284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Wed, 28 Aug 2024 18:44:33 +0200 Subject: [PATCH 11/18] Adapt to oscar-system#4052 --- experimental/LieAlgebras/src/RootSystem.jl | 2 +- src/Groups/gsets.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/experimental/LieAlgebras/src/RootSystem.jl b/experimental/LieAlgebras/src/RootSystem.jl index e77a4c641904..117b14e1fa27 100644 --- a/experimental/LieAlgebras/src/RootSystem.jl +++ b/experimental/LieAlgebras/src/RootSystem.jl @@ -1156,7 +1156,7 @@ function dominant_character(R::RootSystem, hw::WeightLatticeElem) ( WeightLatticeElem( R, - transpose(first(intersect(elements(o)::Vector{ZZMatrix}, pos_roots_w_coeffs))), + transpose(first(intersect(elements(o), pos_roots_w_coeffs))), ), length(o), ) for o in O diff --git a/src/Groups/gsets.jl b/src/Groups/gsets.jl index 7e902ee2e1ef..3df318bbb371 100644 --- a/src/Groups/gsets.jl +++ b/src/Groups/gsets.jl @@ -787,7 +787,7 @@ end acting_domain(Omega::GSet) = acting_group(Omega) -Base.length(Omega::GSetByElements) = length(elements(Omega))::Int +Base.length(Omega::GSetByElements) = length(elements(Omega)) Base.length(::Type{T}, Omega::GSetByElements) where T <: IntegerUnion = T(length(elements(Omega))) representative(Omega::GSetByElements) = first(Omega.seeds) From ef94ec72488ba3b0bf78570e275e0b46399d20c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Fri, 30 Aug 2024 15:41:34 +0200 Subject: [PATCH 12/18] Try to make doctests deterministic --- experimental/LieAlgebras/src/LieAlgebraModule.jl | 6 +++--- experimental/LieAlgebras/src/RootSystem.jl | 12 ++++++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/experimental/LieAlgebras/src/LieAlgebraModule.jl b/experimental/LieAlgebras/src/LieAlgebraModule.jl index 000936a8029d..b12df8a5036d 100644 --- a/experimental/LieAlgebras/src/LieAlgebraModule.jl +++ b/experimental/LieAlgebras/src/LieAlgebraModule.jl @@ -1534,14 +1534,14 @@ julia> L = lie_algebra(QQ, :A, 3); julia> character(L, [2, 0, 0]) Dict{Vector{Int64}, Int64} with 10 entries: - [0, -2, 2] => 1 [0, 1, 0] => 1 + [0, -2, 2] => 1 [0, 0, -2] => 1 - [-2, 2, 0] => 1 [-1, 1, -1] => 1 + [-2, 2, 0] => 1 [1, -1, 1] => 1 - [1, 0, -1] => 1 [-1, 0, 1] => 1 + [1, 0, -1] => 1 [2, 0, 0] => 1 [0, -1, 0] => 1 ``` diff --git a/experimental/LieAlgebras/src/RootSystem.jl b/experimental/LieAlgebras/src/RootSystem.jl index 117b14e1fa27..2b059665e3cf 100644 --- a/experimental/LieAlgebras/src/RootSystem.jl +++ b/experimental/LieAlgebras/src/RootSystem.jl @@ -150,6 +150,14 @@ function fundamental_weights(R::RootSystem) return [fundamental_weight(R, i) for i in 1:rank(R)] end +function Base.hash(R::RootSystem, h::UInt) + # even though we don't have a == method for RootSystem, we add a hash method + # to make hashing of RootSpaceElem and WeightLatticeElem more deterministic + b = 0xeb5362118dea2a0e % UInt + h = hash(cartan_matrix(R), h) + return xor(b, h) +end + function is_simple(R::RootSystem) if is_finite(weyl_group(R)) return length(root_system_type(R)) == 1 @@ -1040,8 +1048,8 @@ julia> dominant_weights(Vector{Int}, R, [3, 0, 1]) 7-element Vector{Vector{Int64}}: [3, 0, 1] [1, 1, 1] - [0, 0, 3] [2, 0, 1] + [0, 0, 3] [0, 1, 1] [1, 0, 1] [0, 0, 1] @@ -1263,8 +1271,8 @@ julia> tensor_product_decomposition(R, [1, 1], [1, 1]) MSet{Vector{Int64}} with 10 elements: [0, 0] [0, 4] - [2, 0] [0, 2] : 2 + [2, 0] [1, 0] [2, 2] [3, 0] From 972c8ffbef1a0e60e16c9a717dbc2ffc40447caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Tue, 10 Sep 2024 14:11:31 +0200 Subject: [PATCH 13/18] Adapt to oscar-system/Oscar.jl#4036 --- experimental/LieAlgebras/src/LieAlgebras.jl | 6 ------ experimental/LieAlgebras/src/exports.jl | 1 + 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/experimental/LieAlgebras/src/LieAlgebras.jl b/experimental/LieAlgebras/src/LieAlgebras.jl index 018a6a35d9d4..9b264bf3ff43 100644 --- a/experimental/LieAlgebras/src/LieAlgebras.jl +++ b/experimental/LieAlgebras/src/LieAlgebras.jl @@ -113,9 +113,6 @@ function number_of_simple_roots end @alias n_roots number_of_roots @alias n_simple_roots number_of_simple_roots -# TODO: move me -export dominant_weights - include("Types.jl") include("Combinatorics.jl") include("Util.jl") @@ -146,9 +143,6 @@ include("serialization.jl") end # module LieAlgebras -# TODO: move me -export dominant_weights - using .LieAlgebras include("exports.jl") diff --git a/experimental/LieAlgebras/src/exports.jl b/experimental/LieAlgebras/src/exports.jl index 54736d1f6985..18a021ab3bff 100644 --- a/experimental/LieAlgebras/src/exports.jl +++ b/experimental/LieAlgebras/src/exports.jl @@ -38,6 +38,7 @@ export coxeter_matrix export derived_algebra export dim_of_simple_module export dominant_character +export dominant_weights export exterior_power export fundamental_weight export fundamental_weights From 47e70cc995011560d09c33b62175236950e86740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Tue, 10 Sep 2024 14:16:56 +0200 Subject: [PATCH 14/18] Update experimental/LieAlgebras/src/CoxeterGroup.jl Co-authored-by: Max Horn --- experimental/LieAlgebras/src/CoxeterGroup.jl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/experimental/LieAlgebras/src/CoxeterGroup.jl b/experimental/LieAlgebras/src/CoxeterGroup.jl index 8cf3a6aeae37..a25866d54f93 100644 --- a/experimental/LieAlgebras/src/CoxeterGroup.jl +++ b/experimental/LieAlgebras/src/CoxeterGroup.jl @@ -23,13 +23,14 @@ function coxeter_matrix_entry_from_cartan_matrix(gcm::ZZMatrix, i::Int, j::Int) return 1 end - if gcm[i, j] * gcm[j, i] == 0 + d = gcm[i, j] * gcm[j, i] + if d == 0 return 2 - elseif gcm[i, j] * gcm[j, i] == 1 + elseif d == 1 return 3 - elseif gcm[i, j] * gcm[j, i] == 2 + elseif d == 2 return 4 - elseif gcm[i, j] * gcm[j, i] == 3 + elseif d == 3 return 6 else return 0 From a3d8640806de1b7511cff923e7f167f9dec74523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Tue, 10 Sep 2024 16:14:58 +0200 Subject: [PATCH 15/18] Update experimental/LieAlgebras/src/LieAlgebraModule.jl --- experimental/LieAlgebras/src/LieAlgebraModule.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/LieAlgebras/src/LieAlgebraModule.jl b/experimental/LieAlgebras/src/LieAlgebraModule.jl index b12df8a5036d..905da45d2405 100644 --- a/experimental/LieAlgebras/src/LieAlgebraModule.jl +++ b/experimental/LieAlgebras/src/LieAlgebraModule.jl @@ -1570,7 +1570,7 @@ end Computes the decomposition of the tensor product of the simple modules of the Lie algebra `L` with highest weights `hw1` and `hw2` into simple modules with their multiplicities. -This function uses Klymik's formula. +This function uses Klimyk's formula (see [Hum72; Exercise 24.9](@cite)). The return type may change in the future. From 49f1eb5d00407541e8d622d838facc06f4e9cd10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Mon, 16 Sep 2024 11:15:05 +0200 Subject: [PATCH 16/18] Update experimental/LieAlgebras/src/WeylGroup.jl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Felix Röhrich <47457568+felix-roehrich@users.noreply.github.com> --- experimental/LieAlgebras/src/WeylGroup.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/experimental/LieAlgebras/src/WeylGroup.jl b/experimental/LieAlgebras/src/WeylGroup.jl index 58c002ba490e..821fe43e161e 100644 --- a/experimental/LieAlgebras/src/WeylGroup.jl +++ b/experimental/LieAlgebras/src/WeylGroup.jl @@ -668,7 +668,6 @@ end function Base.iterate(iter::WeylOrbitIterator) (wt, _), data = iterate(iter.nocopy) - # wt is already a copy, so here we don't need to make one return deepcopy(wt), data end From 1f6ba6d48da73f4909fcb144848321431fb51dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Mon, 16 Sep 2024 11:15:12 +0200 Subject: [PATCH 17/18] Update experimental/LieAlgebras/src/LieAlgebraModule.jl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Felix Röhrich <47457568+felix-roehrich@users.noreply.github.com> --- experimental/LieAlgebras/src/LieAlgebraModule.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/LieAlgebras/src/LieAlgebraModule.jl b/experimental/LieAlgebras/src/LieAlgebraModule.jl index 905da45d2405..562c86122eb6 100644 --- a/experimental/LieAlgebras/src/LieAlgebraModule.jl +++ b/experimental/LieAlgebras/src/LieAlgebraModule.jl @@ -1398,7 +1398,7 @@ function simple_module(L::LieAlgebra, hw::Vector{Int}) end @doc raw""" - dim_of_simple_module([T = Int,] L::LieAlgebra{C}, hw::Vector{<:IntegerUnion}) -> T + dim_of_simple_module([T = Int], L::LieAlgebra{C}, hw::Vector{<:IntegerUnion}) -> T Compute the dimension of the simple module of the Lie algebra `L` with highest weight `hw` using Weyl's dimension formula. From e7611d5d1640bb01c61129a66bcfbefae9f00746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Mon, 16 Sep 2024 13:31:48 +0200 Subject: [PATCH 18/18] Remove unneeded arithmetics --- experimental/LieAlgebras/src/RootSystem.jl | 24 ---------------------- 1 file changed, 24 deletions(-) diff --git a/experimental/LieAlgebras/src/RootSystem.jl b/experimental/LieAlgebras/src/RootSystem.jl index 2b059665e3cf..170a1b8f855c 100644 --- a/experimental/LieAlgebras/src/RootSystem.jl +++ b/experimental/LieAlgebras/src/RootSystem.jl @@ -951,30 +951,6 @@ end ############################################################################### # more functions -function Base.:+(r::RootSpaceElem, w::WeightLatticeElem) - @req root_system(r) === root_system(w) "parent root system mismatch" - - return WeightLatticeElem(r) + w -end - -function Base.:+(w::WeightLatticeElem, r::RootSpaceElem) - @req root_system(w) === root_system(r) "parent root system mismatch" - - return w + WeightLatticeElem(r) -end - -function Base.:-(r::RootSpaceElem, w::WeightLatticeElem) - @req root_system(r) === root_system(w) "parent root system mismatch" - - return WeightLatticeElem(r) - w -end - -function Base.:-(w::WeightLatticeElem, r::RootSpaceElem) - @req root_system(w) === root_system(r) "parent root system mismatch" - - return w - WeightLatticeElem(r) -end - function dot(r::RootSpaceElem, w::WeightLatticeElem) @req root_system(r) === root_system(w) "parent root system mismatch" R = root_system(r)