diff --git a/experimental/BasisLieHighestWeight/src/MainAlgorithm.jl b/experimental/BasisLieHighestWeight/src/MainAlgorithm.jl index 889fc3ae0161..c212095c24b8 100644 --- a/experimental/BasisLieHighestWeight/src/MainAlgorithm.jl +++ b/experimental/BasisLieHighestWeight/src/MainAlgorithm.jl @@ -43,7 +43,7 @@ function basis_lie_highest_weight_compute( # save computations from recursions calc_highest_weight = Dict{WeightLatticeElem,Set{ZZMPolyRingElem}}( - zero(WeightLatticeElem, R) => Set([ZZx(1)]) + zero(weight_lattice(R)) => Set([ZZx(1)]) ) # save all highest weights, for which the Minkowski-sum did not suffice to gain all monomials no_minkowski = Set{WeightLatticeElem}() @@ -98,7 +98,7 @@ function basis_coordinate_ring_kodaira_compute( # save computations from recursions calc_highest_weight = Dict{WeightLatticeElem,Set{ZZMPolyRingElem}}( - zero(WeightLatticeElem, R) => Set([ZZx(1)]) + zero(weight_lattice(R)) => Set([ZZx(1)]) ) # save all highest weights, for which the Minkowski-sum did not suffice to gain all monomials @@ -362,12 +362,12 @@ function add_by_hand( matrices_of_operators = tensor_matrices_of_operators( L, highest_weight, operators_as_roots(birational_seq) ) - space = Dict(zero(WeightLatticeElem, R) => sparse_matrix(QQ)) # span of basis vectors to keep track of the basis + space = Dict(zero(weight_lattice(R)) => sparse_matrix(QQ)) # span of basis vectors to keep track of the basis v0 = sparse_row(ZZ, [(1, 1)]) # starting vector v push!(basis, ZZx(1)) # required monomials of each weightspace - weightspaces = _character(R, highest_weight) + weightspaces = Dict{WeightLatticeElem,Int}(_character(R, highest_weight)) # sort the monomials from the minkowski-sum by their weightspaces monomials_in_weightspace = Dict{WeightLatticeElem,Set{ZZMPolyRingElem}}() for (weight_w, _) in weightspaces diff --git a/experimental/BasisLieHighestWeight/test/MainAlgorithm-test.jl b/experimental/BasisLieHighestWeight/test/MainAlgorithm-test.jl index b5c9a0d8a9b2..0ce680f95bcb 100644 --- a/experimental/BasisLieHighestWeight/test/MainAlgorithm-test.jl +++ b/experimental/BasisLieHighestWeight/test/MainAlgorithm-test.jl @@ -36,7 +36,7 @@ end sub_weights_proper = BasisLieHighestWeight.sub_weights_proper R = root_system(:B, 3) - w_zero = zero(WeightLatticeElem, R) + w_zero = zero(weight_lattice(R)) @test issetequal(sub_weights(w_zero), [w_zero]) @test isempty(sub_weights_proper(w_zero)) diff --git a/experimental/LieAlgebras/docs/doc.main b/experimental/LieAlgebras/docs/doc.main index 50f30650ee38..403ab988c8fc 100644 --- a/experimental/LieAlgebras/docs/doc.main +++ b/experimental/LieAlgebras/docs/doc.main @@ -8,6 +8,7 @@ "module_homs.md", "cartan_matrix.md", "root_systems.md", + "weight_lattices.md", "weyl_groups.md", ], ] diff --git a/experimental/LieAlgebras/docs/src/root_systems.md b/experimental/LieAlgebras/docs/src/root_systems.md index e61c7f80cef5..1449e39eac3a 100644 --- a/experimental/LieAlgebras/docs/src/root_systems.md +++ b/experimental/LieAlgebras/docs/src/root_systems.md @@ -10,8 +10,7 @@ Root systems in this module are meant to be abstract root systems, i.e. they are The relevant types around root systems are: - `RootSystem` for the root system itself, - `RootSpaceElem` for elements in the root space, i.e. roots and linear combinations thereof, -- `DualRootSpaceElem` for elements in the dual root space, i.e. coroots and linear combinations thereof, -- `WeightLatticeElem` for elements in the weight lattice, i.e. weights and linear combinations thereof. +- `DualRootSpaceElem` for elements in the dual root space, i.e. coroots and linear combinations thereof. !!! warning Most functionality around root systems is currently only intended to be used with root systems of finite type. @@ -46,6 +45,7 @@ rank(::RootSystem) cartan_matrix(::RootSystem) ``` ```@docs; canonical=false +weight_lattice(::RootSystem) weyl_group(::RootSystem) ``` @@ -180,44 +180,3 @@ is_positive_coroot_with_index(::DualRootSpaceElem) is_negative_coroot(::DualRootSpaceElem) is_negative_coroot_with_index(::DualRootSpaceElem) ``` - - -## Weight lattice elements - -```@docs -WeightLatticeElem(::RootSystem, ::Vector{<:IntegerUnion}) -WeightLatticeElem(::RootSystem, ::ZZMatrix) -WeightLatticeElem(::RootSpaceElem) -zero(::Type{WeightLatticeElem}, ::RootSystem) -``` - -```@docs -root_system(::WeightLatticeElem) -``` - -Basic arithmetic operations like `zero`, `+`, `-`, `*` (with integer scalars), and `==` are supported. - -```@docs -coeff(::WeightLatticeElem, ::Int) -coefficients(::WeightLatticeElem) -``` - -```@docs -iszero(::WeightLatticeElem) -is_dominant(::WeightLatticeElem) -is_fundamental_weight(::WeightLatticeElem) -is_fundamental_weight_with_index(::WeightLatticeElem) -``` - -### Reflections -```@docs -reflect(::WeightLatticeElem, ::Int) -reflect!(::WeightLatticeElem, ::Int) -``` - -### Conjugate dominant weight -```@docs -conjugate_dominant_weight(::WeightLatticeElem) -conjugate_dominant_weight_with_left_elem(::WeightLatticeElem) -conjugate_dominant_weight_with_right_elem(::WeightLatticeElem) -``` diff --git a/experimental/LieAlgebras/docs/src/weight_lattices.md b/experimental/LieAlgebras/docs/src/weight_lattices.md new file mode 100644 index 000000000000..20f373d770d8 --- /dev/null +++ b/experimental/LieAlgebras/docs/src/weight_lattices.md @@ -0,0 +1,71 @@ +```@meta +CurrentModule = Oscar +DocTestSetup = Oscar.doctestsetup() +``` + +# Weight lattices + +TODO + + +## Table of contents + +```@contents +Pages = ["weight_lattices.md"] +Depth = 2:5 +``` + +## Constructing weight lattices + +TODO + + + +## Properties of weight lattices + +TODO + + + + +## Weight lattice elements + +```@docs +WeightLatticeElem(::WeightLattice, ::Vector{<:IntegerUnion}) +WeightLatticeElem(::RootSystem, ::Vector{<:IntegerUnion}) +WeightLatticeElem(::WeightLattice, ::ZZMatrix) +WeightLatticeElem(::RootSystem, ::ZZMatrix) +WeightLatticeElem(::RootSpaceElem) +zero(::WeightLattice) +``` + +```@docs +parent(::WeightLatticeElem) +``` + +Basic arithmetic operations like `zero`, `+`, `-`, `*` (with integer scalars), and `==` are supported. + +```@docs +coeff(::WeightLatticeElem, ::Int) +coefficients(::WeightLatticeElem) +``` + +```@docs +iszero(::WeightLatticeElem) +is_dominant(::WeightLatticeElem) +is_fundamental_weight(::WeightLatticeElem) +is_fundamental_weight_with_index(::WeightLatticeElem) +``` + +### Reflections +```@docs +reflect(::WeightLatticeElem, ::Int) +reflect!(::WeightLatticeElem, ::Int) +``` + +### Conjugate dominant weight +```@docs +conjugate_dominant_weight(::WeightLatticeElem) +conjugate_dominant_weight_with_left_elem(::WeightLatticeElem) +conjugate_dominant_weight_with_right_elem(::WeightLatticeElem) +``` diff --git a/experimental/LieAlgebras/src/LieAlgebraModule.jl b/experimental/LieAlgebras/src/LieAlgebraModule.jl index a66743167284..4139643ff14f 100644 --- a/experimental/LieAlgebras/src/LieAlgebraModule.jl +++ b/experimental/LieAlgebras/src/LieAlgebraModule.jl @@ -1454,14 +1454,14 @@ See [MP82](@cite) for details and the implemented algorithm. 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] - [0, 0, 3] - [2, 0, 1] - [0, 1, 1] - [1, 0, 1] - [0, 0, 1] +7-element Vector{WeightLatticeElem}: + w_1 + 3*w_3 + w_1 + w_2 + w_3 + 3*w_3 + 2*w_1 + w_3 + w_2 + w_3 + w_1 + w_3 + w_3 ``` """ function dominant_weights(T::Type, L::LieAlgebra, hw::Vector{<:IntegerUnion}) @@ -1470,7 +1470,8 @@ function dominant_weights(T::Type, L::LieAlgebra, hw::Vector{<:IntegerUnion}) end function dominant_weights(L::LieAlgebra, hw::Vector{<:IntegerUnion}) - return dominant_weights(Vector{Int}, L, hw) + R = root_system(L) + return dominant_weights(R, hw) end function dominant_weights(T::Type, L::LieAlgebra, hw::WeightLatticeElem) @@ -1479,7 +1480,8 @@ function dominant_weights(T::Type, L::LieAlgebra, hw::WeightLatticeElem) end function dominant_weights(L::LieAlgebra, hw::WeightLatticeElem) - return dominant_weights(Vector{Int}, L, hw) + R = root_system(L) + return dominant_weights(R, hw) end @doc raw""" @@ -1498,11 +1500,7 @@ This function uses an optimized version of the Freudenthal formula, see [MP82](@ julia> L = lie_algebra(QQ, :A, 3); julia> dominant_character(L, [2, 1, 0]) -Dict{Vector{Int64}, Int64} with 4 entries: - [2, 1, 0] => 1 - [1, 0, 1] => 2 - [0, 0, 0] => 3 - [0, 2, 0] => 1 +3*e(0) + e(2*w_1 + w_2) + e(2*w_2) + 2*e(w_1 + w_3) ``` """ function dominant_character(L::LieAlgebra, hw::Vector{<:IntegerUnion}) @@ -1530,17 +1528,7 @@ The return type may change in the future. 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, 0, -2] => 1 - [-1, 1, -1] => 1 - [-2, 2, 0] => 1 - [1, -1, 1] => 1 - [1, 0, -1] => 1 - [-1, 0, 1] => 1 - [0, -1, 0] => 1 - [2, 0, 0] => 1 +e(2*w_1) + e(w_2) + e(-2*w_1 + 2*w_2) + e(-2*w_2 + 2*w_3) + e(-2*w_3) + e(w_1 - w_2 + w_3) + e(-w_1 + w_3) + e(w_1 - w_3) + e(-w_1 + w_2 - w_3) + e(-w_2) ``` """ function character(L::LieAlgebra, hw::Vector{<:IntegerUnion}) diff --git a/experimental/LieAlgebras/src/LieAlgebras.jl b/experimental/LieAlgebras/src/LieAlgebras.jl index cde9d32e94b9..2c67d76806ca 100644 --- a/experimental/LieAlgebras/src/LieAlgebras.jl +++ b/experimental/LieAlgebras/src/LieAlgebras.jl @@ -59,6 +59,7 @@ import ..Oscar: inv, is_abelian, is_finite, + is_gen, is_isomorphism, is_nilpotent, is_perfect, @@ -124,6 +125,7 @@ include("Util.jl") include("CartanMatrix.jl") include("CoxeterGroup.jl") include("RootSystem.jl") +include("WeightLattice.jl") include("DynkinDiagram.jl") include("WeylGroup.jl") diff --git a/experimental/LieAlgebras/src/RootSystem.jl b/experimental/LieAlgebras/src/RootSystem.jl index 48dc0e030b83..9771beb10cf7 100644 --- a/experimental/LieAlgebras/src/RootSystem.jl +++ b/experimental/LieAlgebras/src/RootSystem.jl @@ -307,6 +307,42 @@ function set_root_system_type!( return nothing end +function character_parent_ring(R::RootSystem) + if !isdefined(R, :character_parent_ring) + R.character_parent_ring = Hecke._group_algebra( + ZZ, weight_lattice(R); sparse=true, cached=false + ) + end + return R.character_parent_ring::GroupAlgebra{ZZRingElem,WeightLattice,WeightLatticeElem} +end + +@doc raw""" + weight_lattice(R::RootSystem) -> WeightLattice + +Return the weight lattice of `R`. + +# Examples +```jldoctest +julia> weight_lattice(root_system([2 -1; -1 2])) +Weight lattice + of root system of rank 2 + of type A2 + +julia> weight_lattice(root_system(matrix(ZZ, 2, 2, [2, -1, -1, 2]); detect_type=false)) +Weight lattice + of root system of rank 2 + of unknown type + +julia> weight_lattice(root_system(matrix(ZZ, [2 -1 -2; -1 2 0; -1 0 2]))) +Weight lattice + of root system of rank 3 + of type C3 (with non-canonical ordering of simple roots) +``` +""" +function weight_lattice(R::RootSystem) + return R.weight_lattice::WeightLattice +end + @doc raw""" weyl_group(R::RootSystem) -> WeylGroup @@ -680,8 +716,7 @@ This is a more efficient version for `fundamental_weights(R)[i]`. See also: [`fundamental_weight(::RootSystem)`](@ref). """ function fundamental_weight(R::RootSystem, i::Int) - @req 1 <= i <= rank(R) "invalid index" - return WeightLatticeElem(R, matrix(ZZ, 1, rank(R), i .== 1:rank(R))) + return gen(weight_lattice(R), i) end @doc raw""" @@ -701,7 +736,7 @@ julia> fundamental_weights(root_system(:A, 2)) ``` """ function fundamental_weights(R::RootSystem) - return [fundamental_weight(R, i) for i in 1:rank(R)] + return gens(weight_lattice(R)) end @doc raw""" @@ -1406,364 +1441,6 @@ function root_system(r::DualRootSpaceElem) return r.root_system end -############################################################################### -# -# Weight lattice elements -# -############################################################################### - -@doc raw""" - WeightLatticeElem(R::RootSystem, vec::Vector{<:IntegerUnion}) -> WeightLatticeElem - -Construct a weight lattice element in the root system `R` with the given coefficients w.r.t. the fundamental weights of `R`. -""" -function WeightLatticeElem(R::RootSystem, v::Vector{<:IntegerUnion}) - return WeightLatticeElem(R, matrix(ZZ, 1, rank(R), v)) -end - -@doc raw""" - WeightLatticeElem(r::RootSpaceElem) -> WeightLatticeElem - -Construct a weight lattice element from the root space element `r`. -""" -function WeightLatticeElem(r::RootSpaceElem) - R = root_system(r) - coeffs = 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 - -@doc raw""" - zero(::Type{WeightLatticeElem}, R::RootSystem) -> WeightLatticeElem - -Return the neutral additive element in the weight lattice of `R`. -""" -function zero(::Type{WeightLatticeElem}, R::RootSystem) - return WeightLatticeElem(R, zero_matrix(ZZ, 1, rank(R))) -end - -function zero(r::WeightLatticeElem) - return zero(WeightLatticeElem, root_system(r)) -end - -function Base.:*(n::IntegerUnion, w::WeightLatticeElem) - return WeightLatticeElem(root_system(w), n * w.vec) -end - -function Base.:*(w::WeightLatticeElem, n::IntegerUnion) - return WeightLatticeElem(root_system(w), w.vec * n) -end - -function Base.:+(w::WeightLatticeElem, w2::WeightLatticeElem) - @req root_system(w) === root_system(w2) "parent root system mismatch" - - return WeightLatticeElem(root_system(w), w.vec + w2.vec) -end - -function Base.:-(w::WeightLatticeElem, w2::WeightLatticeElem) - @req root_system(w) === root_system(w2) "parent root system mismatch" - - return WeightLatticeElem(root_system(w), w.vec - w2.vec) -end - -function Base.:-(w::WeightLatticeElem) - return WeightLatticeElem(root_system(w), -w.vec) -end - -function zero!(w::WeightLatticeElem) - w.vec = zero!(w.vec) - return w -end - -function add!(wr::WeightLatticeElem, w1::WeightLatticeElem, w2::WeightLatticeElem) - @req root_system(wr) === root_system(w1) === root_system(w2) "parent root system mismatch" - wr.vec = add!(wr.vec, w1.vec, w2.vec) - return wr -end - -function neg!(wr::WeightLatticeElem, w::WeightLatticeElem) - @req root_system(wr) === root_system(w) "parent root system mismatch" - wr.vec = neg!(wr.vec, w.vec) - return wr -end - -function sub!(wr::WeightLatticeElem, w1::WeightLatticeElem, w2::WeightLatticeElem) - @req root_system(wr) === root_system(w1) === root_system(w2) "parent root system mismatch" - wr.vec = sub!(wr.vec, w1.vec, w2.vec) - return wr -end - -function mul!(wr::WeightLatticeElem, w::WeightLatticeElem, n::IntegerUnion) - @req root_system(wr) === root_system(w) "parent root system mismatch" - wr.vec = mul!(wr.vec, w.vec, n) - return wr -end - -function mul!(wr::WeightLatticeElem, n::IntegerUnion, w::WeightLatticeElem) - @req root_system(wr) === root_system(w) "parent root system mismatch" - wr.vec = mul!(wr.vec, n, w.vec) - return wr -end - -function addmul!(wr::WeightLatticeElem, w::WeightLatticeElem, n::IntegerUnion) - @req root_system(wr) === root_system(w) "parent root system mismatch" - wr.vec = addmul!(wr.vec, w.vec, n) - return wr -end - -function addmul!(wr::WeightLatticeElem, n::IntegerUnion, w::WeightLatticeElem) - @req root_system(wr) === root_system(w) "parent root system mismatch" - wr.vec = addmul!(wr.vec, n, w.vec) - return wr -end - -# ignore temp storage -addmul!(wr::WeightLatticeElem, w::WeightLatticeElem, n::IntegerUnion, t) = addmul!(wr, w, n) -addmul!(wr::WeightLatticeElem, n::IntegerUnion, w::WeightLatticeElem, t) = addmul!(wr, n, w) - -function Base.:(==)(w::WeightLatticeElem, w2::WeightLatticeElem) - return w.root_system === w2.root_system && w.vec == w2.vec -end - -function Base.deepcopy_internal(w::WeightLatticeElem, dict::IdDict) - if haskey(dict, w) - return dict[w] - end - - w2 = WeightLatticeElem(root_system(w), deepcopy_internal(w.vec, dict)) - dict[w] = w2 - return w2 -end - -function Base.hash(w::WeightLatticeElem, h::UInt) - b = 0x7b2fefadacf46f4e % UInt - h = hash(w.root_system, h) - h = hash(w.vec, h) - return xor(b, h) -end - -@doc raw""" - iszero(w::WeightLatticeElem) -> Bool - -Return whether `w` is zero. -""" -function Base.iszero(w::WeightLatticeElem) - return iszero(w.vec) -end - -@doc raw""" - coefficients(w::WeightLatticeElem) -> ZZMatrix - -Return the coefficients of the weight lattice element `w` -w.r.t. the fundamental weights as a row vector. - -!!! note - The return type may not be relied on; - we only guarantee that it is a one-dimensional iterable with `eltype` `ZZRingElem` - that can be indexed with integers. -""" -function coefficients(w::WeightLatticeElem) - return w.vec -end - -@doc raw""" - coeff(w::WeightLatticeElem, i::Int) -> ZZRingElem - -Return the coefficient of the `i`-th fundamental weight in `w`. - -This can be also accessed via `w[i]`. -""" -function coeff(w::WeightLatticeElem, i::Int) - return w.vec[i] -end - -function Base.getindex(w::WeightLatticeElem, i::Int) - return coeff(w, i) -end - -@doc raw""" - conjugate_dominant_weight(w::WeightLatticeElem) -> WeightLatticeElem - -Return the unique dominant weight conjugate to `w`. - -See also: [`conjugate_dominant_weight_with_left_elem(::WeightLatticeElem)`](@ref), [`conjugate_dominant_weight_with_right_elem(::WeightLatticeElem)`](@ref). -""" -function conjugate_dominant_weight(w::WeightLatticeElem) - return conjugate_dominant_weight!(deepcopy(w)) -end - -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 w[s] < 0 - reflect!(w, s) - s = 1 - else - s += 1 - end - end - - return w -end - -@doc raw""" - conjugate_dominant_weight_with_left_elem(w::WeightLatticeElem) -> Tuple{WeightLatticeElem, WeylGroupElem} - -Returns the unique dominant weight `dom` conjugate to `w` and a Weyl group element `x` -such that `x * w == dom`. - -See also: [`conjugate_dominant_weight_with_right_elem(::WeightLatticeElem)`](@ref). -""" -function conjugate_dominant_weight_with_left_elem(w::WeightLatticeElem) - return conjugate_dominant_weight_with_left_elem!(deepcopy(w)) -end - -function conjugate_dominant_weight_with_left_elem!(w::WeightLatticeElem) - R = root_system(w) - - # determine the Weyl group element taking w to the fundamental chamber - word = UInt8[] - #sizehint!(word, count(<(0), coefficients(w))^2) - s = 1 - while s <= rank(R) - if w[s] < 0 - push!(word, UInt8(s)) - reflect!(w, s) - s = 1 - else - s += 1 - end - end - - # reversing word means it is in short revlex normal form - # and it is the element taking original w to new w - return w, weyl_group(R)(reverse!(word); normalize=false) -end - -@doc raw""" - conjugate_dominant_weight_with_right_elem(w::WeightLatticeElem) -> Tuple{WeightLatticeElem, WeylGroupElem} - -Returns the unique dominant weight `dom` conjugate to `w` and a Weyl group element `x` -such that `w * x == dom`. - -See also: [`conjugate_dominant_weight_with_left_elem(::WeightLatticeElem)`](@ref). -""" -function conjugate_dominant_weight_with_right_elem(w::WeightLatticeElem) - return conjugate_dominant_weight_with_right_elem!(deepcopy(w)) -end - -function conjugate_dominant_weight_with_right_elem!(w::WeightLatticeElem) - w, x = conjugate_dominant_weight_with_left_elem!(w) - return w, inv(x) -end - -function dot(w1::WeightLatticeElem, w2::WeightLatticeElem) - @req root_system(w1) === root_system(w2) "parent root system mismatch" - R = root_system(w1) - - return dot( - coefficients(w1), - (coefficients(w2) * _cartan_symmetrizer_mat(R)) * cartan_matrix_inv(R), - ) -end - -function expressify(w::WeightLatticeElem; context=nothing) - if is_unicode_allowed() - return expressify(w, :ω; context) - else - return expressify(w, :w; context) - end -end - -function expressify(w::WeightLatticeElem, s; context=nothing) - sum = Expr(:call, :+) - for i in 1:length(w.vec) - push!(sum.args, Expr(:call, :*, expressify(w.vec[i]; context), "$(s)_$(i)")) - end - return sum -end -@enable_all_show_via_expressify WeightLatticeElem - -@doc raw""" - is_dominant(w::WeightLatticeElem) -> Bool - -Check if `w` is a dominant weight, i.e. if all coefficients are non-negative. -""" -function is_dominant(w::WeightLatticeElem) - return all(>=(0), coefficients(w)) -end - -@doc raw""" - is_fundamental_weight(w::WeightLatticeElem) -> Bool - -Check if `w` is a fundamental weight, i.e. exactly one coefficient is equal to 1 and all others are zero. - -See also: [`is_fundamental_weight_with_index(::WeightLatticeElem)`](@ref). -""" -function is_fundamental_weight(w::WeightLatticeElem) - fl, _ = is_fundamental_weight_with_index(w) - return fl -end - -@doc raw""" - is_fundamental_weight_with_index(w::WeightLatticeElem) -> Bool, Int - -Check if `w` is a fundamental weight and return this together with the index of the fundamental weight in [`fundamental_weights(::RootSystem)`](@ref fundamental_weights(root_system(w))). - -If `w` is not a fundamental weight, the second return value is arbitrary. - -See also: [`is_fundamental_weight(::WeightLatticeElem)`](@ref). -""" -function is_fundamental_weight_with_index(w::WeightLatticeElem) - ind = 0 - coeffs = coefficients(w) - for i in 1:size(coeffs, 2) - if is_zero_entry(coeffs, 1, i) - continue - elseif is_one(coeffs[1, i]) - ind != 0 && return false, 0 - ind = i - else - return false, 0 - end - end - return ind != 0, ind -end - -@doc raw""" - reflect(w::WeightLatticeElem, s::Int) -> WeightLatticeElem - -Return the reflection of `w` in the hyperplane orthogonal to the `s`-th simple root. - -See also: [`reflect!(::WeightLatticeElem, ::Int)`](@ref). -""" -function reflect(w::WeightLatticeElem, s::Int) - return reflect!(deepcopy(w), s) -end - -@doc raw""" - reflect!(w::WeightLatticeElem, s::Int) -> WeightLatticeElem - -Reflect `w` in the hyperplane orthogonal to the `s`-th simple root, and return it. - -This is a mutating version of [`reflect(::WeightLatticeElem, ::Int)`](@ref). -""" -function reflect!(w::WeightLatticeElem, s::Int) - w.vec = addmul!(w.vec, view(cartan_matrix_tr(root_system(w)), s:s, :), -w.vec[s]) # change to submul! once available - return w -end - -@doc raw""" - root_system(w::WeightLatticeElem) -> RootSystem - -Return the root system `w` belongs to. -""" -function root_system(w::WeightLatticeElem) - return w.root_system -end - ############################################################################### # more functions @@ -1848,15 +1525,15 @@ See [MP82](@cite) for details and the implemented algorithm. ```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] +julia> dominant_weights(R, [3, 0, 1]) +7-element Vector{WeightLatticeElem}: + 3*w_1 + w_3 + w_1 + w_2 + w_3 + 2*w_1 + w_3 + 3*w_3 + w_2 + w_3 + w_1 + w_3 + w_3 ``` """ function dominant_weights(R::RootSystem, hw::WeightLatticeElem) @@ -1929,16 +1606,11 @@ This function uses an optimized version of the Freudenthal formula, see [MP82](@ 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 +e(2*w_1 + w_3) + e(w_2 + w_3) + 3*e(w_1 + w_3) + 6*e(w_3) ``` """ function dominant_character(R::RootSystem, hw::WeightLatticeElem) - char = _dominant_character(R, hw) - return Dict(Int.(_vec(coefficients(w))) => m for (w, m) in char) + return _dominant_character(R, hw) end function dominant_character(R::RootSystem, hw::Vector{<:IntegerUnion}) @@ -1958,13 +1630,14 @@ function _dominant_character(R::RootSystem, hw::WeightLatticeElem) pos_roots_w = WeightLatticeElem.(positive_roots(R)) pos_roots_w_coeffs = coefficients.(pos_roots_w) - char = Dict(hw => T(1)) + ZP = character_parent_ring(R) + char = ZP(hw) 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) + for w in Iterators.drop(todo, 1) # drop hw as its multiplicity is 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] @@ -1989,7 +1662,7 @@ function _dominant_character(R::RootSystem, hw::WeightLatticeElem) 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 + iszero(char[w_plus_i_rep_conj]) && break accum2 += char[w_plus_i_rep_conj] * dot(w_plus_i_rep, rep) add!(w_plus_i_rep, rep) end @@ -1999,11 +1672,11 @@ function _dominant_character(R::RootSystem, hw::WeightLatticeElem) 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))) + char += ZZ(div(accum, denom)) * ZP(w) end end end - return char + return char::elem_type(ZP) end @doc raw""" @@ -2021,20 +1694,11 @@ The return type may change in the future. 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 - [1, 0, -1] => 1 - [0, 0, -1] => 1 - [0, -1, 1] => 1 +e(w_3) + e(w_2 - w_3) + e(w_1 - w_2 + w_3) + e(-w_1 + w_3) + e(w_1 - w_3) + e(-w_1 + w_2 - w_3) + e(-w_2 + w_3) + e(-w_3) ``` """ function character(R::RootSystem, hw::WeightLatticeElem) - char = _character(R, hw) - return Dict(Int.(_vec(coefficients(w))) => m for (w, m) in char) + return _character(R, hw) end function character(R::RootSystem, hw::Vector{<:IntegerUnion}) @@ -2046,11 +1710,12 @@ function _character(R::RootSystem, hw::WeightLatticeElem) @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}() + ZP = character_parent_ring(R) + char = zero(ZP) for (w, m) in dom_char for w_conj in weyl_orbit(w) - push!(char, w_conj => m) + char += m * ZP(w_conj) end end @@ -2101,13 +1766,13 @@ function tensor_product_decomposition( mults = multiset(WeightLatticeElem) for (w_, m) in dominant_character(R, hw1) - for w in weyl_orbit(WeightLatticeElem(R, w_)) + for w in weyl_orbit(w_) add!(w, hw2_plus_rho) w_dom, x = conjugate_dominant_weight_with_left_elem!(w) if all(!iszero, coefficients(w_dom)) sub!(w_dom, rho) coeff = m * (-1)^length(x) - push!(mults, w_dom, coeff) + push!(mults, w_dom, Int(coeff)) end end end @@ -2187,3 +1852,25 @@ function positive_roots_and_reflections(cartan_matrix::ZZMatrix) roots[perm], coroots[perm], table end + +# TODO: move to Hecke +function Base.length(x::GroupAlgebraElem) + @assert Hecke._is_sparse(x) + return length(x.coeffs_sparse) +end + +function Base.iterate(x::GroupAlgebraElem) + @assert Hecke._is_sparse(x) + next = iterate(x.coeffs_sparse) + isnothing(next) && return nothing + (i, c), st = next + return (parent(x).base_to_group[i], c), st +end + +function Base.iterate(x::GroupAlgebraElem, st) + @assert Hecke._is_sparse(x) + next = iterate(x.coeffs_sparse, st) + isnothing(next) && return nothing + (i, c), st = next + return (parent(x).base_to_group[i], c), st +end diff --git a/experimental/LieAlgebras/src/Types.jl b/experimental/LieAlgebras/src/Types.jl index 155637542896..b78f8ed37bfd 100644 --- a/experimental/LieAlgebras/src/Types.jl +++ b/experimental/LieAlgebras/src/Types.jl @@ -18,10 +18,12 @@ See [`root_system(::ZZMatrix)`](@ref) for the constructor. positive_coroots::Vector #::Vector{DualRootSpaceElem} (cyclic reference) positive_coroots_map::Dict{QQMatrix,Int} weyl_group::Any #::WeylGroup (cyclic reference) + weight_lattice::Any #::WeightLattice (cyclic reference) # optional: type::Vector{Tuple{Symbol,Int}} type_ordering::Vector{Int} + character_parent_ring::Any #::GroupAlgebra{ZZRingElem, WeightLattice, WeightLatticeElem} function RootSystem(mat::ZZMatrix; check::Bool=true, detect_type::Bool=true) check && @req is_cartan_matrix(mat) "Requires a generalized Cartan matrix" @@ -41,6 +43,7 @@ See [`root_system(::ZZMatrix)`](@ref) for the constructor. (ind, root) in enumerate(R.positive_coroots::Vector{DualRootSpaceElem}) ) R.weyl_group = WeylGroup(finite, refl, R) + R.weight_lattice = WeightLattice(R) detect_type && is_finite(weyl_group(R)) && assure_root_system_type(R) return R @@ -91,25 +94,44 @@ mutable struct DualRootSpaceElem end end +############################################################################### +# +# Weight lattices +# +############################################################################### + @doc raw""" - WeightLatticeElem + WeightLattice <: AbstractAlgebra.AdditiveGroup -Type for weights and linear combinations thereof. +Type for weight lattices, parent type of `WeightLatticeElem`. """ -mutable struct WeightLatticeElem +@attributes mutable struct WeightLattice <: AbstractAlgebra.AdditiveGroup root_system::RootSystem + + function WeightLattice(root_system::RootSystem) + return new(root_system) + end +end + +@doc raw""" + WeightLatticeElem <: AbstractAlgebra.AdditiveGroupElem + +Type for weights and linear combinations thereof, elem type of `WeightLattice`. +""" +mutable struct WeightLatticeElem <: AbstractAlgebra.AdditiveGroupElem + parent_lat::WeightLattice vec::ZZMatrix # the coordinate (row) vector with respect to the fundamental weights @doc raw""" - WeightLatticeElem(R::RootSystem, vec::ZZMatrix) -> WeightLatticeElem + WeightLatticeElem(P::WeightLattice, vec::ZZMatrix) -> WeightLatticeElem - Construct a weight lattice element in the root system `R` with the given coefficient vector w.r.t. the fundamental weights of `R`. + Construct a weight lattice element in `P` with the given coefficients w.r.t. the fundamental weights of corresponding root system. - `vec` must be a row vector of the same length as the rank of `R`. + `vec` must be a row vector of the same length as the rank of `P`. """ - function WeightLatticeElem(root_system::RootSystem, vec::ZZMatrix) - @req size(vec) == (1, rank(root_system)) "Invalid dimension" - return new(root_system, vec) + function WeightLatticeElem(P::WeightLattice, vec::ZZMatrix) + @req size(vec) == (1, rank(P)) "Invalid dimension" + return new(P, vec) end end diff --git a/experimental/LieAlgebras/src/WeightLattice.jl b/experimental/LieAlgebras/src/WeightLattice.jl new file mode 100644 index 000000000000..c047a8b4e863 --- /dev/null +++ b/experimental/LieAlgebras/src/WeightLattice.jl @@ -0,0 +1,437 @@ +############################################################################### +# +# Weight lattices +# +############################################################################### + +function elem_type(::Type{WeightLattice}) + return WeightLatticeElem +end + +function rank(P::WeightLattice) + return rank(root_system(P)) +end + +function root_system(P::WeightLattice) + return P.root_system +end + +function zero(P::WeightLattice) + return WeightLatticeElem(P, zero_matrix(ZZ, 1, rank(P))) +end + +function Base.show(io::IO, mime::MIME"text/plain", P::WeightLattice) + @show_name(io, P) + @show_special(io, mime, P) + io = pretty(io) + println(io, "Weight lattice") + print(io, Indent(), "of ", Lowercase()) + show(io, mime, root_system(P)) + print(io, Dedent()) +end + +function Base.show(io::IO, P::WeightLattice) + @show_name(io, P) + @show_special(io, P) + io = pretty(io) + if is_terse(io) + print(io, "Weight lattice") + else + print(io, "Weight lattice of ", Lowercase(), root_system(P)) + end +end + +function number_of_generators(P::WeightLattice) + return rank(P) +end + +function gen(P::WeightLattice, i::Int) + @req 1 <= i <= rank(P) "invalid index" + return WeightLatticeElem(P, matrix(ZZ, 1, rank(P), i .== 1:rank(P))) +end + +function gens(P::WeightLattice) + return [gen(P, i) for i in 1:rank(P)] +end + +function is_abelian(P::WeightLattice) + return true +end + +function is_finite(P::WeightLattice) + return iszero(rank(P)) +end + +############################################################################### +# +# Weight lattice elements +# +############################################################################### + +@doc raw""" + WeightLatticeElem(R::RootSystem, vec::ZZMatrix) -> WeightLatticeElem + +Construct a weight lattice element in the root system `R` with the given coefficient vector w.r.t. the fundamental weights of `R`. + +`vec` must be a row vector of the same length as the rank of `R`. +""" +function WeightLatticeElem(R::RootSystem, vec::ZZMatrix) + return WeightLatticeElem(weight_lattice(R), vec) +end + +@doc raw""" + WeightLatticeElem(R::RootSystem, vec::Vector{<:IntegerUnion}) -> WeightLatticeElem + +Construct a weight lattice element in the root system `R` with the given coefficients w.r.t. the fundamental weights of `R`. +""" +function WeightLatticeElem(R::RootSystem, v::Vector{<:IntegerUnion}) + return WeightLatticeElem(R, matrix(ZZ, 1, rank(R), v)) +end + +@doc raw""" + WeightLatticeElem(P::WeightLattice, vec::Vector{<:IntegerUnion}) -> WeightLatticeElem + +Construct a weight lattice element in `P` with the given coefficients w.r.t. the fundamental weights of corresponding root system. +""" +function WeightLatticeElem(P::WeightLattice, v::Vector{<:IntegerUnion}) + return WeightLatticeElem(P, matrix(ZZ, 1, rank(P), v)) +end + +@doc raw""" + WeightLatticeElem(r::RootSpaceElem) -> WeightLatticeElem + +Construct a weight lattice element from the root space element `r`. +""" +function WeightLatticeElem(r::RootSpaceElem) + R = root_system(r) + coeffs = 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 parent_type(::Type{WeightLatticeElem}) + return WeightLattice +end + +function parent(w::WeightLatticeElem) + return w.parent_lat +end + +function root_system(w::WeightLatticeElem) + return root_system(parent(w)) +end + +function zero(w::WeightLatticeElem) + return zero(parent(w)) +end + +function Base.:*(n::IntegerUnion, w::WeightLatticeElem) + return WeightLatticeElem(parent(w), n * w.vec) +end + +function Base.:*(w::WeightLatticeElem, n::IntegerUnion) + return WeightLatticeElem(parent(w), w.vec * n) +end + +function Base.:+(w::WeightLatticeElem, w2::WeightLatticeElem) + @req parent(w) === parent(w2) "parent mismatch" + + return WeightLatticeElem(parent(w), w.vec + w2.vec) +end + +function Base.:-(w::WeightLatticeElem, w2::WeightLatticeElem) + @req parent(w) === parent(w2) "parent mismatch" + + return WeightLatticeElem(parent(w), w.vec - w2.vec) +end + +function Base.:-(w::WeightLatticeElem) + return WeightLatticeElem(parent(w), -w.vec) +end + +function zero!(w::WeightLatticeElem) + w.vec = zero!(w.vec) + return w +end + +function add!(wr::WeightLatticeElem, w1::WeightLatticeElem, w2::WeightLatticeElem) + @req parent(wr) === parent(w1) === parent(w2) "parent mismatch" + wr.vec = add!(wr.vec, w1.vec, w2.vec) + return wr +end + +function neg!(wr::WeightLatticeElem, w::WeightLatticeElem) + @req parent(wr) === parent(w) "parent mismatch" + wr.vec = neg!(wr.vec, w.vec) + return wr +end + +function sub!(wr::WeightLatticeElem, w1::WeightLatticeElem, w2::WeightLatticeElem) + @req parent(wr) === parent(w1) === parent(w2) "parent mismatch" + wr.vec = sub!(wr.vec, w1.vec, w2.vec) + return wr +end + +function mul!(wr::WeightLatticeElem, w::WeightLatticeElem, n::IntegerUnion) + @req parent(wr) === parent(w) "parent mismatch" + wr.vec = mul!(wr.vec, w.vec, n) + return wr +end + +function mul!(wr::WeightLatticeElem, n::IntegerUnion, w::WeightLatticeElem) + @req parent(wr) === parent(w) "parent mismatch" + wr.vec = mul!(wr.vec, n, w.vec) + return wr +end + +function addmul!(wr::WeightLatticeElem, w::WeightLatticeElem, n::IntegerUnion) + @req parent(wr) === parent(w) "parent mismatch" + wr.vec = addmul!(wr.vec, w.vec, n) + return wr +end + +function addmul!(wr::WeightLatticeElem, n::IntegerUnion, w::WeightLatticeElem) + @req parent(wr) === parent(w) "parent mismatch" + wr.vec = addmul!(wr.vec, n, w.vec) + return wr +end + +# ignore temp storage +addmul!(wr::WeightLatticeElem, w::WeightLatticeElem, n::IntegerUnion, t) = addmul!(wr, w, n) +addmul!(wr::WeightLatticeElem, n::IntegerUnion, w::WeightLatticeElem, t) = addmul!(wr, n, w) + +function Base.:(==)(w1::WeightLatticeElem, w2::WeightLatticeElem) + return parent(w1) === parent(w2) && w1.vec == w2.vec +end + +function Base.deepcopy_internal(w::WeightLatticeElem, dict::IdDict) + if haskey(dict, w) + return dict[w] + end + + w2 = WeightLatticeElem(parent(w), deepcopy_internal(w.vec, dict)) + dict[w] = w2 + return w2 +end + +function Base.hash(w::WeightLatticeElem, h::UInt) + b = 0x7b2fefadacf46f4e % UInt + h = hash(parent(w), h) + h = hash(w.vec, h) + return xor(b, h) +end + +@doc raw""" + iszero(w::WeightLatticeElem) -> Bool + +Return whether `w` is zero. +""" +function Base.iszero(w::WeightLatticeElem) + return iszero(w.vec) +end + +@doc raw""" + coefficients(w::WeightLatticeElem) -> ZZMatrix + +Return the coefficients of the weight lattice element `w` +w.r.t. the fundamental weights as a row vector. + +!!! note + The return type may not be relied on; + we only guarantee that it is a one-dimensional iterable with `eltype` `ZZRingElem` + that can be indexed with integers. +""" +function coefficients(w::WeightLatticeElem) + return w.vec +end + +@doc raw""" + coeff(w::WeightLatticeElem, i::Int) -> ZZRingElem + +Return the coefficient of the `i`-th fundamental weight in `w`. + +This can be also accessed via `w[i]`. +""" +function coeff(w::WeightLatticeElem, i::Int) + return w.vec[i] +end + +function Base.getindex(w::WeightLatticeElem, i::Int) + return coeff(w, i) +end + +@doc raw""" + conjugate_dominant_weight(w::WeightLatticeElem) -> WeightLatticeElem + +Return the unique dominant weight conjugate to `w`. + +See also: [`conjugate_dominant_weight_with_left_elem(::WeightLatticeElem)`](@ref), [`conjugate_dominant_weight_with_right_elem(::WeightLatticeElem)`](@ref). +""" +function conjugate_dominant_weight(w::WeightLatticeElem) + return conjugate_dominant_weight!(deepcopy(w)) +end + +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(parent(w)) + if w[s] < 0 + reflect!(w, s) + s = 1 + else + s += 1 + end + end + + return w +end + +@doc raw""" + conjugate_dominant_weight_with_left_elem(w::WeightLatticeElem) -> Tuple{WeightLatticeElem, WeylGroupElem} + +Returns the unique dominant weight `dom` conjugate to `w` and a Weyl group element `x` +such that `x * w == dom`. + +See also: [`conjugate_dominant_weight_with_right_elem(::WeightLatticeElem)`](@ref). +""" +function conjugate_dominant_weight_with_left_elem(w::WeightLatticeElem) + return conjugate_dominant_weight_with_left_elem!(deepcopy(w)) +end + +function conjugate_dominant_weight_with_left_elem!(w::WeightLatticeElem) + # determine the Weyl group element taking w to the fundamental chamber + word = UInt8[] + #sizehint!(word, count(<(0), coefficients(w))^2) + s = 1 + while s <= rank(parent(w)) + if w[s] < 0 + push!(word, UInt8(s)) + reflect!(w, s) + s = 1 + else + s += 1 + end + end + + # reversing word means it is in short revlex normal form + # and it is the element taking original w to new w + return w, weyl_group(root_system(w))(reverse!(word); normalize=false) +end + +@doc raw""" + conjugate_dominant_weight_with_right_elem(w::WeightLatticeElem) -> Tuple{WeightLatticeElem, WeylGroupElem} + +Returns the unique dominant weight `dom` conjugate to `w` and a Weyl group element `x` +such that `w * x == dom`. + +See also: [`conjugate_dominant_weight_with_left_elem(::WeightLatticeElem)`](@ref). +""" +function conjugate_dominant_weight_with_right_elem(w::WeightLatticeElem) + return conjugate_dominant_weight_with_right_elem!(deepcopy(w)) +end + +function conjugate_dominant_weight_with_right_elem!(w::WeightLatticeElem) + w, x = conjugate_dominant_weight_with_left_elem!(w) + return w, inv(x) +end + +function dot(w1::WeightLatticeElem, w2::WeightLatticeElem) + @req parent(w1) === parent(w2) "parent mismatch" + R = root_system(w1) + + return dot( + coefficients(w1), + (coefficients(w2) * _cartan_symmetrizer_mat(R)) * cartan_matrix_inv(R), + ) +end + +function expressify(w::WeightLatticeElem; context=nothing) + if is_unicode_allowed() + return expressify(w, :ω; context) + else + return expressify(w, :w; context) + end +end + +function expressify(w::WeightLatticeElem, s; context=nothing) + sum = Expr(:call, :+) + for i in 1:length(w.vec) + push!(sum.args, Expr(:call, :*, expressify(w.vec[i]; context), "$(s)_$(i)")) + end + return sum +end +@enable_all_show_via_expressify WeightLatticeElem + +@doc raw""" + is_dominant(w::WeightLatticeElem) -> Bool + +Check if `w` is a dominant weight, i.e. if all coefficients are non-negative. +""" +function is_dominant(w::WeightLatticeElem) + return all(>=(0), coefficients(w)) +end + +@doc raw""" + is_fundamental_weight(w::WeightLatticeElem) -> Bool + +Check if `w` is a fundamental weight, i.e. exactly one coefficient is equal to 1 and all others are zero. + +See also: [`is_fundamental_weight_with_index(::WeightLatticeElem)`](@ref). +""" +function is_fundamental_weight(w::WeightLatticeElem) + fl, _ = is_fundamental_weight_with_index(w) + return fl +end + +function is_gen(w::WeightLatticeElem) + return is_fundamental_weight(w) +end + +@doc raw""" + is_fundamental_weight_with_index(w::WeightLatticeElem) -> Bool, Int + +Check if `w` is a fundamental weight and return this together with the index of the fundamental weight in [`fundamental_weights(::RootSystem)`](@ref fundamental_weights(root_system(w))). + +If `w` is not a fundamental weight, the second return value is arbitrary. + +See also: [`is_fundamental_weight(::WeightLatticeElem)`](@ref). +""" +function is_fundamental_weight_with_index(w::WeightLatticeElem) + ind = 0 + coeffs = coefficients(w) + for i in 1:size(coeffs, 2) + if is_zero_entry(coeffs, 1, i) + continue + elseif is_one(coeffs[1, i]) + ind != 0 && return false, 0 + ind = i + else + return false, 0 + end + end + return ind != 0, ind +end + +@doc raw""" + reflect(w::WeightLatticeElem, s::Int) -> WeightLatticeElem + +Return the reflection of `w` in the hyperplane orthogonal to the `s`-th simple root. + +See also: [`reflect!(::WeightLatticeElem, ::Int)`](@ref). +""" +function reflect(w::WeightLatticeElem, s::Int) + return reflect!(deepcopy(w), s) +end + +@doc raw""" + reflect!(w::WeightLatticeElem, s::Int) -> WeightLatticeElem + +Reflect `w` in the hyperplane orthogonal to the `s`-th simple root, and return it. + +This is a mutating version of [`reflect(::WeightLatticeElem, ::Int)`](@ref). +""" +function reflect!(w::WeightLatticeElem, s::Int) + w.vec = addmul!(w.vec, view(cartan_matrix_tr(root_system(w)), s:s, :), -w.vec[s]) # change to submul! once available + return w +end diff --git a/experimental/LieAlgebras/src/WeylGroup.jl b/experimental/LieAlgebras/src/WeylGroup.jl index 6683f177baf9..ba6e6fb7252d 100644 --- a/experimental/LieAlgebras/src/WeylGroup.jl +++ b/experimental/LieAlgebras/src/WeylGroup.jl @@ -722,7 +722,6 @@ end function _iterate_nocopy(state::WeylIteratorNoCopyState) wt, path = state[1], word(state[2]) - R = root_system(wt) ai = isempty(path) ? UInt8(0) : path[end] # compute next descendant index @@ -748,7 +747,7 @@ end # based on [Ste01], 4.D function next_descendant_index(ai::Int, di::Int, wt::WeightLatticeElem) if iszero(ai) - for j in (di + 1):rank(root_system(wt)) + for j in (di + 1):rank(parent(wt)) if !iszero(wt[j]) return j end @@ -762,7 +761,7 @@ function next_descendant_index(ai::Int, di::Int, wt::WeightLatticeElem) end end - for j in (max(ai, di) + 1):rank(root_system(wt)) + for j in (max(ai, di) + 1):rank(parent(wt)) if is_zero_entry(cartan_matrix(root_system(wt)), ai, j) continue end diff --git a/experimental/LieAlgebras/src/exports.jl b/experimental/LieAlgebras/src/exports.jl index 9f88d9cd6c11..ebbfed26fc4f 100644 --- a/experimental/LieAlgebras/src/exports.jl +++ b/experimental/LieAlgebras/src/exports.jl @@ -14,7 +14,7 @@ export LieSubalgebra export LinearLieAlgebra, LinearLieAlgebraElem export RootSpaceElem export RootSystem -export WeightLatticeElem +export WeightLattice, WeightLatticeElem export WeylGroup, WeylGroupElem export WeylOrbitIterator @@ -110,6 +110,7 @@ export tensor_power export tensor_product_decomposition export trivial_module export universal_enveloping_algebra +export weight_lattice export weyl_group export weyl_orbit export word diff --git a/experimental/LieAlgebras/test/RootSystem-test.jl b/experimental/LieAlgebras/test/RootSystem-test.jl index 4a4bca04ab5b..51b72df8b162 100644 --- a/experimental/LieAlgebras/test/RootSystem-test.jl +++ b/experimental/LieAlgebras/test/RootSystem-test.jl @@ -1,25 +1,4 @@ @testset "LieAlgebras.RootSystem" begin - @testset "conjugate_dominant_weight_with_*_elem(w::WeightLatticeElem)" begin - for (R, vec) in [ - (root_system(:A, 5), [1, -1, 2, 0, 2]), - (root_system(:B, 3), [1, 1, 1]), - (root_system(:C, 4), [2, 1, 0, 1]), - (root_system(:D, 5), [-1, 2, 2, -1, -1]), - (root_system(:E, 6), [1, 2, 0, 0, 2, 1]), - (root_system(:F, 4), [1, 2, 3, 4]), - (root_system(:G, 2), [-1, -1]), - ] - wt = WeightLatticeElem(R, vec) - d, x = conjugate_dominant_weight_with_left_elem(wt) - @test is_dominant(d) - @test x * wt == d - - d, x = conjugate_dominant_weight_with_right_elem(wt) - @test is_dominant(d) - @test wt * x == d - end - end - @testset "root_system(cartan_matrix::ZZMatrix)" begin R = root_system(:F, 4) @test n_positive_roots(R) == 24 @@ -139,9 +118,9 @@ is_fundamental_weight_with_index(w) == (true, i) for (i, w) in enumerate(fundamental_weights(R)) ) - @test !is_fundamental_weight(zero(WeightLatticeElem, R)) + @test !is_fundamental_weight(zero(weight_lattice(R))) rk != 1 && @test !is_fundamental_weight( - sum(fundamental_weights(R); init=zero(WeightLatticeElem, R)) + sum(fundamental_weights(R); init=zero(weight_lattice(R))) ) @test all( dot(simple_root(R, i), fundamental_weight(R, j)) == @@ -279,13 +258,6 @@ end end - @testset "WeightLatticeElem" begin - R = root_system(:A, 2) - w = WeightLatticeElem(R, [2, 2]) - - @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]) diff --git a/experimental/LieAlgebras/test/WeightLattice-test.jl b/experimental/LieAlgebras/test/WeightLattice-test.jl new file mode 100644 index 000000000000..985eac2cd0ba --- /dev/null +++ b/experimental/LieAlgebras/test/WeightLattice-test.jl @@ -0,0 +1,29 @@ +@testset "LieAlgebras.WeightLattice" begin + @testset "WeightLatticeElem" begin + R = root_system(:A, 2) + w = WeightLatticeElem(R, [2, 2]) + + @test root_system(w) === R + end + + @testset "conjugate_dominant_weight_with_*_elem(w::WeightLatticeElem)" begin + for (R, vec) in [ + (root_system(:A, 5), [1, -1, 2, 0, 2]), + (root_system(:B, 3), [1, 1, 1]), + (root_system(:C, 4), [2, 1, 0, 1]), + (root_system(:D, 5), [-1, 2, 2, -1, -1]), + (root_system(:E, 6), [1, 2, 0, 0, 2, 1]), + (root_system(:F, 4), [1, 2, 3, 4]), + (root_system(:G, 2), [-1, -1]), + ] + wt = WeightLatticeElem(R, vec) + d, x = conjugate_dominant_weight_with_left_elem(wt) + @test is_dominant(d) + @test x * wt == d + + d, x = conjugate_dominant_weight_with_right_elem(wt) + @test is_dominant(d) + @test wt * x == d + end + end +end