From 15c5d21f173336231b4825ee253a3e33cb03c547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Tue, 19 Nov 2024 14:07:18 +0100 Subject: [PATCH 1/4] Move `WeightLatticeElem` to new file --- experimental/LieAlgebras/docs/doc.main | 1 + .../LieAlgebras/docs/src/root_systems.md | 44 +-- .../LieAlgebras/docs/src/weight_lattices.md | 69 ++++ experimental/LieAlgebras/src/LieAlgebras.jl | 1 + experimental/LieAlgebras/src/RootSystem.jl | 358 ------------------ experimental/LieAlgebras/src/WeightLattice.jl | 357 +++++++++++++++++ .../LieAlgebras/test/RootSystem-test.jl | 28 -- .../LieAlgebras/test/WeightLattice-test.jl | 29 ++ 8 files changed, 458 insertions(+), 429 deletions(-) create mode 100644 experimental/LieAlgebras/docs/src/weight_lattices.md create mode 100644 experimental/LieAlgebras/src/WeightLattice.jl create mode 100644 experimental/LieAlgebras/test/WeightLattice-test.jl 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..265b9eeacbad 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. @@ -180,44 +179,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..94a60721bcbb --- /dev/null +++ b/experimental/LieAlgebras/docs/src/weight_lattices.md @@ -0,0 +1,69 @@ +```@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(::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/src/LieAlgebras.jl b/experimental/LieAlgebras/src/LieAlgebras.jl index cde9d32e94b9..4ba91d23a3d7 100644 --- a/experimental/LieAlgebras/src/LieAlgebras.jl +++ b/experimental/LieAlgebras/src/LieAlgebras.jl @@ -124,6 +124,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..522faf63e16c 100644 --- a/experimental/LieAlgebras/src/RootSystem.jl +++ b/experimental/LieAlgebras/src/RootSystem.jl @@ -1406,364 +1406,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 diff --git a/experimental/LieAlgebras/src/WeightLattice.jl b/experimental/LieAlgebras/src/WeightLattice.jl new file mode 100644 index 000000000000..f3769219b0c0 --- /dev/null +++ b/experimental/LieAlgebras/src/WeightLattice.jl @@ -0,0 +1,357 @@ +############################################################################### +# +# 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 diff --git a/experimental/LieAlgebras/test/RootSystem-test.jl b/experimental/LieAlgebras/test/RootSystem-test.jl index 4a4bca04ab5b..9ef5712f2ca2 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 @@ -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..16943dae1a65 --- /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 From c1c7f661ab4f213d2cfc76b71dbfe642dd14d494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Tue, 19 Nov 2024 16:53:17 +0100 Subject: [PATCH 2/4] Add formal parent for `WeightLatticeElem` --- .../src/MainAlgorithm.jl | 6 +- .../test/MainAlgorithm-test.jl | 2 +- .../LieAlgebras/docs/src/root_systems.md | 1 + .../LieAlgebras/docs/src/weight_lattices.md | 6 +- experimental/LieAlgebras/src/RootSystem.jl | 27 ++++ experimental/LieAlgebras/src/Types.jl | 39 +++-- experimental/LieAlgebras/src/WeightLattice.jl | 138 ++++++++++++------ experimental/LieAlgebras/src/WeylGroup.jl | 5 +- experimental/LieAlgebras/src/exports.jl | 3 +- .../LieAlgebras/test/RootSystem-test.jl | 4 +- 10 files changed, 169 insertions(+), 62 deletions(-) diff --git a/experimental/BasisLieHighestWeight/src/MainAlgorithm.jl b/experimental/BasisLieHighestWeight/src/MainAlgorithm.jl index 889fc3ae0161..832357e7226c 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,7 +362,7 @@ 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)) 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/src/root_systems.md b/experimental/LieAlgebras/docs/src/root_systems.md index 265b9eeacbad..1449e39eac3a 100644 --- a/experimental/LieAlgebras/docs/src/root_systems.md +++ b/experimental/LieAlgebras/docs/src/root_systems.md @@ -45,6 +45,7 @@ rank(::RootSystem) cartan_matrix(::RootSystem) ``` ```@docs; canonical=false +weight_lattice(::RootSystem) weyl_group(::RootSystem) ``` diff --git a/experimental/LieAlgebras/docs/src/weight_lattices.md b/experimental/LieAlgebras/docs/src/weight_lattices.md index 94a60721bcbb..20f373d770d8 100644 --- a/experimental/LieAlgebras/docs/src/weight_lattices.md +++ b/experimental/LieAlgebras/docs/src/weight_lattices.md @@ -31,14 +31,16 @@ TODO ## Weight lattice elements ```@docs +WeightLatticeElem(::WeightLattice, ::Vector{<:IntegerUnion}) WeightLatticeElem(::RootSystem, ::Vector{<:IntegerUnion}) +WeightLatticeElem(::WeightLattice, ::ZZMatrix) WeightLatticeElem(::RootSystem, ::ZZMatrix) WeightLatticeElem(::RootSpaceElem) -zero(::Type{WeightLatticeElem}, ::RootSystem) +zero(::WeightLattice) ``` ```@docs -root_system(::WeightLatticeElem) +parent(::WeightLatticeElem) ``` Basic arithmetic operations like `zero`, `+`, `-`, `*` (with integer scalars), and `==` are supported. diff --git a/experimental/LieAlgebras/src/RootSystem.jl b/experimental/LieAlgebras/src/RootSystem.jl index 522faf63e16c..039e5faf9193 100644 --- a/experimental/LieAlgebras/src/RootSystem.jl +++ b/experimental/LieAlgebras/src/RootSystem.jl @@ -307,6 +307,33 @@ function set_root_system_type!( return nothing 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 diff --git a/experimental/LieAlgebras/src/Types.jl b/experimental/LieAlgebras/src/Types.jl index 155637542896..57b469d6ce15 100644 --- a/experimental/LieAlgebras/src/Types.jl +++ b/experimental/LieAlgebras/src/Types.jl @@ -18,6 +18,7 @@ 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}} @@ -41,6 +42,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 +93,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 index f3769219b0c0..1964022195ac 100644 --- a/experimental/LieAlgebras/src/WeightLattice.jl +++ b/experimental/LieAlgebras/src/WeightLattice.jl @@ -1,9 +1,63 @@ +############################################################################### +# +# 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 + ############################################################################### # # 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 @@ -13,6 +67,15 @@ 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 @@ -25,41 +88,45 @@ function WeightLatticeElem(r::RootSpaceElem) return WeightLatticeElem(R, matrix(ZZ, coeffs)) end -@doc raw""" - zero(::Type{WeightLatticeElem}, R::RootSystem) -> WeightLatticeElem +function parent_type(::Type{WeightLatticeElem}) + return WeightLattice +end -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))) +function parent(w::WeightLatticeElem) + return w.parent_lat end -function zero(r::WeightLatticeElem) - return zero(WeightLatticeElem, root_system(r)) +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(root_system(w), n * w.vec) + return WeightLatticeElem(parent(w), n * w.vec) end function Base.:*(w::WeightLatticeElem, n::IntegerUnion) - return WeightLatticeElem(root_system(w), w.vec * n) + return WeightLatticeElem(parent(w), w.vec * n) end function Base.:+(w::WeightLatticeElem, w2::WeightLatticeElem) - @req root_system(w) === root_system(w2) "parent root system mismatch" + @req parent(w) === parent(w2) "parent mismatch" - return WeightLatticeElem(root_system(w), w.vec + w2.vec) + return WeightLatticeElem(parent(w), w.vec + w2.vec) end function Base.:-(w::WeightLatticeElem, w2::WeightLatticeElem) - @req root_system(w) === root_system(w2) "parent root system mismatch" + @req parent(w) === parent(w2) "parent mismatch" - return WeightLatticeElem(root_system(w), w.vec - w2.vec) + return WeightLatticeElem(parent(w), w.vec - w2.vec) end function Base.:-(w::WeightLatticeElem) - return WeightLatticeElem(root_system(w), -w.vec) + return WeightLatticeElem(parent(w), -w.vec) end function zero!(w::WeightLatticeElem) @@ -68,43 +135,43 @@ function zero!(w::WeightLatticeElem) end function add!(wr::WeightLatticeElem, w1::WeightLatticeElem, w2::WeightLatticeElem) - @req root_system(wr) === root_system(w1) === root_system(w2) "parent root system mismatch" + @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 root_system(wr) === root_system(w) "parent root system mismatch" + @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 root_system(wr) === root_system(w1) === root_system(w2) "parent root system mismatch" + @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 root_system(wr) === root_system(w) "parent root system mismatch" + @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 root_system(wr) === root_system(w) "parent root system mismatch" + @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 root_system(wr) === root_system(w) "parent root system mismatch" + @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 root_system(wr) === root_system(w) "parent root system mismatch" + @req parent(wr) === parent(w) "parent mismatch" wr.vec = addmul!(wr.vec, n, w.vec) return wr end @@ -113,8 +180,8 @@ end 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 +function Base.:(==)(w1::WeightLatticeElem, w2::WeightLatticeElem) + return parent(w1) === parent(w2) && w1.vec == w2.vec end function Base.deepcopy_internal(w::WeightLatticeElem, dict::IdDict) @@ -122,14 +189,14 @@ function Base.deepcopy_internal(w::WeightLatticeElem, dict::IdDict) return dict[w] end - w2 = WeightLatticeElem(root_system(w), deepcopy_internal(w.vec, dict)) + 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(w.root_system, h) + h = hash(parent(w), h) h = hash(w.vec, h) return xor(b, h) end @@ -188,7 +255,7 @@ 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)) + while s <= rank(parent(w)) if w[s] < 0 reflect!(w, s) s = 1 @@ -213,13 +280,11 @@ function conjugate_dominant_weight_with_left_elem(w::WeightLatticeElem) 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) + while s <= rank(parent(w)) if w[s] < 0 push!(word, UInt8(s)) reflect!(w, s) @@ -231,7 +296,7 @@ function conjugate_dominant_weight_with_left_elem!(w::WeightLatticeElem) # 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) + return w, weyl_group(root_system(w))(reverse!(word); normalize=false) end @doc raw""" @@ -252,7 +317,7 @@ function conjugate_dominant_weight_with_right_elem!(w::WeightLatticeElem) end function dot(w1::WeightLatticeElem, w2::WeightLatticeElem) - @req root_system(w1) === root_system(w2) "parent root system mismatch" + @req parent(w1) === parent(w2) "parent mismatch" R = root_system(w1) return dot( @@ -346,12 +411,3 @@ 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 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 9ef5712f2ca2..51b72df8b162 100644 --- a/experimental/LieAlgebras/test/RootSystem-test.jl +++ b/experimental/LieAlgebras/test/RootSystem-test.jl @@ -118,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)) == From 67ef67a572198367d6a61d551d3c4e70c2aebcce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Tue, 19 Nov 2024 17:08:29 +0100 Subject: [PATCH 3/4] More functionality for `WeightLattice` --- experimental/LieAlgebras/src/LieAlgebras.jl | 1 + experimental/LieAlgebras/src/RootSystem.jl | 5 ++-- experimental/LieAlgebras/src/WeightLattice.jl | 26 +++++++++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/experimental/LieAlgebras/src/LieAlgebras.jl b/experimental/LieAlgebras/src/LieAlgebras.jl index 4ba91d23a3d7..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, diff --git a/experimental/LieAlgebras/src/RootSystem.jl b/experimental/LieAlgebras/src/RootSystem.jl index 039e5faf9193..18d8b99306ba 100644 --- a/experimental/LieAlgebras/src/RootSystem.jl +++ b/experimental/LieAlgebras/src/RootSystem.jl @@ -707,8 +707,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""" @@ -728,7 +727,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""" diff --git a/experimental/LieAlgebras/src/WeightLattice.jl b/experimental/LieAlgebras/src/WeightLattice.jl index 1964022195ac..8dc3bee98f05 100644 --- a/experimental/LieAlgebras/src/WeightLattice.jl +++ b/experimental/LieAlgebras/src/WeightLattice.jl @@ -41,6 +41,28 @@ function Base.show(io::IO, P::WeightLattice) 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 @@ -364,6 +386,10 @@ function is_fundamental_weight(w::WeightLatticeElem) 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 From e7cfeeac74b7d66d470b17283b16032aca857591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Wed, 20 Nov 2024 17:34:38 +0100 Subject: [PATCH 4/4] Draft: Use group algebra for characters --- .../src/MainAlgorithm.jl | 2 +- .../LieAlgebras/src/LieAlgebraModule.jl | 40 +++----- experimental/LieAlgebras/src/RootSystem.jl | 91 +++++++++++-------- experimental/LieAlgebras/src/Types.jl | 1 + experimental/LieAlgebras/src/WeightLattice.jl | 2 - .../LieAlgebras/test/WeightLattice-test.jl | 2 +- 6 files changed, 72 insertions(+), 66 deletions(-) diff --git a/experimental/BasisLieHighestWeight/src/MainAlgorithm.jl b/experimental/BasisLieHighestWeight/src/MainAlgorithm.jl index 832357e7226c..c212095c24b8 100644 --- a/experimental/BasisLieHighestWeight/src/MainAlgorithm.jl +++ b/experimental/BasisLieHighestWeight/src/MainAlgorithm.jl @@ -367,7 +367,7 @@ function add_by_hand( 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/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/RootSystem.jl b/experimental/LieAlgebras/src/RootSystem.jl index 18d8b99306ba..9771beb10cf7 100644 --- a/experimental/LieAlgebras/src/RootSystem.jl +++ b/experimental/LieAlgebras/src/RootSystem.jl @@ -307,6 +307,15 @@ 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 @@ -1516,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) @@ -1597,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}) @@ -1626,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] @@ -1657,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 @@ -1667,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""" @@ -1689,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}) @@ -1714,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 @@ -1769,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 @@ -1855,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 57b469d6ce15..b78f8ed37bfd 100644 --- a/experimental/LieAlgebras/src/Types.jl +++ b/experimental/LieAlgebras/src/Types.jl @@ -23,6 +23,7 @@ See [`root_system(::ZZMatrix)`](@ref) for the constructor. # 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" diff --git a/experimental/LieAlgebras/src/WeightLattice.jl b/experimental/LieAlgebras/src/WeightLattice.jl index 8dc3bee98f05..c047a8b4e863 100644 --- a/experimental/LieAlgebras/src/WeightLattice.jl +++ b/experimental/LieAlgebras/src/WeightLattice.jl @@ -62,7 +62,6 @@ function is_finite(P::WeightLattice) return iszero(rank(P)) end - ############################################################################### # # Weight lattice elements @@ -122,7 +121,6 @@ function root_system(w::WeightLatticeElem) return root_system(parent(w)) end - function zero(w::WeightLatticeElem) return zero(parent(w)) end diff --git a/experimental/LieAlgebras/test/WeightLattice-test.jl b/experimental/LieAlgebras/test/WeightLattice-test.jl index 16943dae1a65..985eac2cd0ba 100644 --- a/experimental/LieAlgebras/test/WeightLattice-test.jl +++ b/experimental/LieAlgebras/test/WeightLattice-test.jl @@ -5,7 +5,7 @@ @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]),