From e8115830bb27dc401244915278cecd127873111c Mon Sep 17 00:00:00 2001 From: Ben Wilop Date: Fri, 24 Mar 2023 09:36:18 +0100 Subject: [PATCH 01/19] first commit of basisLieHighestWeight --- Project.toml | 2 + experimental/Experimental.jl | 1 + .../basisLieHighestWeight/LieAlgebras.jl | 50 +++ .../basisLieHighestWeight/LongestWord.jl | 50 +++ experimental/basisLieHighestWeight/MB.jl | 364 +++++++++++++++++ .../basisLieHighestWeight/MonomialOrder.jl | 110 +++++ .../basisLieHighestWeight/NewMonomial.jl | 128 ++++++ .../basisLieHighestWeight/RootConversion.jl | 384 ++++++++++++++++++ .../basisLieHighestWeight/TensorModels.jl | 34 ++ .../basisLieHighestWeight/VectorSpaceBases.jl | 93 +++++ .../basisLieHighestWeight/WeylPolytope.jl | 183 +++++++++ experimental/basisLieHighestWeight/main.jl | 1 + 12 files changed, 1400 insertions(+) create mode 100644 experimental/basisLieHighestWeight/LieAlgebras.jl create mode 100644 experimental/basisLieHighestWeight/LongestWord.jl create mode 100644 experimental/basisLieHighestWeight/MB.jl create mode 100644 experimental/basisLieHighestWeight/MonomialOrder.jl create mode 100644 experimental/basisLieHighestWeight/NewMonomial.jl create mode 100644 experimental/basisLieHighestWeight/RootConversion.jl create mode 100644 experimental/basisLieHighestWeight/TensorModels.jl create mode 100644 experimental/basisLieHighestWeight/VectorSpaceBases.jl create mode 100644 experimental/basisLieHighestWeight/WeylPolytope.jl create mode 100644 experimental/basisLieHighestWeight/main.jl diff --git a/Project.toml b/Project.toml index f8ad3f540c90..e99f663c802b 100644 --- a/Project.toml +++ b/Project.toml @@ -6,6 +6,7 @@ version = "0.12.0-DEV" [deps] AbstractAlgebra = "c3fe647b-3220-5bb0-a1ea-a7954cac585d" AlgebraicSolving = "66b61cbe-0446-4d5d-9090-1ff510639f9d" +Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" GAP = "c863536a-3901-11e9-33e7-d5cd0df7b904" Hecke = "3e1990a7-5d81-5526-99ce-9ba3ff248f21" @@ -19,6 +20,7 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" RandomExtensions = "fb686558-2515-59ef-acaa-46db3789a887" RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" Singular = "bcd08a7b-43d2-5ff7-b6d4-c458787f915c" +SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" TOPCOM_jll = "36f60fef-b880-50dc-9289-4aaecee93cc3" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" diff --git a/experimental/Experimental.jl b/experimental/Experimental.jl index dbbba8e5c159..9a318e18eed7 100644 --- a/experimental/Experimental.jl +++ b/experimental/Experimental.jl @@ -34,3 +34,4 @@ include("Schemes/BlowupMorphism.jl") include("Schemes/ToricSchemes/include.jl") include("ExteriorAlgebra/ExteriorAlgebra.jl") +include("basisLieHighestWeight/main.jl") diff --git a/experimental/basisLieHighestWeight/LieAlgebras.jl b/experimental/basisLieHighestWeight/LieAlgebras.jl new file mode 100644 index 000000000000..c9bb8b20b100 --- /dev/null +++ b/experimental/basisLieHighestWeight/LieAlgebras.jl @@ -0,0 +1,50 @@ +# ? + +using Oscar +using SparseArrays + +G = Oscar.GAP.Globals +forGap = Oscar.GAP.julia_to_gap +fromGap = Oscar.GAP.gap_to_julia + + +function lieAlgebra(t::String, n::Int) + """ + Creates the Lie-algebra as a GAP object that gets used for a lot other computations with GAP + """ + L = G.SimpleLieAlgebra(forGap(t), n, G.Rationals) + return L, G.ChevalleyBasis(L) +end + + +gapReshape(A) = sparse(hcat(A...)) + + +function matricesForOperators(L, hw, ops) + """ + used to create tensorMatricesForOperators + """ + M = G.HighestWeightModule(L, forGap(hw)) + mats = G.List(ops, o -> G.MatrixOfAction(G.Basis(M), o)) + mats = gapReshape.(fromGap(mats)) + d = lcm(denominator.(union(mats...))) + mats = (A->ZZ.(A*d)).(mats) + return mats +end + + +function weightsForOperators(L, cartan, ops) + """ + Calculates the weight wts[i] for each operator ops[i] + """ + cartan = fromGap(cartan, recursive=false) + ops = fromGap(ops, recursive=false) + asVec(v) = fromGap(G.ExtRepOfObj(v)) + if any(iszero.(asVec.(ops))) + error("ops should be non-zero") + end + nzi(v) = findfirst(asVec(v) .!= 0) + return [ + [asVec(h*v)[nzi(v)] / asVec(v)[nzi(v)] for h in cartan] for v in ops + ] +end \ No newline at end of file diff --git a/experimental/basisLieHighestWeight/LongestWord.jl b/experimental/basisLieHighestWeight/LongestWord.jl new file mode 100644 index 000000000000..df9f4d7aef22 --- /dev/null +++ b/experimental/basisLieHighestWeight/LongestWord.jl @@ -0,0 +1,50 @@ +#using Gapjm + +G = Oscar.GAP.Globals +forGap = Oscar.GAP.julia_to_gap +fromGap = Oscar.GAP.gap_to_julia + +#function longest_weyl_word(t, n) +# """ +# generates a reduced expression of the longest weylword of type (t,n) by choosing uniformly a random reflection that is not leftdescending +# the resulting longest words are not uniformly distributed +# """ +# W = Gapjm.coxgroup(Symbol(t),n) # Weyl-group +# S = Gapjm.gens(W) # generators of W (simple reflections) +# m = length(S) +# p = W() # id +# word = [] # generated word +# +# # extend p with reflection that are not leftdescending until not possible (i.e. reached longest word) +# while true +# not_desc = [i for i=1:m if !(i in Gapjm.leftdescents(W,p))] # set of i s.t. length(S[i]*p) > length(p) +# if length(not_desc) >= 1 +# i = rand(not_desc) +# push!(word, i) +# p = S[i]*p +# else +# break +# end +# end +# return word +#end + +#function is_longest_weyl_word(t,n,word) +# """ +# returns if word is a reduced expression of the longest weyl word of type (t,n) +# is_longest_weyl_word(t,n,longest_weyl_word(t, n)) is always true +# """ +# W = Gapjm.coxgroup(Symbol(t),n) # Weyl-group +# p = W(word ...) # group element of word +# return p == longest(W) # is word longest word? +#end + +function sub_simple_refl(word, L, n) + """ + substitute simple reflections (i,i+1), saved in dec by i, with E_{i,i+1} + """ + R = G.RootSystem(L) + CG = fromGap(G.CanonicalGenerators(R)[1], recursive = false) + ops = forGap([CG[i] for i in word], recursive = false) + return ops +end diff --git a/experimental/basisLieHighestWeight/MB.jl b/experimental/basisLieHighestWeight/MB.jl new file mode 100644 index 000000000000..4c13203bec60 --- /dev/null +++ b/experimental/basisLieHighestWeight/MB.jl @@ -0,0 +1,364 @@ +module MB +export basisLieHighestWeight2 +export is_fundamental + +using Polymake +using Distributed +#using CUDA +#using CuArrays + +include("./NewMonomial.jl") + +#include("./VectorSpaceBases.jl") #--- bekommt gerade noch ZZ, Short und TVEC aus VectorSpaceBases + +G = Oscar.GAP.Globals +forGap = Oscar.GAP.julia_to_gap +fromGap = Oscar.GAP.gap_to_julia + + +function basisLieHighestWeight2(t, n, hw; ops = "regular", known_monomials = [], monomial_order = "GRevLex", cache_size::Int = 1000000, parallel::Bool = false, return_no_minkowski::Bool = false, return_ops::Bool = false) + """ + Compute a monomial basis for the highest weight module with highest weight ``hw`` (in terms of the fundamental weights), for a simple Lie algebra of type ``t`` and rank ``n``. + + Pseudocode: + """ + # The function precomputes objects that are independent of the highest weight and can be used in all recursion steps. Then it starts the recursion and returns the result. + + # initialization + L, CH = lieAlgebra(t, n) # L Lie Algebra of Type t,n and CH Chevalleybasis of L + ops = get_ops(t, n, ops, L, CH) # operators that are represented by our monomials. x_i is connected to ops[i] + wts = weightsForOperators(L, CH[3], ops) # weights of the operators + wts = (v->Int.(v)).(wts) + wts_eps = [w_to_eps(t, n, w) for w in wts] # this is another way of representing the weights and equivalent to wts, but some functionality is easier with those. + calc_hw = Dict{Vector{Int}, Set{Vector{Int}}}([0 for i=1:n] => Set([[0 for i=1:n]])) + no_minkowski = Set() # we save all highest weights, for which the Minkowski-sum did not suffice to gain all monomials + + # start recursion over hw + res = compute_monomials(t, n, L, hw, ops, wts, wts_eps, monomial_order, calc_hw, cache_size, parallel, no_minkowski) + + # output + if return_no_minkowski && return_ops + return res, no_minkowski, ops + elseif return_no_minkowski + return res, no_minkowski + elseif return_ops + return res, ops + else + return res + end +end + +function get_ops(t,n, ops, L, CH) + """ + handles user input for ops + "regular" for all operators + "longest-word" for random longest-word in Weyl-group + ops::Vector{Int} for explicit longest-word + """ + # create standard ops + if ops == "regular" # use ops as specified by GAP + ops = CH[1] + return ops + #elseif ops == "longest-word" # choose a random longest word. Created by extending by random not leftdescending reflections until total length is reached + # ops = longest_weyl_word(t,n) + # ops = sub_simple_refl(ops, L, n) + # return ops + end + + # use user defined ops + # wrong input + if !(typeof(ops) == Vector{Int}) + println("ops needs to of type Vector{Int}") + return -1 + end + if !(all([(1 <= i <= n) for i in ops])) + println("all values of ops need to between 1 and the rank of the lie algebra.") + end + # If one of the conditions is met, the algorithms works for sure. Otherwise a warning is printed (and can be ignored). + if !(is_longest_weyl_word(t, n, ops)) && !(Set(ops) == [i for i=1:n]) + println("WARNING: ops may be incorrect input.") + end + ops = sub_simple_refl(ops, L, n) + return ops +end + +function compute_monomials(t, n, L, hw, ops, wts, wts_eps, monomial_order, calc_hw, cache_size::Int, parallel::Bool, no_minkowski) + """ + This function calculates the monomial basis M_{hw} recursively. The recursion saves all computed results in calc_hw and we first check, if we already + encountered this highest weight in a prior step. If this is not the case, we need to perform computations. The recursion works by using the + Minkowski-sum. If M_{hw} is the desired set of monomials (identified by the exponents as lattice points), it is know that for lambda_1 + lambda_2 = hw + we have M_{lambda_1} + M_{lambda_2} subseteq M_{hw}. The complexity grows exponentially in the size of hw. Therefore, it is very helpful to obtain + a part of M_{hw} by going through all partitions of hw and using the Minkowski-property. The base cases of the recursion are the fundamental weights + hw = [0, ..., 1, ..., 0]. In this case, or if the Minkowski-property did not find enough monomials, we need to perform the computations "by hand". + """ + # simple cases + if haskey(calc_hw, hw) # we already computed the result in a prior recursion step + return calc_hw[hw] + elseif hw == [0 for i=1:n] # we mathematically know the solution + return Set([0 for i=1:n]) + end + + # calculation required + gapDim = G.DimensionOfHighestWeightModule(L, forGap(hw)) # number of monomials that we need to find, i.e. |M_{hw}|. + # fundamental weights + if is_fundamental(hw) # if hw is a fundamental weight, no partition into smaller summands is possible. This is the basecase of the recursion. + push!(no_minkowski, hw) + set_mon = add_by_hand(t, n, L, hw, ops, wts, wts_eps, monomial_order, gapDim, Set(), cache_size, parallel) + push!(calc_hw, hw => set_mon) + return set_mon + else + # use Minkowski-Sum for recursion + set_mon = Set() + i = 0 + sub_weights = compute_sub_weights(hw) + l = length(sub_weights) + # go through partitions lambda_1 + lambda_2 = hw until we have monomials enough monomials or used all partitions + while length(set_mon) < gapDim && i < l + i += 1 + lambda_1 = sub_weights[i] + lambda_2 = hw .- lambda_1 + mon_lambda_1 = compute_monomials(t, n, L, lambda_1, ops, wts, wts_eps, monomial_order, calc_hw, cache_size, parallel, no_minkowski) + mon_lambda_2 = compute_monomials(t, n, L, lambda_2, ops, wts, wts_eps, monomial_order, calc_hw, cache_size, parallel, no_minkowski) + mon_sum = Set([p .+ q for p in mon_lambda_1 for q in mon_lambda_2]) # Minkowski-sum: M_{lambda_1} + M_{lambda_2} subseteq M_{hw} + union!(set_mon, mon_sum) + end + # check if we found enough monomials + if length(set_mon) < gapDim + push!(no_minkowski, hw) + set_mon = add_by_hand(t, n, L, hw, ops, wts, wts_eps, monomial_order, gapDim, set_mon, cache_size, parallel) + end + push!(calc_hw, hw => set_mon) + return set_mon + end +end + +function is_fundamental(hw) + """ + returns true if hw is fundamental weight, i.e. hw = [0, ..., 1, ..., 0] (or hw = [0, ..., 0]) + """ + one = false + for i in hw + if i > 0 + if one || i > 1 + return false + else + one = true + end + end + end + return true +end + +function order_sub_weights(hw, sub_weights) + """ + sort weights incrasing by their 2-norm + """ + sort!(sub_weights, by=x->sum((x).^2)) +end + +function compute_sub_weights(hw) + """ + returns list of weights w != 0 with 0 <= w <= hw elementwise + """ + sub_weights = [] + foreach(Iterators.product((0:x for x in hw)...)) do i + push!(sub_weights, [i...]) + end + popfirst!(sub_weights) # [0, ..., 0] + pop!(sub_weights) # hw + order_sub_weights(hw, sub_weights) + return sub_weights +end + +function add_known_monomials!(weightspace, set_mon_in_weightspace, m, wts, mats, calc_monomials, space, e, cache_size) + """ + By using the Minkowski-sum, we know that all monomials in set_mon_in_weightspace are in our basis. Since we want to extend the weightspacse with + missing monomials, we go need to calculate and add the vector of each monomial to our basis. + """ + weight = weightspace[1] + for mon in set_mon_in_weightspace[weight] + #vec, wt = calc_new_mon!(mon, m, wts, mats, calc_monomials, space, e, cache_size) + d = sz(mats[1]) + v0 = spzeros(Int, d); v0[1] = 1 # starting vector v + vec = calc_vec(v0, mon, mats) + wt = calc_wt(mon, wts) + #println("vec:" , vec) + #println("wt: ", wt) + if !haskey(space, wt) + space[wt] = nullSpace() + end + addAndReduce!(space[wt], vec) + end + GC.gc() +end + +function add_new_monomials!(t, n, mats, wts, monomial_order, weightspace, wts_eps, set_mon_in_weightspace, calc_monomials, space, e, cache_size, set_mon, m) + """ + If a weightspace is missing monomials, we need to calculate them by trial and error. We would like to go through all monomials in the order monomial_order + and calculate the corresponding vector. If it extends the basis, we add it to the result and else we try the next one. We know, that all monomials that work + lie in the weyl-polytope. Therefore, we only inspect the monomials that lie both in the weyl-polytope and the weightspace. Since the weyl-polytope is bounded + these are finitely many, we can sort them and then go trough them, until we found enough. + """ + #println("memory: ", Int(Base.Sys.free_memory()) / 2^20) + weight = weightspace[1] + dim_weightspace = weightspace[2] + + # get monomials from weyl-polytope that are in the weightspace + poss_mon_in_weightspace = get_monomials_of_weightspace(wts_eps, w_to_eps(t, n, weight), t) + lt_function = lt_monomial_order(monomial_order) + poss_mon_in_weightspace = sort(poss_mon_in_weightspace, lt=lt_function) + + # check which monomials should get added to the basis + i=0 + if weight == 0 # check if [0 0 ... 0] already in basis + i += 1 + end + number_mon_in_weightspace = length(set_mon_in_weightspace[weight]) + # go through possible monomials one by one and check if it extends the basis + while number_mon_in_weightspace < dim_weightspace + i += 1 + + # get a new mon + if t in ["A", "G"] # necessary because of the structure of get_monomials_of_weightspace_An + mon = convert(Vector{Int64}, poss_mon_in_weightspace[i][2:end]) + else + mon = convert(Vector{Int64}, poss_mon_in_weightspace[i]) + end + if mon in set_mon + continue + end + + # calculate the vector and check if it extends the basis + #vec, _ = calc_new_mon!(mon, m, wts, mats, calc_monomials, space, e, cache_size) + d = sz(mats[1]) + v0 = spzeros(Int, d); v0[1] = 1 # starting vector v + vec = calc_vec(v0, mon, mats) + #println("vec:" , vec) + if !haskey(space, weight) + space[weight] = nullSpace() + end + vec_red = addAndReduce!(space[weight], vec) + if isempty(vec_red.nzind) # v0 == 0 + continue + end + + # save monom + number_mon_in_weightspace += 1 + push!(set_mon, mon) + end + + # Weirdly, removing this causes memory problems. The lines should not be necessary since the objects are not referenced + # and the garbage collector should run automatically. If I find out what causes this, it will be removed. + weight = 0 + dim_weightspace = 0 + lt_function = 0 + number_mon_in_weightspace = 0 + poss_mon_in_weightspace = 0 + GC.gc() +end + + +function add_by_hand(t, n, L, hw, ops, wts, wts_eps, monomial_order, gapDim, set_mon, cache_size::Int, parallel::Bool) + """ + This function calculates the missing monomials by going through each non full weightspace and adding possible monomials + manually by computing their corresponding vectors and checking if they enlargen the basis. + """ + #println("") + #println("add_by_hand: ", hw) + # initialization + mats = tensorMatricesForOperators(L, hw, ops) # matrices g_i for (g_1^a_1 * ... * g_k^a_k)*v + m = length(mats) + e = [(1:m .== i) for i in 1:m] # e_i + space = Dict(0*wts[1] => nullSpace()) # span of basis vectors to keep track of the basis + d = sz(mats[1]) + v0 = spzeros(Int, d); v0[1] = 1 # starting vector v + calc_monomials = Dict{Vector{Int}, Tuple{TVec, Vector{Int}}}([0 for i in 1:m] => (v0, 0 * wts[1])) # saves the calculated vectors to decrease necessary matrix multiplicatons + push!(set_mon, [0 for i in 1:m]) + weightspaces = get_dim_weightspace(t,n, L, hw) # required monomials of each weightspace + + # sort the monomials from the minkowski-sum by their weightspaces + set_mon_in_weightspace = Dict{Vector{Int}, Set{Vector{Int}}}() + for (weight, _) in weightspaces + set_mon_in_weightspace[weight] = Set() + end + for mon in set_mon + weight = calc_wt(mon, wts) + push!(set_mon_in_weightspace[weight], mon) + end + + # only inspect weightspaces with missing monomials + full_weightspaces = zeros(Bool, length(weightspaces)) + for i=1:length(weightspaces) + full_weightspaces[i] = (length(set_mon_in_weightspace[weightspaces[i][1]]) == weightspaces[i][2]) + end + deleteat!(weightspaces, full_weightspaces) + weightsapces = full_weightspaces + + + # use parallel computations if parallel=true. The weightspaces could be calculated completely indepent. We just save + # the computed monomials. + # insert known monomials into basis + if parallel + @distributed for weightspace in weightspaces + add_known_monomials!(weightspace, set_mon_in_weightspace, m, wts, mats, calc_monomials, space, e, cache_size) + end + else + for weightspace in weightspaces + println("known memory: ", Int(Base.Sys.free_memory()) / 2^20) + #println("size space: ", Int(Base.summarysize(space)) / 2^20) + #println("size calc_monomials: ", Int(Base.summarysize(calc_monomials)) / 2^20) + add_known_monomials!(weightspace, set_mon_in_weightspace, m, wts, mats, calc_monomials, space, e, cache_size) + if Int(Base.Sys.free_memory()) / 2^20 < 100 + println("-----------------KNOWN------------------------") + end + end + end + + # calculate new monomials + if parallel + @distributed for weightspace in weightspaces + add_new_monomials!(t, n, mats, wts, monomial_order, weightspace, wts_eps, set_mon_in_weightspace, calc_monomials, space, e, cache_size, set_mon, m) + end + else + for weightspace in weightspaces + #println("varinfo: ", InteractiveUtils.varinfo(MB3)) + println("new memory: ", Int(Base.Sys.free_memory()) / 2^20) + #println("size space: ", Int(Base.summarysize(space)) / 2^20) + #println("size calc_monomials: ", Int(Base.summarysize(calc_monomials)) / 2^20) + add_new_monomials!(t, n, mats, wts, monomial_order, weightspace, wts_eps, set_mon_in_weightspace, calc_monomials, space, e, cache_size, set_mon, m) + if Int(Base.Sys.free_memory()) / 2^20 < 100 + println("-----------------NEW------------------------") + end + end + end + #println("calc_monomials: ", length(calc_monomials)) + return set_mon +end + +function get_dim_weightspace(t, n, L, hw) + """ + calculates matrix, first row weights, second row dimension of corresponding weightspace + GAP computes the dimension for all positive weights. The dimension is constant on orbits of the weylgroup, + and we can therefore calculate the dimension of each weightspace + """ + # calculate dimension for dominant weights with GAP + R = G.RootSystem(L) + W = fromGap(G.DominantCharacter(R, forGap(hw))) + dominant_weights = W[1] + dominant_weights_dim = W[2] + dim_weightspace = [] + + # calculate dimension for the rest by checking which positive weights lies in the orbit. + for i=1:length(dominant_weights) + orbit_weights = orbit_weylgroup(t,n, dominant_weights[i]) + dim = dominant_weights_dim[i] + for weight in eachrow(orbit_weights) + append!(dim_weightspace, [[hw-eps_to_w(t,n,weight), dim]]) + end + end + return dim_weightspace +end + + + +end \ No newline at end of file diff --git a/experimental/basisLieHighestWeight/MonomialOrder.jl b/experimental/basisLieHighestWeight/MonomialOrder.jl new file mode 100644 index 000000000000..2efdcda7ab2e --- /dev/null +++ b/experimental/basisLieHighestWeight/MonomialOrder.jl @@ -0,0 +1,110 @@ +# manages methods for different orders of monomials + +function highest_calc_sub_monomial(mon::Vector{Int}, calc_monomials) + """ + returns the key in calc_monomials that can be extended by the least amount of left-operations to mon + """ + sub_mon = copy(mon) + + m = length(mon) + for i in 1:m + while sub_mon[i] > 0 + #println(sub_mon) + #println(calc_monomials) + if haskey(calc_monomials, sub_mon) + return sub_mon + else + sub_mon[i] -= 1 + end + end + end + #println(sub_mon) + return sub_mon # [0 for i in 1:m] +end + +function lt_monomial_order(monomial_order) + """ + Returns the desired monomial_order function + """ + if isa(monomial_order, Function) + return monomial_order + elseif monomial_order == "GRevLex" + return lt_grevlex + elseif monomial_order == "RevLex" + return lt_rlex + elseif monomial_order == "Lex" + return lt_lex + elseif monomial_order == "GLex" + return lt_glex + else + println("no suitable order picked") + end +end + +function lt_grevlex(mon1, mon2) + """ + graded reverse lexicographic order + returns true if mon1 is less than mon2 + """ + if sum(mon1) == sum(mon2) + for i=1:length(mon1) + if mon1[i] < mon2[i] + return false + elseif mon1[i] > mon2[i] + return true + end + end + return false + else + return sum(mon1) < sum(mon2) + end +end + +function lt_glex(mon1, mon2) + """ + graded lexicographic order + returns true if mon1 is less than mon2 + """ + if sum(mon1) == sum(mon2) + for i=length(mon1):-1:1 + if mon1[i] < mon2[i] + return true + elseif mon1[i] > mon2[i] + return false + end + end + return false + else + return sum(mon1) < sum(mon2) + end +end + +function lt_lex(mon1, mon2) + """ + lexicographic order + returns true if mon1 is less than mon2 + """ + for i=length(mon1):-1:1 + if mon1[i] < mon2[i] + return true + elseif mon1[i] > mon2[i] + return false + end + end + return false +end + +function lt_rlex(mon1, mon2) + """ + reverse lexicographic order + returns true if mon1 is less than mon2 + """ + for i=1:length(mon1) + if mon1[i] < mon2[i] + return true + elseif mon1[i] > mon2[i] + return false + end + end + return false +end \ No newline at end of file diff --git a/experimental/basisLieHighestWeight/NewMonomial.jl b/experimental/basisLieHighestWeight/NewMonomial.jl new file mode 100644 index 000000000000..c04f9f7d43e3 --- /dev/null +++ b/experimental/basisLieHighestWeight/NewMonomial.jl @@ -0,0 +1,128 @@ +# main file +#--- bekommt gerade noch ZZ, Short und TVEC aus VectorSpaceBases + + +# TODO use dimension of weightspace to stop unnecessary calculations +# TODO use UInt8 instead of Int for polynomials again + +# module MB2 + +include("./VectorSpaceBases.jl") +include("./TensorModels.jl") +include("./LieAlgebras.jl") +include("./MonomialOrder.jl") +include("./LongestWord.jl") +include("./WeylPolytope.jl") + +G = Oscar.GAP.Globals +forGap = Oscar.GAP.julia_to_gap +fromGap = Oscar.GAP.gap_to_julia + + +function calc_wt(mon, weights) + """ + + """ + wt = [0 for i in 1:length(weights[1])] + for i in 1:length(mon) + wt .+= mon[i] * weights[i] + end + return wt +end + +function calc_vec(v0, mon, mats) + vec = v0 + for i in length(mon):-1:1 + for j in 1:mon[i] + vec = mats[i]*vec + end + end + return vec +end + +function highest_calc_sub_monomial(mon::Vector{Int}, calc_monomials) + """ + returns the key in calc_monomials that can be extended by the least amount of left-operations to mon + """ + sub_mon = copy(mon) + + m = length(mon) + for i in 1:m + while sub_mon[i] > 0 + #println(sub_mon) + #println(calc_monomials) + if haskey(calc_monomials, sub_mon) + return sub_mon + else + sub_mon[i] -= 1 + end + end + end + #println(sub_mon) + return sub_mon # [0 for i in 1:m] +end + +function calc_new_mon!(mon, m, wts, mats, calc_monomials, space, e, cache_size) + # calculate vector of mon by extending a previous calculated vector to a + # monom that differs only by left-multiplication, save results in calc_monomials + sub_mon = highest_calc_sub_monomial(mon, calc_monomials) + #println("sub_mon: ", sub_mon) + sub_mon_cur = copy(sub_mon) + if !haskey(calc_monomials, sub_mon_cur) + println("ERROR IN calc_new_mon") + println(mon) + println(sub_mon_cur) + println(calc_monomials) + end + (vec, wt) = calc_monomials[sub_mon] + + # this block cannot be used in MB3 because we don't iterate through monomials in universal order, + # but instead in the monomial-order for each weightspace + #if mon == sub_mon # mon already contained so we need to reduce it to 0 + # return spzeros(ZZ, m), wt + #end + + #needs_to_be_saved = true + for i in m:-1:1 + for k in sub_mon[i]:(mon[i]-1) + sub_mon_cur += e[i] + wt += wts[i] + if !haskey(space, wt) + space[wt] = nullSpace() + end + #if isempty(vec.nzind) # v already 0 + # needs_to_be_saved = false + #else + # vec = mats[i] * vec + #end + #vec = addAndReduce!(space[wt], vec) + #println(sub_mon_cur) + #if needs_to_be_saved + # calc_monomials[sub_mon_cur] = (vec, wt) + #end + #mul!(A, vec) + vec = mats[i] * vec + if length(calc_monomials) < cache_size + calc_monomials[sub_mon_cur] = (vec, wt) + end + + # check if the extended monomial can be deleted from calculated_monomials, i.e. the other possible extensions are already contained + can_be_deleted = true + k = m + for l = 1:m + if (sub_mon_cur-e[i])[l] != 0 + k = l + end + end + for l = 1:k + can_be_deleted = can_be_deleted && haskey(calc_monomials, sub_mon_cur-e[i]+e[l]) + end + if can_be_deleted && sub_mon_cur != e[i] + delete!(calc_monomials, sub_mon_cur-e[i]) + end + end + end + # calc_monomials[sub_mon_cur] = (vec, wt) this position is for graded_reverse_lexicographic enough instead of the one above + return vec, wt +end + diff --git a/experimental/basisLieHighestWeight/RootConversion.jl b/experimental/basisLieHighestWeight/RootConversion.jl new file mode 100644 index 000000000000..c3471cec0a4a --- /dev/null +++ b/experimental/basisLieHighestWeight/RootConversion.jl @@ -0,0 +1,384 @@ +#using Gapjm +using Oscar + +G = Oscar.GAP.Globals +forGap = Oscar.GAP.julia_to_gap +fromGap = Oscar.GAP.gap_to_julia + +############################################ +# conversion weight representation # +############################################ + + +function w_to_eps(t, n, weight) + #println("w_to_eps: ", t, n, weight) + if t == "A" + return w_to_eps_A(n, weight) + elseif t in ["B", "C", "D", "E", "F", "G"] + #return round.(alpha_to_eps(t, n, w_to_alpha(t, n, weight))) # round not necessary + return alpha_to_eps(t, n, w_to_alpha(t, n, weight)) + else + println("This type of lie algebra is not supported.") + end +end + +function eps_to_w(t, n, weight) + #println("eps_to_w: ", t, n, weight) + if t == "A" + return eps_to_w_A(n, weight) + elseif t in ["B", "C", "D", "E", "F", "G"] + return round.(alpha_to_w(t, n, eps_to_alpha(t, n, weight))) + #return alpha_to_w(t, n, eps_to_alpha(t, n, weight)) + else + println("This type of lie algebra is not supported.") + end +end + +function alpha_to_eps(t, n, weight) + if t in ["B", "C", "D"] + return alpha_to_eps_BCD(t, n, weight) + elseif t == "E" && n in [6, 7, 8] + return alpha_to_eps_E(n, weight) + elseif t == "F" && n == 4 + return alpha_to_eps_F(weight) + elseif t == "G" && n == 2 + return alpha_to_eps_G(weight) + else + println("This rank of lie algebra is not supported.") + end +end + +function eps_to_alpha(t, n, weight) + if t in ["B", "C", "D"] + return eps_to_alpha_BCD(t, n, weight) + elseif t == "E" && n in [6, 7, 8] + return eps_to_alpha_E(n, weight) + elseif t == "F" && n == 4 + return eps_to_alpha_F(weight) + elseif t == "G" && n == 2 + return eps_to_alpha_G(weight) + else + println("This rank of lie algebra is not supported.") + end +end + +function w_to_alpha(t, n, weight) + C = get_CartanMatrix(t, n) + #return round.([i for i in C*weights]) + #println("w_to_alpha: ", [i for i in C*weight]) + return [i for i in C*weight] +end + +function alpha_to_w(t, n, weight) + C_inv = get_inverse_CartanMatrix(t, n) + #return round.([i for i in C_inv*weights]) + #println("alpha_to_w: ", [i for i in C_inv*weight]) + return [i for i in C_inv*weight] +end + +function get_CartanMatrix(t, n) + L = G.SimpleLieAlgebra(forGap(t), n, G.Rationals) + R = G.RootSystem(L) + C_list = fromGap(G.CartanMatrix(R)) + C = zeros(n,n) + for i in 1:n + for j in 1:n + C[i,j] = C_list[i][j] + end + end + return C +end + +function get_inverse_CartanMatrix(t, n) + return inv(get_CartanMatrix(t, n)) +end + + + +function alpha_to_eps_BCD(t, n, weight) + """ + for B-D + """ + eps = [0.0 for i=1:n] + for i in 1:(n-1) + eps[i] += weight[i] + eps[i+1] -= weight[i] + end + if t == "B" + eps[n] += weight[n] + elseif t == "C" + eps[n] += 2*weight[n] + elseif t == "D" + eps[n-1] += weight[n] + eps[n] += weight[n] + end + return eps +end + +function eps_to_alpha_BCD(t, n, weight) + """ + for B-D + """ + alpha = [0.0 for i=1:n] + for i in 1:(n-2) + alpha[i] = weight[i] + weight[i+1] += weight[i] + end + if t == "B" + alpha[n-1] = weight[n-1] + alpha[n] += weight[n-1] + weight[n] + elseif t == "C" + alpha[n-1] = weight[n-1] + alpha[n] += 0.5*weight[n-1] + 0.5*weight[n] # requires eps to be always even + elseif t == "D" + alpha[n-1] += (weight[n-1] - weight[n])/2 + alpha[n] += (weight[n-1] + weight[n])/2 + end + return alpha +end + +function alpha_to_eps_E(n, weight) + """ + for E + """ + if n == 6 + return alpha_to_eps_E6(weight) + elseif n == 7 + return alpha_to_eps_E7(weight) + elseif n == 8 + return alpha_to_eps_E8(weight) + end +end + +function eps_to_alpha_E(n, weight) + """ + for E + """ + if n == 6 + return eps_to_alpha_E6(weight) + elseif n == 7 + return eps_to_alpha_E7(weight) + elseif n == 8 + return eps_to_alpha_E8(weight) + end +end + +function alpha_to_eps_E6(weight) + """ + for E6, potentially wrong order or roots (1-2-3-5-6, 3-4) + """ + eps = [0.0 for i=1:6] + for i=1:4 + eps[i] += weight[i] + eps[i+1] += - weight[i] + end + eps[4] += weight[5] + eps[5] += weight[5] + for i=1:5 + eps[i] += -0.5*weight[6] + end + eps[6] += 0.5*sqrt(3)*weight[6] + #println("alpha_to_eps_E6: ", eps) + return eps +end + +function eps_to_alpha_E6(weight) + """ + for E6 + """ + alpha = [0.0 for i=1:6] + for j=1:3 + for i=1:j + alpha[j] += weight[i] + end + alpha[j] += j*(sqrt(3) / 3) *weight[6] + end + for i=1:4 + alpha[4] += 0.5*weight[i] + alpha[5] += 0.5*weight[i] + end + alpha[4] += -0.5*weight[5] + (sqrt(3) / 2)*weight[6] + alpha[5] += 0.5*weight[5] + 5*(sqrt(3) / 6)*weight[6] + alpha[6] = +2*(sqrt(3) / 3)*weight[6] + #println("eps_to_alpha_E6: ", alpha) + return alpha +end + +function alpha_to_eps_E7(weight) + """ + for E7, potentially wrong order of roots (1-2-3-4-6-7, 4-5) + """ + eps = [0.0 for i=1:7] + for i=1:5 + eps[i] += weight[i] + eps[i+1] += - weight[i] + end + eps[5] += weight[6] + eps[6] += weight[6] + for i=1:6 + eps[i] += -0.5*weight[7] + end + eps[7] += 0.5*sqrt(2)*weight[7] + #println("alpha_to_eps_E7: ", eps) + return eps +end + +function eps_to_alpha_E7(weight) + """ + for E7 + """ + alpha = [0.0 for i=1:7] + for j=1:4 + for i=1:j + alpha[j] += weight[i] + end + alpha[j] += j*(sqrt(2) / 2) *weight[7] + end + for i=1:5 + alpha[5] += 0.5*weight[i] + alpha[6] += 0.5*weight[i] + end + alpha[5] += -0.5*weight[6] + sqrt(2)*weight[7] + alpha[6] += 0.5*weight[6] + 3*(sqrt(2) / 2)*weight[7] + alpha[7] = sqrt(2)*weight[7] + #println("eps_to_alpha_E6: ", alpha) + return alpha +end + +function alpha_to_eps_E8(weight) + """ + for E8 + """ + eps = [0.0 for i=1:8] + for i=1:6 + eps[i] += weight[i] + eps[i+1] += - weight[i] + end + eps[6] += weight[7] + eps[7] += weight[7] + for i=1:8 + eps[i] += -0.5*weight[8] + end + return eps +end + +function eps_to_alpha_E8(weight) + """ + for E8 + """ + alpha = [0.0 for i=1:8] + for j=1:5 + for i=1:j + alpha[j] += weight[i] + end + alpha[j] += -j*weight[8] + end + for i=1:6 + alpha[6] += 0.5*weight[i] + alpha[7] += 0.5*weight[i] + end + alpha[6] += -0.5*weight[7] - 2.5*weight[8] + alpha[7] += 0.5*weight[7] - 3.5*weight[8] + alpha[8] = -2*weight[8] + return alpha +end + +function alpha_to_eps_F(weight) # how does this work for G? + """ + for F + """ + eps = [0.0 for i=1:4] + eps[1] = weight[1] - 0.5*weight[4] + eps[2] = - weight[1] + weight[2] - 0.5*weight[4] + eps[3] = - weight[2] + weight[3] - 0.5*weight[4] + eps[4] = - 0.5*weight[4] + return eps +end + +function eps_to_alpha_F(weight) + """ + for F + """ + alpha = [0 for i=1:4] + alpha[1] = weight[1] - weight[4] + alpha[2] = weight[1] + weight[2] - 2*weight[4] + alpha[3] = weight[1] + weight[2] + weight[3] - 3*weight[4] + alpha[4] = -2*weight[4] + return alpha +end + +function alpha_to_eps_G(weight) # how does this work for G? + """ + for G_2 + """ + eps = [0.0 for i=1:3] + eps[1] = weight[1] - weight[2] + eps[2] = - weight[1] + 2*weight[2] + eps[3] = - weight[2] + choose_representant_eps(eps) + return eps +end + +function eps_to_alpha_G(weight) + """ + for G_2 + """ + alpha = [0.0 for i=1:2] + #choose_representant_eps(weight) + if length(weight) >= 3 + weight .-= weight[3] + end + alpha[1] = weight[1] + alpha[2] = (weight[1] + weight[2]) / 3 + return alpha +end + +function w_to_eps_A(n, weight) + """ + input: weight in w_i + output: weight in eps_i + inverse to eps_to_w + # TODO (right now only for t=A) + """ + res = [0 for i=1:(n+1)] + for i in 1:n + for l in 1:i + res[l] += weight[i] + end + end + choose_representant_eps(res) + return res +end + +function choose_representant_eps(weight) + # choose representant eps_1 + ... + eps_m = 0 + if any(<(0), weight) # non negative + weight .-= min(weight ...) + end +end + +function eps_to_w_A(n, weight) + """ + input: weight in eps_i + output: weight in w_i + inverse to w_to_eps + # TODO (right now only for t=A) + """ + m = length(weight) + choose_representant_eps(weight) + if weight[n+1] != 0 # eps_n+1 = 0 + weight .-= weight[n+1] + weight[n+1] = 0 + end + #if all(>(0), weight) # minimal + # weight .-= min(weight ...) + #end + res = [0 for i=1:n] + for i in n:-1:1 + res[i] = weight[i] + for l in 1:i + weight[l] -= weight[i] + end + end + return res +end \ No newline at end of file diff --git a/experimental/basisLieHighestWeight/TensorModels.jl b/experimental/basisLieHighestWeight/TensorModels.jl new file mode 100644 index 000000000000..990c73dd0e69 --- /dev/null +++ b/experimental/basisLieHighestWeight/TensorModels.jl @@ -0,0 +1,34 @@ +# ? + +using Oscar +using SparseArrays + +# TODO: make the first one a symmetric product, or reduce more generally + +spid(n) = spdiagm(0 => [ZZ(1) for _ in 1:n]) +sz(A) = size(A)[1] +tensorProduct(A, B) = kron(A, spid(sz(B))) + kron(spid(sz(A)), B) +tensorProducts(As, Bs) = (AB->tensorProduct(AB[1], AB[2])).(zip(As, Bs)) +tensorPower(A, n) = (n == 1) ? A : tensorProduct(tensorPower(A, n-1), A) +tensorPowers(As, n) = (A->tensorPower(A, n)).(As) + + +function tensorMatricesForOperators(L, hw, ops) + """ + Calculates the matrices g_i corresponding to the operator ops[i]. + """ + mats = [] + + for i in 1:length(hw) + if hw[i] <= 0 + continue + end + wi = Int.(1:length(hw) .== i) # i-th fundamental weight + _mats = matricesForOperators(L, wi, ops) + _mats = tensorPowers(_mats, hw[i]) + mats = mats == [] ? _mats : tensorProducts(mats, _mats) + #display(mats) + end + + return mats +end \ No newline at end of file diff --git a/experimental/basisLieHighestWeight/VectorSpaceBases.jl b/experimental/basisLieHighestWeight/VectorSpaceBases.jl new file mode 100644 index 000000000000..83d82d25df79 --- /dev/null +++ b/experimental/basisLieHighestWeight/VectorSpaceBases.jl @@ -0,0 +1,93 @@ +# manages the basisvectors and its linear independence + +using Oscar +using SparseArrays + +ZZ = Int +TVec = SparseVector{ZZ, Int} #--- Werte sind ZZ, Indizies sind Int (TVec ist Datentyp der Basisvektoren in basisLieHighestWeight) +Short = UInt8 # for exponents of monomials; max. 255 + +struct VSBasis + A::Vector{TVec} #--- Vektor von Basisvektoren + pivot::Vector{Int} #--- Vektor von Pivotelementen, d.h. pivot[i] ist erster nichtnull Index von A[i] + dim::Vector{Int} #--- dimension +end + + +nullSpace() = VSBasis([], [], []) #--- leerer Vektorraum + + +function normalize(v::TVec) + """ + divides vector by gcd of nonzero entries, returns vector and first nonzero index + used: addAndReduce! + """ + dropzeros!(v) #--- deletes stored zeros in SparsedArray (in-place, hingegen würde dropzeros(v) Kopie zurückgeben) + if isempty(v.nzind) #--- v.nzind sind abgespeicherte Werte + #--- v.nzval sind abgespeicherte Indizies (der Größe nach geordnet, startet bei 1) + #return (0, 0) + return (v, 0) + end + + pivot = v.nzind[1] #--- erster != 0 Eintrag im Vektor, d.h. der oberste + + return v .÷ gcd(v.nzval), pivot #--- durch ggT teilen +end + + +reduceCol(a, b, i::Int) = a*b[i] - b*a[i] #--- a = reduceCol(a, b, i) erzeugt Nulleintrag in a[i] durch elementare Zeilenumformungen + #--- Werte bleiben Integers + + +function addAndReduce!(sp::VSBasis, v::TVec) + """ + for each pivot of sp.A we make entry of v zero and return the result and insert it into sp + 0 => linear dependent + * => linear independent, new column element of sp.A since it increases basis + invariants: the row of a pivotelement in any column in A is 0 (except the pivotelement) + elements of A are integers, gcd of each column is 1 + """ + A = sp.A + pivot = sp.pivot + dim = sp.dim + + if dim == [] #--- update dimension + insert!(dim, 1, length(v)) + end + + if length(A) == sp.dim[1] #-- space already full => linear dependence guaranteed + v = spzeros(ZZ, sp.dim[1]) + return v + end + + v, newPivot = normalize(v) + if newPivot == 0 #--- v ist Nullvektor + #return 0 + return v + end + + for j = 1:length(A) + i = pivot[j] + if i != newPivot + continue + end + v = reduceCol(v, A[j], i) + v, newPivot = normalize(v) + if newPivot == 0 + #return 0 + return v + end + end + + pos = findfirst(pivot .> newPivot) + if (pos === nothing) + pos = length(pivot) + 1 + end + + insert!(A, pos, v) + insert!(pivot, pos, newPivot) + return v +end + + + diff --git a/experimental/basisLieHighestWeight/WeylPolytope.jl b/experimental/basisLieHighestWeight/WeylPolytope.jl new file mode 100644 index 000000000000..00d864271374 --- /dev/null +++ b/experimental/basisLieHighestWeight/WeylPolytope.jl @@ -0,0 +1,183 @@ +#using Gapjm +using Oscar + +include("./RootConversion.jl") + +G = Oscar.GAP.Globals +forGap = Oscar.GAP.julia_to_gap +fromGap = Oscar.GAP.gap_to_julia + +######################### +# weyl-polytope # +######################### + +function weylpolytope(t::String, n::Int, hw::Vector{Int}) + """ + returns weyl-polytope in homogeneous coordinates, i.e. convex hull of orbit of weyl-group of type t,n on highest weight vector hw + """ + vertices = orbit_weylgroup(t, n, hw) + #println("vertices: ", vertices) + println(vertices) + vertices_hom = [ones(Int64, size(vertices)[1]) vertices]# homogeneous coordinates + println(vertices_hom) + #println("vertices_hom: ", vertices_hom) + #weylpoly = convex_hull(vertices) # normalized to first coordinate 1? See documentation in PolyMake + weylpoly = polytope.Polytope(POINTS=vertices_hom) + #println("weylpoly: ", weylpoly) + #println("contains?:", contains(weylpoly, [0, 0])) + return weylpoly +end + +function orbit_weylgroup(t::String, n::Int, hw) + """ + operates weyl-group of type t,n on highest weight vector hw and returns list of vector + input in terms of w_i, output in eps_i (fix!!) + """ + # also possible with polymake orbit_polytope(Vector input_point, Group g), root_system(String type) to save the equations, constant summand missing + # initialization + L, CH = lieAlgebra(t, n) + W = G.WeylGroup(G.RootSystem(L)) + orb = G.WeylOrbitIterator(W, forGap(hw)) + vertices = [] + + # operate with the weylgroup on hw + G.IsDoneIterator(orb) + while !(G.IsDoneIterator(orb)) + w = G.NextIterator(orb) + push!(vertices, fromGap(w)) + end + + # return result + vertices = transpose(hcat(vertices ...)) + vertices = [w_to_eps(t, n, w) for w in eachrow(vertices)] + vertices = transpose(hcat(vertices ...)) + #println("wts_eps ", [w_to_eps(t, n, w) for w in eachrow(vertices)]) + return vertices +end + +function get_points_polytope(polytope) + """ + returns all points (interior and vertices) of a polytope in regular (i.e. not homogenoues coordinates). + """ + interior_points = convert(Matrix{Int64}, polytope.INTERIOR_LATTICE_POINTS) + vertices_points = convert(Matrix{Int64}, polytope.VERTICES) + points = [interior_points; vertices_points][:, 2:end] + return points +end + + +############################################# +# compute monomials for weightspace # +############################################# + +function get_monomials_of_weightspace(wts, weight, t) + # TODO CHECK IF XN WORKS FOR ALL OTHER TYPES + if t in ["A", "G"] + return get_monomials_of_weightspace_An(wts, weight) + else + return get_monomials_of_weightspace_Xn(wts, weight) + end +end + +function get_monomials_of_weightspace_An(wts, weight) + """ + calculates all monomials in a given weightspace for lie algebras that have type A + input: + wts: the operator weights in eps_i + weight: lambda - mu + + output: all monomials with weight weight + + works by calculating all integer solutions to the following linear program: + [ 1 | | ] [ x ] + [ 1 wts[1] ... wts[k] ] * [ | ] = weight + [... | | ] [ res ] + [ 1 | | ] [ | ] + where res[i] >= 0 for all i + + example: + wts = [[1, 0, 2], [-1, 1, 1], [0, -1, 0]] (i.e. a_1 = eps_1 - eps_2, a_2 = eps_2 - eps_3, a_12 = eps_1 - eps_3) + weight = [2, 1, 0] + -> poly = polytope.Polytope(INEQUALITIES=[0 0 1 0 0; 0 0 0 1 0; 0 0 0 0 1], EQUATIONS=[-2 1 1 0 2; -1 1 -1 1 1; 0 1 0 -1 0]) + => returns [[1 0 0], [1 1 0]] + """ + #println("") + #println(weight) + #println(wts) + + wts = [reshape(w, 1, :) for w in wts] + n = length(wts) + ineq = zeros(Int64, n, n+2) + for i in 1:n + ineq[i, 2+i] = 1 + end + equ = cat([-i for i in vec(weight)], [1 for i=1:length(weight)], dims = (2,2)) + equ = cat(equ, [transpose(w) for w in wts] ..., dims = (2,2)) + #println("ineq: ", ineq) + #println("equ: ", equ) + poly = polytope.Polytope(INEQUALITIES=ineq, EQUATIONS=equ) + #println(poly) + #println(typeof(poly)) + #println(poly.VERTICES) + #println(poly.INTERIOR_LATTICE_POINTS) + #monomials = convert(Matrix{Int64}, poly.INTERIOR_LATTICE_POINTS)[:, 3:end] # first coordinate is for homogenous coordinates and second one for eps_1 + ... + eps_k = 0 + + #println("") + #println("TEST") + #q = polytope.Polytope(INEQUALITIES=[0 0 1 0 0; 0 0 0 1 0; 0 0 0 0 1], EQUATIONS=[-2 1 2 1 2; -1 1 0 2 1; 0 1 1 0 0]) + #println(q) + #println(q.LATTICE_POINTS) + + #monomials = convert(Matrix{Int64}, poly.INTERIOR_LATTICE_POINTS)[:, 3:end] # first coordinate is for homogenous coordinates and second one for eps_1 + ... + eps_k = 0 + #println(poly.INTERIOR_LATTICE_POINTS[:, 3:end]) + #println(lattice_points(Polyhedron(poly))) + monomials = lattice_points(Polyhedron(poly)) + #println(length(monomials)) + ##@time monomials = c_time(monomials) #convert(Vector{Vector{Int64}}, monomials) + #println(typeof(monomials)) + #@time monomials = [convert(Vector{Int64}) for m in monomials] + #monomials = convert(Matrix{Int64}, lattice_points(Polyhedron(poly)))[:, 3:end] # first coordinate is for homogenous coordinates and second one for eps_1 + ... + eps_k = 0 + #monomials = [monomials[i,:] for i in 1:size(monomials,1)] + #println(mons) + return monomials + + #poly = polytope.Polytope(INEQUALITIES=[0 0 1 0 0; 0 0 0 1 0; 0 0 0 0 1], EQUATIONS=[0 1 2 0 1; 0 1 1 2 0; 0 1 2 1 0]) + #println("vertices: ", poly.VERTICES) + #println("lattice_points: ", poly.LATTICE_POINTs) +end + +function get_monomials_of_weightspace_Xn(wts, weight) + """ + calculates all monomials in a given weightspace for lie algebras that don't have type A + input: + wts: the operator weights in eps_i + weight: lambda - mu + + output: all monomials with weight weight + + works by calculating all integer solutions to the following linear program: + [ | | ] [ x ] + [wts[1] ... wts[k] ] * [ | ] = weight + [ | | ] [ res ] + [ | | ] [ | ] + where res[i] >= 0 for all i + + example: + wts = [[1, 0, 2], [-1, 1, 1], [0, -1, 0]] (i.e. a_1 = eps_1 - eps_2, a_2 = eps_2 - eps_3, a_12 = eps_1 - eps_3) + weight = [2, 1, 0] + -> poly = polytope.Polytope(INEQUALITIES=[0 1 0 0; 0 0 1 0; 0 0 0 1], EQUATIONS=[-2 1 0 2; -1 -1 1 1; 0 0 -1 0]) + => returns + """ + wts = [reshape(w, 1, :) for w in wts] + n = length(wts) + ineq = zeros(Int64, n, n+1) + for i in 1:n + ineq[i, 1+i] = 1 + end + #equ = cat([-i for i in vec(weight)], [1 for i=1:length(weight)], dims = (2,2)) + equ = [-i for i in vec(weight)] + equ = cat(equ, [transpose(w) for w in wts] ..., dims = (2,2)) + poly = polytope.Polytope(INEQUALITIES=ineq, EQUATIONS=equ) + monomials = lattice_points(Polyhedron(poly)) + return monomials +end \ No newline at end of file diff --git a/experimental/basisLieHighestWeight/main.jl b/experimental/basisLieHighestWeight/main.jl new file mode 100644 index 000000000000..4cfdacd3e2d7 --- /dev/null +++ b/experimental/basisLieHighestWeight/main.jl @@ -0,0 +1 @@ +include("MB.jl") \ No newline at end of file From 365d04a8d7448f3fe6d17a51bd4eb72fc7df74cb Mon Sep 17 00:00:00 2001 From: Ben Wilop Date: Fri, 24 Mar 2023 10:24:16 +0100 Subject: [PATCH 02/19] basisLieHighestWeight tests --- .../basisLieHighestWeight/MB-test.jl | 78 +++ .../basisLieHighestWeight/MBOld.jl | 454 ++++++++++++++++++ test/runtests.jl | 2 + 3 files changed, 534 insertions(+) create mode 100644 test/Experimental/basisLieHighestWeight/MB-test.jl create mode 100644 test/Experimental/basisLieHighestWeight/MBOld.jl diff --git a/test/Experimental/basisLieHighestWeight/MB-test.jl b/test/Experimental/basisLieHighestWeight/MB-test.jl new file mode 100644 index 000000000000..7a3d506b24a2 --- /dev/null +++ b/test/Experimental/basisLieHighestWeight/MB-test.jl @@ -0,0 +1,78 @@ +using Oscar +using Test +using TestSetExtensions +using SparseArrays + +include("MBOld.jl") + +G = Oscar.GAP.Globals +forGap = Oscar.GAP.julia_to_gap +fromGap = Oscar.GAP.gap_to_julia + +""" +We are testing our code in multiple ways. First, we calculated two small examples per hand and compare those. Then we check basic properties of the result. +For example we know the size of our monomial basis. These properties get partially used in the algorithm and could therefore be true for false results. We +have another basic algorithm that solves the problem without the recursion, weightspaces and saving of computations. The third test compares the results we +can compute with the weaker version. +""" + +function compare_algorithms(dynkin::Char, n::Int64, lambda::Vector{Int64}) + dim, m, v = MB.basisLieHighestWeight(string(dynkin), n, lambda) # basic algorithm + w = MB.basisLieHighestWeight2(string(dynkin), n, lambda) # algorithm that needs to be tested + L = G.SimpleLieAlgebra(forGap(string(dynkin)), n, G.Rationals) + gapDim = G.DimensionOfHighestWeightModule(L, forGap(lambda)) # dimension + @test Set(m) == w # compare if result of basic and sophisticated algorithm match + @test gapDim == length(w) # check if dimension is correct +end + +function check_dimension(dynkin::Char, n::Int64, lambda::Vector{Int64}, monomial_order::String, ops::String) + w = MB.basisLieHighestWeight2(string(dynkin), n, lambda, monomial_order=monomial_order, ops=ops) # algorithm that needs to be tested + L = G.SimpleLieAlgebra(forGap(string(dynkin)), n, G.Rationals) + gapDim = G.DimensionOfHighestWeightModule(L, forGap(lambda)) # dimension + @test gapDim == length(w) # check if dimension is correct +end + + +@testset ExtendedTestSet "Test basisLieHighestWeight" begin + # TODO: add test for basis (not just dimension) + @testset "Known examples" begin + @test MB.basisLieHighestWeight2("A", 2, [1,0]) == Set([[0,0,0], [0,0,1], [1,0,0]]) + @test MB.basisLieHighestWeight2("A", 2, [1,0], ops=[1,2,1]) == Set([[0,0,0], [0,1,1], [1,0,0]]) + end + @testset "Compare with simple algorithm and check dimension" begin + @testset "Dynking type $dynkin" for dynkin in ('A', 'B', 'C', 'D') + @testset "n = $n" for n in 1:4 + if (!(dynkin == 'B' && n < 2) && !(dynkin == 'C' && n < 2) && !(dynkin == 'D' && n < 4)) + for i in 1:n # w_i + lambda = zeros(Int64,n) + lambda[i] = 1 + compare_algorithms(dynkin, n, lambda) + end + + if (n > 1) + lambda = [1, (0 for i in 1:n-2)..., 1] # w_1 + w_n + compare_algorithms(dynkin, n, lambda) + end + + if (n < 4) + lambda = ones(Int64,n) # w_1 + ... + w_n + compare_algorithms(dynkin, n, lambda) + end + end + end + end + end + @testset "Check dimension" begin + @testset "Monomial order $monomial_order" for monomial_order in ("Lex", "GLex", "GRevLex", "GRevLex") + @testset "Operators $ops" for ops in ("regular", "longest-word") + check_dimension('A', 3, [1,1,1], monomial_order, ops) + # #check_dimension('B', 3, [2,1,0], monomial_order, ops) + # #check_dimension('C', 3, [1,1,1], monomial_order, ops) + # #check_dimension('D', 4, [3,0,1,1], monomial_order, ops) + # #check_dimension('F', 4, [2,0,1,0], monomial_order, ops) + # #check_dimension('G', 2, [1,0], monomial_order, ops) + # #check_dimension('G', 2, [2,2], monomial_order, ops) + end + end + end +end diff --git a/test/Experimental/basisLieHighestWeight/MBOld.jl b/test/Experimental/basisLieHighestWeight/MBOld.jl new file mode 100644 index 000000000000..530effe5b6bc --- /dev/null +++ b/test/Experimental/basisLieHighestWeight/MBOld.jl @@ -0,0 +1,454 @@ +#--- Bens "Lernkommentare" mit #--- oder """...""" in Methode gekenzeichnet + + +module MBOld + +export basisLieHighestWeight # use parallel = true for parallel computing + +using Oscar +using SparseArrays + +#### vector space bases + +ZZ = Int +TVec = SparseVector{ZZ, Int} #--- Werte sind ZZ, Indizies sind Int (TVec ist Datentyp der Basisvektoren in basisLieHighestWeight) +Short = UInt8 # for exponents of monomials; max. 255 + +struct VSBasis + A::Vector{TVec} #--- Vektor von Basisvektoren + pivot::Vector{Int} #--- Vektor von Pivotelementen, d.h. pivot[i] ist erster nichtnull Index von A[i] +end + + +nullSpace() = VSBasis([], []) #--- leerer Vektorraum + + +function normalize(v::TVec) + """ + divides vector by gcd of nonzero entries, returns vector and first nonzero index + used: addAndReduce! + """ + dropzeros!(v) #--- deletes stored zeros in SparsedArray (in-place, hingegen würde dropzeros(v) Kopie zurückgeben) + if isempty(v.nzind) #--- v.nzind sind abgespeicherte Werte + #--- v.nzval sind abgespeicherte Indizies (der Größe nach geordnet, startet bei 1) + return (0, 0) + end + + pivot = v.nzind[1] #--- erster != 0 Eintrag im Vektor, d.h. der oberste + + return v .÷ gcd(v.nzval), pivot #--- durch ggT teilen +end + + +reduceCol(a, b, i::Int) = a*b[i] - b*a[i] #--- a = reduceCol(a, b, i) erzeugt Nulleintrag in a[i] durch elementare Zeilenumformungen + #--- Werte bleiben Integers + + +function addAndReduce!(sp::VSBasis, v::TVec) + """ + for each pivot of sp.A we make entry of v zero and return the result + 0 => linear dependent + * => linear independent, new column element of sp.A since it increases basis + invariants: the row of a pivotelement in any column in A is 0 (except the pivotelement) + elements of A are integers, gcd of each column is 1 + """ + A = sp.A + pivot = sp.pivot + v, newPivot = normalize(v) + if newPivot == 0 #--- v ist Nullvektor + return 0 + end + + for j = 1:length(A) + i = pivot[j] + if i != newPivot + continue + end + v = reduceCol(v, A[j], i) + v, newPivot = normalize(v) + if newPivot == 0 + return 0 + end + end + + pos = findfirst(pivot .> newPivot) + if (pos === nothing) + pos = length(pivot) + 1 + end + + insert!(A, pos, v) + insert!(pivot, pos, newPivot) + + return v +end + + +#### Lie algebras + +G = Oscar.GAP.Globals +forGap = Oscar.GAP.julia_to_gap +fromGap = Oscar.GAP.gap_to_julia + + +function lieAlgebra(t::String, n::Int) + L = G.SimpleLieAlgebra(forGap(t), n, G.Rationals) + return L, G.ChevalleyBasis(L) +end + + +gapReshape(A) = sparse(hcat(A...)) + + +function matricesForOperators(L, hw, ops) + M = G.HighestWeightModule(L, forGap(hw)) + mats = G.List(ops, o -> G.MatrixOfAction(G.Basis(M), o)) + mats = gapReshape.(fromGap(mats)) + d = lcm(denominator.(union(mats...))) + mats = (A->ZZ.(A*d)).(mats) + return mats +end + + +function weightsForOperators(L, cartan, ops) + cartan = fromGap(cartan, recursive=false) + ops = fromGap(ops, recursive=false) + asVec(v) = fromGap(G.ExtRepOfObj(v)) + if any(iszero.(asVec.(ops))) + error("ops should be non-zero") + end + nzi(v) = findfirst(asVec(v) .!= 0) + return [ + [asVec(h*v)[nzi(v)] / asVec(v)[nzi(v)] for h in cartan] for v in ops + ] +end + +#### tensor model + +# TODO: make the first one a symmetric product, or reduce more generally + +spid(n) = spdiagm(0 => [ZZ(1) for _ in 1:n]) +sz(A) = size(A)[1] +tensorProduct(A, B) = kron(A, spid(sz(B))) + kron(spid(sz(A)), B) +tensorProducts(As, Bs) = (AB->tensorProduct(AB[1], AB[2])).(zip(As, Bs)) +tensorPower(A, n) = (n == 1) ? A : tensorProduct(tensorPower(A, n-1), A) +tensorPowers(As, n) = (A->tensorPower(A, n)).(As) + + +function tensorMatricesForOperators(L, hw, ops) + mats = [] + + for i in 1:length(hw) + if hw[i] <= 0 + continue + end + wi = Int.(1:length(hw) .== i) # i-th fundamental weight + _mats = matricesForOperators(L, wi, ops) + _mats = tensorPowers(_mats, hw[i]) + mats = mats == [] ? _mats : tensorProducts(mats, _mats) + #display(mats) + end + + return mats +end + +#### monomial basis + + +# TODO: Demazure modules + + +""" + basisLieHighestWeight(t::String, n::Int, hw::Vector{Int}; parallel::Bool = true) :: Tuple{Vector{Vector{Short}},Vector{TVec}} + +Compute a monomial basis for the highest weight module with highest weight ``hw`` (in terms of the fundamental weights), for a simple Lie algebra of type ``t`` and rank ``n``. + +Example +====== +```jldoctest +julia> dim, monomials, vectors = PolyBases.MB.basisLieHighestWeight("A", 2, [1,0]) +(3, Vector{UInt8}[[0x00, 0x00, 0x00], [0x01, 0x00, 0x00], [0x00, 0x00, 0x01]], SparseArrays.SparseVector{Int64, Int64}[ [1] = 1, [2] = 1, [3] = 1]) +``` +""" + +function basisLieHighestWeight(t::String, n::Int, hw::Vector{Int}; roots = [], parallel::Bool = false) #--- :: Tuple{Int64,Vector{Vector{Short}},Vector{TVec}} + # TODO: flag for root ordering + L, CH = lieAlgebra(t, n) #--- L ist Lie Algebra vom Typ t, n (z.B: "A", 2) durch Funktion GAP.SimpleLieAlgebra(t,n) + #--- G ist ChevalleyBasis von L durch GAP.ChevalleyBasis(L) + #--- CH[1] obere strikte Dreiecksmatrizen, CH[2] untere strikte Dreiecksmatrizen, CH[3] Diagonalmatrizen + + ops = CH[1] # positive root vectors + # .. reorder.. + wts = weightsForOperators(L, CH[3], ops) + wts = (v->Int.(v)).(wts) + + + # Keep only elements of ops which weights are listed in roots, in order of roots + #if !isempty(roots) + # ops = fromGap(ops, recursive = false) + # ops_vec = [] + # for i in 1:length(wts) + # if wts[i] in roots + # push!(ops_vec, ops[i]) + # end + # end + # ops = forGap(ops_vec, recursive = false) + #end + + #--- mats speichert die Matrizen g_i für (g_1^a_1 * ... * g_k^a_k)*v0 ab. + mats = tensorMatricesForOperators(L, hw, ops) + # display(wts) + # rnd = rand(length(wts[1])) + # rnd /= norm(rnd) + # wts = (v->round(dot(rnd,v), sigdigits=4)).(wts) + # display(wts) + + d = sz(mats[1]) + #display(mats) + #display(d) + hwv = spzeros(ZZ, d); hwv[1] = 1 + # TODO: (okay for now) + # here we assume the first vector in G.Basis(M) is a highest weight vector + #display(hwv) + #display.(1. .* (mats)) + + #--- + #println("--------------------------------------") + #println("Parameter für compute(hwv, mats, wts)") + #println("") + #println("hwv:") + #display(collect(hwv)) + #println("") + #println("mats:") + #for i=1:length(mats) + # println(string("mats[", i, "]:")) + # #display(collect(mats[i])) + # display(mats[i]) + #end + #println("") + #println("wts:") + #display(wts) + #println("") + + res = compute(hwv, mats, wts, parallel = parallel) + + return length(res[1]), res... +end + +nullMon(m) = zeros(Short, m) + + +######### compute_0 ################### +# serial computing +function compute_0(v0, mats, wts::Vector{Vector{Int}}) + m = length(mats) #--- + monomials = [nullMon(m)] #--- hier speichern wir die Monombasis. Ein Eintrag steht für Potenzen unserer Basiselemente + #--- nullMon ist leeres Monom, also nur m-Nullen bzw. die Identität + lastPos = 0 #--- speichert für die untere while-Schleife die Anzahl der Basiselemente nach dem letzten Durchlauf + + #--- jedes Monom erhaelt id + #--- id(mon) returnt die id des entsprechenden mon. + id(mon) = sum((1 << (sum(mon[1:i])+i-1) for i in 1:m-1) , init = 1) # init = 1 for case m = 1 + e = [Short.(1:m .== i) for i in 1:m] #--- Einheitsvektoren z.B.: e = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] für m = 3 + maxid(deg) = id(deg.*e[1]) #--- returnt maximale id für Monom vom Grad deg (worst case ist [1, 0, 0], da dann erste Potenz in jedem Summanden ist) + + #--- Sperrung von Monome + blacklists = [falses(maxid(0))] #--- Monome die bereits in der Basis enthalten sind, i-ter Eintrag ist Sperrung für Monome von Grad i + blacklists[end][id(monomials[1])] = 1 #--- Für Grad 0, d.h. konstant, ist die letzte id gesperrt da 0-Polynom + newMons(deg) = (push!(blacklists, falses(maxid(deg)))) # Neuer Eintrag um Sperrung der Monome von Grad deg zu speichern + checkMon(mon) = blacklists[end-1][id(mon)] #--- returnt ob Monom gesperrt ist. Man nimmt sich den vorletzten Eintrag, weil in der Berechnung + #--- im while-Loop der letzte Eintrag immer der Eintrag für den derzeitigen Grad ist + setMon(mon) = (blacklists[end][id(mon)] = true) #--- sperrt monom (im while loop ist deg immer maximal für mon und damit im letzten Eintrag von blacklists) + + + #--- Speicher für while-loop + vectors = [v0] #--- von Monombasis mit (g_1^a_1 * ... * g_k^a_k)*v0 erzeugte Basisvektoren von V=R^(n+1) + weights = [0 * wts[1]] + space = Dict(weights[1] => nullSpace()) #--- Erzeugnis der bisherigen Basisvektoren. + addAndReduce!(space[weights[1]], v0) #--- Fügt Span von Basisvektor v0 ein + + deg = 0 + + #--- iteriere durch alle Monome in reverse lexicographical order + #--- Bsp: [[0, 0], [1, 0], [0, 1], [2, 0], [1, 1], [0, 2]] + #--- while-loop iteriert durch Grad deg, also Summe der Einträge + #--- i iteriert durch ersten nicht-null Index + #--- di ist neue Potenz an Stelle i (d.h. 1 höher als vorher) + #--- p durchläuft alle Monomome mit deg-1 (monomials[startPos:newPos]), um durch Addition eines e[i] alle Monome von deg erreichen + #--- innerster Durchlauf: Erhöhe bei allen bereits verwendeten Monomen Potenz i um 1 auf di, ansonsten mache nichts + #--- solange bis für einen Grad kein Polynom mehr hinzugefügt worden ist + while length(monomials) > lastPos + + startPos = lastPos + 1 + newPos = length(monomials) + deg = deg + 1 + newMons(deg) #--- Schaffung neues Speicherplatzes in blacklists. Muss iterativ erweitert werden, weil der maximale Grad der Basis unbekannt ist + + for i in 1:m, di in deg:-1:1 + for p in startPos:newPos #--- monomials[startPos:newPos] sind alle hinzugefügten Monome von deg-1 + + #--- Siebe Monome für rev-lex Ordnung + if !all(monomials[p][1:i-1] .== 0) #--- Monome mit nicht-null vor Index i wurden bereits mit kleinerem i getroffen + continue + end + #--- neues monom soll an Stelle i Potenz di haben + if monomials[p][i]+1 > di + startPos = p+1 #--- wegen rev-lex Ordnung wird dieses Monom nie wieder erweitert -> für Grad deg immer erst danach beginnen + continue + end + if monomials[p][i]+1 < di + break #--- break, da monomials bereits rev-lex geordnet ist und alle späteren von Grad deg-1 noch kleinere Potenz bei i haben + end + + mon = monomials[p] + e[i] #--- mögliches neues Monom + + #--- nur mon behalten, falls jeder Index != 0 durch verwendetes Monom des vorherigen Schrittes mit +e[j] hervorging. + #--- folgt nicht automatisch induktiv, da mon-e[j] zwar überprüft worden ist, aber vielleicht neuer Vektor linear abhängig war + if any(i != j && mon[j] > 0 && !checkMon(mon-e[j]) for j in 1:m) + continue + end + + wt = weights[p] + wts[i] + if !haskey(space, wt) + space[wt] = nullSpace() + end + + vec = mats[i] * vectors[p] #--- vec ist neuer potenzieller Kandidat für Basis. + vec = addAndReduce!(space[wt], vec) #--- vec ist altes vec ohne Anteil des bereits vorhandenen Erzeugnisses. Wenn 0, dann linear abhängig zu altem Unterraum + if vec == 0 #--- wenn vec linear abhängig war, fügen wir vec nicht hinzu + continue + end + + #display(v) + #display(1. .* space.A) + setMon(mon) #--- wenn vec linear unabhängig war wird vec zur Basis hinzugefügt und das zugehörige Monom gespeichert + push!(monomials, mon) + push!(weights, wt) + push!(vectors, vec) + end + end + lastPos = newPos + end + + return monomials, vectors +end + + +############ compute_p ######################## +# parallel computing +function compute_p(v0, mats, wts::Vector{Vector{Int}}) + m = length(mats) + monomials = [nullMon(m)] + lastPos = 0 + + id(mon) = sum((1 << (sum(mon[1:i])+i-1) for i in 1:m-1), init = 1) # init = 1 for case m = 1 + e = [Short.(1:m .== i) for i in 1:m] + maxid(deg) = id(deg.*e[1]) + + blacklists = [falses(maxid(0))] + blacklists[end][id(monomials[1])] = 1 + newMons(deg) = (push!(blacklists, falses(maxid(deg)))) + checkMon(mon) = blacklists[end-1][id(mon)] + setMon(mon) = (blacklists[end][id(mon)] = true) + + vectors = [v0] + weights = [0 * wts[1]] + idweight = Dict(weights[1] => 1) + nweights = 1 + space = Dict(1 => nullSpace()) + addAndReduce!(space[1], v0) + + deg = 0 + while length(monomials) > lastPos + startPos = lastPos+1 + newPos = length(monomials) + deg = deg + 1 + newMons(deg) + + num = 0 + jobs = Dict{Int, Vector{Tuple{Int, Vector{Short}, Vector{Int64}, SparseMatrixCSC{Int, Int}, SparseVector{Int, Int}, VSBasis}}}() + + for i in 1:m, di in deg:-1:1 + for p in startPos:newPos + # lex iterator + if !all(monomials[p][1:i-1] .== 0) || + monomials[p][i] + 1 > di + startPos = p + 1 + continue + elseif monomials[p][i] + 1 < di + break + end + + mon = monomials[p] + e[i] + + if any(i != j && mon[j] > 0 && !checkMon(mon - e[j]) for j in 1:m) + continue + end + + num += 1 + wt = weights[p] + wts[i] + + if !haskey(idweight, wt) + nweights += 1 + idweight[wt] = nweights + end + idwt = idweight[wt] + + if !haskey(space, idwt) + space[idwt] = nullSpace() + end + + jo = (num, mon, wt, mats[i], vectors[p], space[idwt]) + if !haskey(jobs, idwt) + jobs[idwt] = [jo] + else + push!(jobs[idwt], jo) + end + #display(typeof(jo)) + end + end + #display(typeof(jobs)) + + #display(Threads.nthreads()) + + res = Vector{Any}(nothing, num) + idwts = [k for (k, l) in jobs if !isempty(l)] + Threads.@threads for idwt in idwts + for (i, mon, wt, A, v, sp) in jobs[idwt] + # this is the heavy lifting + # (in particular, the matrix product A * v) + w = addAndReduce!(sp, A * v) + if w != 0 + res[i] = (mon, wt, w) + end + end + end + + #display(res) + + for r in res + if r == nothing + continue + end + (mon, wt, vec) = r + setMon(mon) + push!(monomials, mon) + push!(vectors, vec) + push!(weights, wt) + end + + lastPos = newPos + end + + #display(idweight) + #display(vectors) + #display([(i, sp.A) for (i, sp) in space if length(sp.pivot) > 0]) + return monomials, vectors +end + + +################## +# chooses parallel / serial computing +# parallel true to use parallel computing through function compute_p +compute(v0, mats, wts::Vector{Vector{Int}}; parallel::Bool = false) = parallel ? compute_p(v0, mats, wts) : compute_0(v0, mats, wts) + +end # module diff --git a/test/runtests.jl b/test/runtests.jl index 5a6b1b3764b8..d682d42322aa 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -125,6 +125,8 @@ include("Serialization/runtests.jl") include("StraightLinePrograms/runtests.jl") +include("experimental/basisLieHighestWeight/MB-test.jl") + @static if compiletimes Base.cumulative_compile_timing(false); end From b413207c019e99776e00ff838bd92b591ff2e8ba Mon Sep 17 00:00:00 2001 From: Ben Wilop Date: Fri, 24 Mar 2023 11:31:39 +0100 Subject: [PATCH 03/19] deleted german comments, adapted tests, removed LongestWord --- .../{MB.jl => BasisLieHighestWeight.jl} | 24 ++- .../basisLieHighestWeight/LongestWord.jl | 50 ------ .../basisLieHighestWeight/MonomialOrder.jl | 22 --- .../basisLieHighestWeight/NewMonomial.jl | 1 - .../basisLieHighestWeight/VectorSpaceBases.jl | 31 ++-- experimental/basisLieHighestWeight/main.jl | 3 +- .../basisLieHighestWeight/MB-test.jl | 20 +-- .../basisLieHighestWeight/MBOld.jl | 149 ++---------------- 8 files changed, 54 insertions(+), 246 deletions(-) rename experimental/basisLieHighestWeight/{MB.jl => BasisLieHighestWeight.jl} (96%) delete mode 100644 experimental/basisLieHighestWeight/LongestWord.jl diff --git a/experimental/basisLieHighestWeight/MB.jl b/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl similarity index 96% rename from experimental/basisLieHighestWeight/MB.jl rename to experimental/basisLieHighestWeight/BasisLieHighestWeight.jl index 4c13203bec60..9311c18652b1 100644 --- a/experimental/basisLieHighestWeight/MB.jl +++ b/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl @@ -1,4 +1,4 @@ -module MB +module BasisLieHighestWeight export basisLieHighestWeight2 export is_fundamental @@ -19,8 +19,6 @@ fromGap = Oscar.GAP.gap_to_julia function basisLieHighestWeight2(t, n, hw; ops = "regular", known_monomials = [], monomial_order = "GRevLex", cache_size::Int = 1000000, parallel::Bool = false, return_no_minkowski::Bool = false, return_ops::Bool = false) """ Compute a monomial basis for the highest weight module with highest weight ``hw`` (in terms of the fundamental weights), for a simple Lie algebra of type ``t`` and rank ``n``. - - Pseudocode: """ # The function precomputes objects that are independent of the highest weight and can be used in all recursion steps. Then it starts the recursion and returns the result. @@ -48,6 +46,16 @@ function basisLieHighestWeight2(t, n, hw; ops = "regular", known_monomials = [], end end +function sub_simple_refl(word, L, n) + """ + substitute simple reflections (i,i+1), saved in dec by i, with E_{i,i+1} + """ + R = G.RootSystem(L) + CG = fromGap(G.CanonicalGenerators(R)[1], recursive = false) + ops = forGap([CG[i] for i in word], recursive = false) + return ops +end + function get_ops(t,n, ops, L, CH) """ handles user input for ops @@ -75,9 +83,9 @@ function get_ops(t,n, ops, L, CH) println("all values of ops need to between 1 and the rank of the lie algebra.") end # If one of the conditions is met, the algorithms works for sure. Otherwise a warning is printed (and can be ignored). - if !(is_longest_weyl_word(t, n, ops)) && !(Set(ops) == [i for i=1:n]) - println("WARNING: ops may be incorrect input.") - end + #if !(is_longest_weyl_word(t, n, ops)) && !(Set(ops) == [i for i=1:n]) + # println("WARNING: ops may be incorrect input.") + #end ops = sub_simple_refl(ops, L, n) return ops end @@ -304,7 +312,7 @@ function add_by_hand(t, n, L, hw, ops, wts, wts_eps, monomial_order, gapDim, set end else for weightspace in weightspaces - println("known memory: ", Int(Base.Sys.free_memory()) / 2^20) + #println("known memory: ", Int(Base.Sys.free_memory()) / 2^20) #println("size space: ", Int(Base.summarysize(space)) / 2^20) #println("size calc_monomials: ", Int(Base.summarysize(calc_monomials)) / 2^20) add_known_monomials!(weightspace, set_mon_in_weightspace, m, wts, mats, calc_monomials, space, e, cache_size) @@ -322,7 +330,7 @@ function add_by_hand(t, n, L, hw, ops, wts, wts_eps, monomial_order, gapDim, set else for weightspace in weightspaces #println("varinfo: ", InteractiveUtils.varinfo(MB3)) - println("new memory: ", Int(Base.Sys.free_memory()) / 2^20) + #println("new memory: ", Int(Base.Sys.free_memory()) / 2^20) #println("size space: ", Int(Base.summarysize(space)) / 2^20) #println("size calc_monomials: ", Int(Base.summarysize(calc_monomials)) / 2^20) add_new_monomials!(t, n, mats, wts, monomial_order, weightspace, wts_eps, set_mon_in_weightspace, calc_monomials, space, e, cache_size, set_mon, m) diff --git a/experimental/basisLieHighestWeight/LongestWord.jl b/experimental/basisLieHighestWeight/LongestWord.jl deleted file mode 100644 index df9f4d7aef22..000000000000 --- a/experimental/basisLieHighestWeight/LongestWord.jl +++ /dev/null @@ -1,50 +0,0 @@ -#using Gapjm - -G = Oscar.GAP.Globals -forGap = Oscar.GAP.julia_to_gap -fromGap = Oscar.GAP.gap_to_julia - -#function longest_weyl_word(t, n) -# """ -# generates a reduced expression of the longest weylword of type (t,n) by choosing uniformly a random reflection that is not leftdescending -# the resulting longest words are not uniformly distributed -# """ -# W = Gapjm.coxgroup(Symbol(t),n) # Weyl-group -# S = Gapjm.gens(W) # generators of W (simple reflections) -# m = length(S) -# p = W() # id -# word = [] # generated word -# -# # extend p with reflection that are not leftdescending until not possible (i.e. reached longest word) -# while true -# not_desc = [i for i=1:m if !(i in Gapjm.leftdescents(W,p))] # set of i s.t. length(S[i]*p) > length(p) -# if length(not_desc) >= 1 -# i = rand(not_desc) -# push!(word, i) -# p = S[i]*p -# else -# break -# end -# end -# return word -#end - -#function is_longest_weyl_word(t,n,word) -# """ -# returns if word is a reduced expression of the longest weyl word of type (t,n) -# is_longest_weyl_word(t,n,longest_weyl_word(t, n)) is always true -# """ -# W = Gapjm.coxgroup(Symbol(t),n) # Weyl-group -# p = W(word ...) # group element of word -# return p == longest(W) # is word longest word? -#end - -function sub_simple_refl(word, L, n) - """ - substitute simple reflections (i,i+1), saved in dec by i, with E_{i,i+1} - """ - R = G.RootSystem(L) - CG = fromGap(G.CanonicalGenerators(R)[1], recursive = false) - ops = forGap([CG[i] for i in word], recursive = false) - return ops -end diff --git a/experimental/basisLieHighestWeight/MonomialOrder.jl b/experimental/basisLieHighestWeight/MonomialOrder.jl index 2efdcda7ab2e..630d7e9a3226 100644 --- a/experimental/basisLieHighestWeight/MonomialOrder.jl +++ b/experimental/basisLieHighestWeight/MonomialOrder.jl @@ -1,27 +1,5 @@ # manages methods for different orders of monomials -function highest_calc_sub_monomial(mon::Vector{Int}, calc_monomials) - """ - returns the key in calc_monomials that can be extended by the least amount of left-operations to mon - """ - sub_mon = copy(mon) - - m = length(mon) - for i in 1:m - while sub_mon[i] > 0 - #println(sub_mon) - #println(calc_monomials) - if haskey(calc_monomials, sub_mon) - return sub_mon - else - sub_mon[i] -= 1 - end - end - end - #println(sub_mon) - return sub_mon # [0 for i in 1:m] -end - function lt_monomial_order(monomial_order) """ Returns the desired monomial_order function diff --git a/experimental/basisLieHighestWeight/NewMonomial.jl b/experimental/basisLieHighestWeight/NewMonomial.jl index c04f9f7d43e3..4cc12b7782ca 100644 --- a/experimental/basisLieHighestWeight/NewMonomial.jl +++ b/experimental/basisLieHighestWeight/NewMonomial.jl @@ -11,7 +11,6 @@ include("./VectorSpaceBases.jl") include("./TensorModels.jl") include("./LieAlgebras.jl") include("./MonomialOrder.jl") -include("./LongestWord.jl") include("./WeylPolytope.jl") G = Oscar.GAP.Globals diff --git a/experimental/basisLieHighestWeight/VectorSpaceBases.jl b/experimental/basisLieHighestWeight/VectorSpaceBases.jl index 83d82d25df79..9cee6ca17734 100644 --- a/experimental/basisLieHighestWeight/VectorSpaceBases.jl +++ b/experimental/basisLieHighestWeight/VectorSpaceBases.jl @@ -4,17 +4,17 @@ using Oscar using SparseArrays ZZ = Int -TVec = SparseVector{ZZ, Int} #--- Werte sind ZZ, Indizies sind Int (TVec ist Datentyp der Basisvektoren in basisLieHighestWeight) +TVec = SparseVector{ZZ, Int} # values ZZ, indices Int (TVec is datatype of basisvectors basisLieHighestWeight) Short = UInt8 # for exponents of monomials; max. 255 struct VSBasis - A::Vector{TVec} #--- Vektor von Basisvektoren - pivot::Vector{Int} #--- Vektor von Pivotelementen, d.h. pivot[i] ist erster nichtnull Index von A[i] - dim::Vector{Int} #--- dimension + A::Vector{TVec} # vector of basisvectors + pivot::Vector{Int} # vector of pivotelements, i.e. pivot[i] is first nonzero element of A[i] + dim::Vector{Int} # dimension end -nullSpace() = VSBasis([], [], []) #--- leerer Vektorraum +nullSpace() = VSBasis([], [], []) # empty Vektorraum function normalize(v::TVec) @@ -22,21 +22,18 @@ function normalize(v::TVec) divides vector by gcd of nonzero entries, returns vector and first nonzero index used: addAndReduce! """ - dropzeros!(v) #--- deletes stored zeros in SparsedArray (in-place, hingegen würde dropzeros(v) Kopie zurückgeben) - if isempty(v.nzind) #--- v.nzind sind abgespeicherte Werte - #--- v.nzval sind abgespeicherte Indizies (der Größe nach geordnet, startet bei 1) - #return (0, 0) + dropzeros!(v) + if isempty(v.nzind) return (v, 0) end - pivot = v.nzind[1] #--- erster != 0 Eintrag im Vektor, d.h. der oberste + pivot = v.nzind[1] # first nonzero element of vector - return v .÷ gcd(v.nzval), pivot #--- durch ggT teilen + return v .÷ gcd(v.nzval), pivot end -reduceCol(a, b, i::Int) = a*b[i] - b*a[i] #--- a = reduceCol(a, b, i) erzeugt Nulleintrag in a[i] durch elementare Zeilenumformungen - #--- Werte bleiben Integers +reduceCol(a, b, i::Int) = a*b[i] - b*a[i] # create zero entry in a function addAndReduce!(sp::VSBasis, v::TVec) @@ -51,18 +48,17 @@ function addAndReduce!(sp::VSBasis, v::TVec) pivot = sp.pivot dim = sp.dim - if dim == [] #--- update dimension + if dim == [] # update dimension insert!(dim, 1, length(v)) end - if length(A) == sp.dim[1] #-- space already full => linear dependence guaranteed + if length(A) == sp.dim[1] # space already full => linear dependence guaranteed v = spzeros(ZZ, sp.dim[1]) return v end v, newPivot = normalize(v) - if newPivot == 0 #--- v ist Nullvektor - #return 0 + if newPivot == 0 # v zero vector return v end @@ -74,7 +70,6 @@ function addAndReduce!(sp::VSBasis, v::TVec) v = reduceCol(v, A[j], i) v, newPivot = normalize(v) if newPivot == 0 - #return 0 return v end end diff --git a/experimental/basisLieHighestWeight/main.jl b/experimental/basisLieHighestWeight/main.jl index 4cfdacd3e2d7..4bfca765ad45 100644 --- a/experimental/basisLieHighestWeight/main.jl +++ b/experimental/basisLieHighestWeight/main.jl @@ -1 +1,2 @@ -include("MB.jl") \ No newline at end of file +include("BasisLieHighestWeight.jl") +export MB \ No newline at end of file diff --git a/test/Experimental/basisLieHighestWeight/MB-test.jl b/test/Experimental/basisLieHighestWeight/MB-test.jl index 7a3d506b24a2..2f0d33907c42 100644 --- a/test/Experimental/basisLieHighestWeight/MB-test.jl +++ b/test/Experimental/basisLieHighestWeight/MB-test.jl @@ -17,16 +17,16 @@ can compute with the weaker version. """ function compare_algorithms(dynkin::Char, n::Int64, lambda::Vector{Int64}) - dim, m, v = MB.basisLieHighestWeight(string(dynkin), n, lambda) # basic algorithm - w = MB.basisLieHighestWeight2(string(dynkin), n, lambda) # algorithm that needs to be tested + dim, m, v = MBOld.basisLieHighestWeight(string(dynkin), n, lambda) # basic algorithm + w = BasisLieHighestWeight.basisLieHighestWeight2(string(dynkin), n, lambda) # algorithm that needs to be tested L = G.SimpleLieAlgebra(forGap(string(dynkin)), n, G.Rationals) gapDim = G.DimensionOfHighestWeightModule(L, forGap(lambda)) # dimension @test Set(m) == w # compare if result of basic and sophisticated algorithm match @test gapDim == length(w) # check if dimension is correct end -function check_dimension(dynkin::Char, n::Int64, lambda::Vector{Int64}, monomial_order::String, ops::String) - w = MB.basisLieHighestWeight2(string(dynkin), n, lambda, monomial_order=monomial_order, ops=ops) # algorithm that needs to be tested +function check_dimension(dynkin::Char, n::Int64, lambda::Vector{Int64}, monomial_order::String) + w = BasisLieHighestWeight.basisLieHighestWeight2(string(dynkin), n, lambda, monomial_order=monomial_order, ops=ops) # algorithm that needs to be tested L = G.SimpleLieAlgebra(forGap(string(dynkin)), n, G.Rationals) gapDim = G.DimensionOfHighestWeightModule(L, forGap(lambda)) # dimension @test gapDim == length(w) # check if dimension is correct @@ -36,11 +36,11 @@ end @testset ExtendedTestSet "Test basisLieHighestWeight" begin # TODO: add test for basis (not just dimension) @testset "Known examples" begin - @test MB.basisLieHighestWeight2("A", 2, [1,0]) == Set([[0,0,0], [0,0,1], [1,0,0]]) - @test MB.basisLieHighestWeight2("A", 2, [1,0], ops=[1,2,1]) == Set([[0,0,0], [0,1,1], [1,0,0]]) + @test BasisLieHighestWeight.basisLieHighestWeight2("A", 2, [1,0]) == Set([[0,0,0], [0,0,1], [1,0,0]]) + @test BasisLieHighestWeight.basisLieHighestWeight2("A", 2, [1,0], ops=[1,2,1]) == Set([[0,0,0], [0,1,1], [1,0,0]]) end @testset "Compare with simple algorithm and check dimension" begin - @testset "Dynking type $dynkin" for dynkin in ('A', 'B', 'C', 'D') + @testset "Dynkin type $dynkin" for dynkin in ('A', 'B', 'C', 'D') @testset "n = $n" for n in 1:4 if (!(dynkin == 'B' && n < 2) && !(dynkin == 'C' && n < 2) && !(dynkin == 'D' && n < 4)) for i in 1:n # w_i @@ -64,15 +64,15 @@ end end @testset "Check dimension" begin @testset "Monomial order $monomial_order" for monomial_order in ("Lex", "GLex", "GRevLex", "GRevLex") - @testset "Operators $ops" for ops in ("regular", "longest-word") - check_dimension('A', 3, [1,1,1], monomial_order, ops) + #@testset "Operators $ops" for ops in ("regular", "longest-word") + check_dimension('A', 3, [1,1,1], monomial_order) # #check_dimension('B', 3, [2,1,0], monomial_order, ops) # #check_dimension('C', 3, [1,1,1], monomial_order, ops) # #check_dimension('D', 4, [3,0,1,1], monomial_order, ops) # #check_dimension('F', 4, [2,0,1,0], monomial_order, ops) # #check_dimension('G', 2, [1,0], monomial_order, ops) # #check_dimension('G', 2, [2,2], monomial_order, ops) - end + #end end end end diff --git a/test/Experimental/basisLieHighestWeight/MBOld.jl b/test/Experimental/basisLieHighestWeight/MBOld.jl index 530effe5b6bc..54141c18d2ed 100644 --- a/test/Experimental/basisLieHighestWeight/MBOld.jl +++ b/test/Experimental/basisLieHighestWeight/MBOld.jl @@ -1,4 +1,4 @@ -#--- Bens "Lernkommentare" mit #--- oder """...""" in Methode gekenzeichnet + module MBOld @@ -11,16 +11,16 @@ using SparseArrays #### vector space bases ZZ = Int -TVec = SparseVector{ZZ, Int} #--- Werte sind ZZ, Indizies sind Int (TVec ist Datentyp der Basisvektoren in basisLieHighestWeight) -Short = UInt8 # for exponents of monomials; max. 255 +TVec = SparseVector{ZZ, Int} +Short = UInt8 struct VSBasis - A::Vector{TVec} #--- Vektor von Basisvektoren - pivot::Vector{Int} #--- Vektor von Pivotelementen, d.h. pivot[i] ist erster nichtnull Index von A[i] + A::Vector{TVec} + pivot::Vector{Int} end -nullSpace() = VSBasis([], []) #--- leerer Vektorraum +nullSpace() = VSBasis([], []) function normalize(v::TVec) @@ -28,20 +28,18 @@ function normalize(v::TVec) divides vector by gcd of nonzero entries, returns vector and first nonzero index used: addAndReduce! """ - dropzeros!(v) #--- deletes stored zeros in SparsedArray (in-place, hingegen würde dropzeros(v) Kopie zurückgeben) - if isempty(v.nzind) #--- v.nzind sind abgespeicherte Werte - #--- v.nzval sind abgespeicherte Indizies (der Größe nach geordnet, startet bei 1) + dropzeros!(v) + if isempty(v.nzind) return (0, 0) end - pivot = v.nzind[1] #--- erster != 0 Eintrag im Vektor, d.h. der oberste + pivot = v.nzind[1] - return v .÷ gcd(v.nzval), pivot #--- durch ggT teilen + return v .÷ gcd(v.nzval), pivot end -reduceCol(a, b, i::Int) = a*b[i] - b*a[i] #--- a = reduceCol(a, b, i) erzeugt Nulleintrag in a[i] durch elementare Zeilenumformungen - #--- Werte bleiben Integers +reduceCol(a, b, i::Int) = a*b[i] - b*a[i] function addAndReduce!(sp::VSBasis, v::TVec) @@ -55,7 +53,7 @@ function addAndReduce!(sp::VSBasis, v::TVec) A = sp.A pivot = sp.pivot v, newPivot = normalize(v) - if newPivot == 0 #--- v ist Nullvektor + if newPivot == 0 return 0 end @@ -237,9 +235,7 @@ end nullMon(m) = zeros(Short, m) -######### compute_0 ################### -# serial computing -function compute_0(v0, mats, wts::Vector{Vector{Int}}) +function compute(v0, mats, wts::Vector{Vector{Int}}) m = length(mats) #--- monomials = [nullMon(m)] #--- hier speichern wir die Monombasis. Ein Eintrag steht für Potenzen unserer Basiselemente #--- nullMon ist leeres Monom, also nur m-Nullen bzw. die Identität @@ -332,123 +328,4 @@ function compute_0(v0, mats, wts::Vector{Vector{Int}}) return monomials, vectors end - -############ compute_p ######################## -# parallel computing -function compute_p(v0, mats, wts::Vector{Vector{Int}}) - m = length(mats) - monomials = [nullMon(m)] - lastPos = 0 - - id(mon) = sum((1 << (sum(mon[1:i])+i-1) for i in 1:m-1), init = 1) # init = 1 for case m = 1 - e = [Short.(1:m .== i) for i in 1:m] - maxid(deg) = id(deg.*e[1]) - - blacklists = [falses(maxid(0))] - blacklists[end][id(monomials[1])] = 1 - newMons(deg) = (push!(blacklists, falses(maxid(deg)))) - checkMon(mon) = blacklists[end-1][id(mon)] - setMon(mon) = (blacklists[end][id(mon)] = true) - - vectors = [v0] - weights = [0 * wts[1]] - idweight = Dict(weights[1] => 1) - nweights = 1 - space = Dict(1 => nullSpace()) - addAndReduce!(space[1], v0) - - deg = 0 - while length(monomials) > lastPos - startPos = lastPos+1 - newPos = length(monomials) - deg = deg + 1 - newMons(deg) - - num = 0 - jobs = Dict{Int, Vector{Tuple{Int, Vector{Short}, Vector{Int64}, SparseMatrixCSC{Int, Int}, SparseVector{Int, Int}, VSBasis}}}() - - for i in 1:m, di in deg:-1:1 - for p in startPos:newPos - # lex iterator - if !all(monomials[p][1:i-1] .== 0) || - monomials[p][i] + 1 > di - startPos = p + 1 - continue - elseif monomials[p][i] + 1 < di - break - end - - mon = monomials[p] + e[i] - - if any(i != j && mon[j] > 0 && !checkMon(mon - e[j]) for j in 1:m) - continue - end - - num += 1 - wt = weights[p] + wts[i] - - if !haskey(idweight, wt) - nweights += 1 - idweight[wt] = nweights - end - idwt = idweight[wt] - - if !haskey(space, idwt) - space[idwt] = nullSpace() - end - - jo = (num, mon, wt, mats[i], vectors[p], space[idwt]) - if !haskey(jobs, idwt) - jobs[idwt] = [jo] - else - push!(jobs[idwt], jo) - end - #display(typeof(jo)) - end - end - #display(typeof(jobs)) - - #display(Threads.nthreads()) - - res = Vector{Any}(nothing, num) - idwts = [k for (k, l) in jobs if !isempty(l)] - Threads.@threads for idwt in idwts - for (i, mon, wt, A, v, sp) in jobs[idwt] - # this is the heavy lifting - # (in particular, the matrix product A * v) - w = addAndReduce!(sp, A * v) - if w != 0 - res[i] = (mon, wt, w) - end - end - end - - #display(res) - - for r in res - if r == nothing - continue - end - (mon, wt, vec) = r - setMon(mon) - push!(monomials, mon) - push!(vectors, vec) - push!(weights, wt) - end - - lastPos = newPos - end - - #display(idweight) - #display(vectors) - #display([(i, sp.A) for (i, sp) in space if length(sp.pivot) > 0]) - return monomials, vectors -end - - -################## -# chooses parallel / serial computing -# parallel true to use parallel computing through function compute_p -compute(v0, mats, wts::Vector{Vector{Int}}; parallel::Bool = false) = parallel ? compute_p(v0, mats, wts) : compute_0(v0, mats, wts) - end # module From 5e67d55333323abd2ba60228b9b08bd7c7f5129b Mon Sep 17 00:00:00 2001 From: Lars Kastner Date: Fri, 24 Mar 2023 11:37:28 +0100 Subject: [PATCH 04/19] [LieAlgebraBases] Base file for docs --- docs/doc.main | 1 + docs/src/Experimental/basisLieHighestWeight.md | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 docs/src/Experimental/basisLieHighestWeight.md diff --git a/docs/doc.main b/docs/doc.main index c789a7966b15..7be0e911645e 100644 --- a/docs/doc.main +++ b/docs/doc.main @@ -198,6 +198,7 @@ ], "Miscellaneous" => [ "AlgebraicGeometry/Miscellaneous/miscellaneous.md", + "Experimental/basisLieHighestWeight.md", ] ], diff --git a/docs/src/Experimental/basisLieHighestWeight.md b/docs/src/Experimental/basisLieHighestWeight.md new file mode 100644 index 000000000000..391a1ec7305e --- /dev/null +++ b/docs/src/Experimental/basisLieHighestWeight.md @@ -0,0 +1,13 @@ +```@meta +CurrentModule = Oscar +``` + +```@setup oscar +using Oscar +``` + +```@contents +Pages = ["basisLieHighestWeight.md"] +``` + +# Monomial bases for Lie algebras From c6219e89dc819a61732210783f8e161957c8dbed Mon Sep 17 00:00:00 2001 From: Lars Kastner Date: Fri, 24 Mar 2023 11:53:18 +0100 Subject: [PATCH 05/19] [LieAlgebraBases] Eliminate abbreviation forGap --- .../basisLieHighestWeight/BasisLieHighestWeight.jl | 9 ++++----- experimental/basisLieHighestWeight/LieAlgebras.jl | 7 +++---- experimental/basisLieHighestWeight/NewMonomial.jl | 1 - experimental/basisLieHighestWeight/RootConversion.jl | 5 ++--- experimental/basisLieHighestWeight/WeylPolytope.jl | 5 ++--- 5 files changed, 11 insertions(+), 16 deletions(-) diff --git a/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl b/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl index 9311c18652b1..6b595fcc24db 100644 --- a/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl +++ b/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl @@ -12,7 +12,6 @@ include("./NewMonomial.jl") #include("./VectorSpaceBases.jl") #--- bekommt gerade noch ZZ, Short und TVEC aus VectorSpaceBases G = Oscar.GAP.Globals -forGap = Oscar.GAP.julia_to_gap fromGap = Oscar.GAP.gap_to_julia @@ -52,7 +51,7 @@ function sub_simple_refl(word, L, n) """ R = G.RootSystem(L) CG = fromGap(G.CanonicalGenerators(R)[1], recursive = false) - ops = forGap([CG[i] for i in word], recursive = false) + ops = GAP.Obj([CG[i] for i in word], recursive = false) return ops end @@ -107,7 +106,7 @@ function compute_monomials(t, n, L, hw, ops, wts, wts_eps, monomial_order, calc_ end # calculation required - gapDim = G.DimensionOfHighestWeightModule(L, forGap(hw)) # number of monomials that we need to find, i.e. |M_{hw}|. + gapDim = G.DimensionOfHighestWeightModule(L, GAP.Obj(hw)) # number of monomials that we need to find, i.e. |M_{hw}|. # fundamental weights if is_fundamental(hw) # if hw is a fundamental weight, no partition into smaller summands is possible. This is the basecase of the recursion. push!(no_minkowski, hw) @@ -351,7 +350,7 @@ function get_dim_weightspace(t, n, L, hw) """ # calculate dimension for dominant weights with GAP R = G.RootSystem(L) - W = fromGap(G.DominantCharacter(R, forGap(hw))) + W = fromGap(G.DominantCharacter(R, GAP.Obj(hw))) dominant_weights = W[1] dominant_weights_dim = W[2] dim_weightspace = [] @@ -369,4 +368,4 @@ end -end \ No newline at end of file +end diff --git a/experimental/basisLieHighestWeight/LieAlgebras.jl b/experimental/basisLieHighestWeight/LieAlgebras.jl index c9bb8b20b100..890528173fce 100644 --- a/experimental/basisLieHighestWeight/LieAlgebras.jl +++ b/experimental/basisLieHighestWeight/LieAlgebras.jl @@ -4,7 +4,6 @@ using Oscar using SparseArrays G = Oscar.GAP.Globals -forGap = Oscar.GAP.julia_to_gap fromGap = Oscar.GAP.gap_to_julia @@ -12,7 +11,7 @@ function lieAlgebra(t::String, n::Int) """ Creates the Lie-algebra as a GAP object that gets used for a lot other computations with GAP """ - L = G.SimpleLieAlgebra(forGap(t), n, G.Rationals) + L = G.SimpleLieAlgebra(GAP.Obj(t), n, G.Rationals) return L, G.ChevalleyBasis(L) end @@ -24,7 +23,7 @@ function matricesForOperators(L, hw, ops) """ used to create tensorMatricesForOperators """ - M = G.HighestWeightModule(L, forGap(hw)) + M = G.HighestWeightModule(L, GAP.Obj(hw)) mats = G.List(ops, o -> G.MatrixOfAction(G.Basis(M), o)) mats = gapReshape.(fromGap(mats)) d = lcm(denominator.(union(mats...))) @@ -47,4 +46,4 @@ function weightsForOperators(L, cartan, ops) return [ [asVec(h*v)[nzi(v)] / asVec(v)[nzi(v)] for h in cartan] for v in ops ] -end \ No newline at end of file +end diff --git a/experimental/basisLieHighestWeight/NewMonomial.jl b/experimental/basisLieHighestWeight/NewMonomial.jl index 4cc12b7782ca..bcf7f9baf75c 100644 --- a/experimental/basisLieHighestWeight/NewMonomial.jl +++ b/experimental/basisLieHighestWeight/NewMonomial.jl @@ -14,7 +14,6 @@ include("./MonomialOrder.jl") include("./WeylPolytope.jl") G = Oscar.GAP.Globals -forGap = Oscar.GAP.julia_to_gap fromGap = Oscar.GAP.gap_to_julia diff --git a/experimental/basisLieHighestWeight/RootConversion.jl b/experimental/basisLieHighestWeight/RootConversion.jl index c3471cec0a4a..34ed98f11615 100644 --- a/experimental/basisLieHighestWeight/RootConversion.jl +++ b/experimental/basisLieHighestWeight/RootConversion.jl @@ -2,7 +2,6 @@ using Oscar G = Oscar.GAP.Globals -forGap = Oscar.GAP.julia_to_gap fromGap = Oscar.GAP.gap_to_julia ############################################ @@ -77,7 +76,7 @@ function alpha_to_w(t, n, weight) end function get_CartanMatrix(t, n) - L = G.SimpleLieAlgebra(forGap(t), n, G.Rationals) + L = G.SimpleLieAlgebra(GAP.Obj(t), n, G.Rationals) R = G.RootSystem(L) C_list = fromGap(G.CartanMatrix(R)) C = zeros(n,n) @@ -381,4 +380,4 @@ function eps_to_w_A(n, weight) end end return res -end \ No newline at end of file +end diff --git a/experimental/basisLieHighestWeight/WeylPolytope.jl b/experimental/basisLieHighestWeight/WeylPolytope.jl index 00d864271374..735627329328 100644 --- a/experimental/basisLieHighestWeight/WeylPolytope.jl +++ b/experimental/basisLieHighestWeight/WeylPolytope.jl @@ -4,7 +4,6 @@ using Oscar include("./RootConversion.jl") G = Oscar.GAP.Globals -forGap = Oscar.GAP.julia_to_gap fromGap = Oscar.GAP.gap_to_julia ######################### @@ -37,7 +36,7 @@ function orbit_weylgroup(t::String, n::Int, hw) # initialization L, CH = lieAlgebra(t, n) W = G.WeylGroup(G.RootSystem(L)) - orb = G.WeylOrbitIterator(W, forGap(hw)) + orb = G.WeylOrbitIterator(W, GAP.Obj(hw)) vertices = [] # operate with the weylgroup on hw @@ -180,4 +179,4 @@ function get_monomials_of_weightspace_Xn(wts, weight) poly = polytope.Polytope(INEQUALITIES=ineq, EQUATIONS=equ) monomials = lattice_points(Polyhedron(poly)) return monomials -end \ No newline at end of file +end From 8cd22e91c5c3b3fc0003efa5c0f48815bed88f36 Mon Sep 17 00:00:00 2001 From: Lars Kastner Date: Fri, 24 Mar 2023 12:01:38 +0100 Subject: [PATCH 06/19] [LieAlgebraBases] Eliminate abbreviation G = GAP.Globals --- .../basisLieHighestWeight/BasisLieHighestWeight.jl | 11 +++++------ experimental/basisLieHighestWeight/LieAlgebras.jl | 11 +++++------ experimental/basisLieHighestWeight/NewMonomial.jl | 1 - experimental/basisLieHighestWeight/RootConversion.jl | 7 +++---- experimental/basisLieHighestWeight/WeylPolytope.jl | 11 +++++------ 5 files changed, 18 insertions(+), 23 deletions(-) diff --git a/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl b/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl index 6b595fcc24db..de9f766f79ff 100644 --- a/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl +++ b/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl @@ -11,7 +11,6 @@ include("./NewMonomial.jl") #include("./VectorSpaceBases.jl") #--- bekommt gerade noch ZZ, Short und TVEC aus VectorSpaceBases -G = Oscar.GAP.Globals fromGap = Oscar.GAP.gap_to_julia @@ -49,8 +48,8 @@ function sub_simple_refl(word, L, n) """ substitute simple reflections (i,i+1), saved in dec by i, with E_{i,i+1} """ - R = G.RootSystem(L) - CG = fromGap(G.CanonicalGenerators(R)[1], recursive = false) + R = GAP.Globals.RootSystem(L) + CG = fromGap(GAP.Globals.CanonicalGenerators(R)[1], recursive = false) ops = GAP.Obj([CG[i] for i in word], recursive = false) return ops end @@ -106,7 +105,7 @@ function compute_monomials(t, n, L, hw, ops, wts, wts_eps, monomial_order, calc_ end # calculation required - gapDim = G.DimensionOfHighestWeightModule(L, GAP.Obj(hw)) # number of monomials that we need to find, i.e. |M_{hw}|. + gapDim = GAP.Globals.DimensionOfHighestWeightModule(L, GAP.Obj(hw)) # number of monomials that we need to find, i.e. |M_{hw}|. # fundamental weights if is_fundamental(hw) # if hw is a fundamental weight, no partition into smaller summands is possible. This is the basecase of the recursion. push!(no_minkowski, hw) @@ -349,8 +348,8 @@ function get_dim_weightspace(t, n, L, hw) and we can therefore calculate the dimension of each weightspace """ # calculate dimension for dominant weights with GAP - R = G.RootSystem(L) - W = fromGap(G.DominantCharacter(R, GAP.Obj(hw))) + R = GAP.Globals.RootSystem(L) + W = fromGap(GAP.Globals.DominantCharacter(R, GAP.Obj(hw))) dominant_weights = W[1] dominant_weights_dim = W[2] dim_weightspace = [] diff --git a/experimental/basisLieHighestWeight/LieAlgebras.jl b/experimental/basisLieHighestWeight/LieAlgebras.jl index 890528173fce..15d08b5772f4 100644 --- a/experimental/basisLieHighestWeight/LieAlgebras.jl +++ b/experimental/basisLieHighestWeight/LieAlgebras.jl @@ -3,7 +3,6 @@ using Oscar using SparseArrays -G = Oscar.GAP.Globals fromGap = Oscar.GAP.gap_to_julia @@ -11,8 +10,8 @@ function lieAlgebra(t::String, n::Int) """ Creates the Lie-algebra as a GAP object that gets used for a lot other computations with GAP """ - L = G.SimpleLieAlgebra(GAP.Obj(t), n, G.Rationals) - return L, G.ChevalleyBasis(L) + L = GAP.Globals.SimpleLieAlgebra(GAP.Obj(t), n, GAP.Globals.Rationals) + return L, GAP.Globals.ChevalleyBasis(L) end @@ -23,8 +22,8 @@ function matricesForOperators(L, hw, ops) """ used to create tensorMatricesForOperators """ - M = G.HighestWeightModule(L, GAP.Obj(hw)) - mats = G.List(ops, o -> G.MatrixOfAction(G.Basis(M), o)) + M = GAP.Globals.HighestWeightModule(L, GAP.Obj(hw)) + mats = GAP.Globals.List(ops, o -> GAP.Globals.MatrixOfAction(GAP.Globals.Basis(M), o)) mats = gapReshape.(fromGap(mats)) d = lcm(denominator.(union(mats...))) mats = (A->ZZ.(A*d)).(mats) @@ -38,7 +37,7 @@ function weightsForOperators(L, cartan, ops) """ cartan = fromGap(cartan, recursive=false) ops = fromGap(ops, recursive=false) - asVec(v) = fromGap(G.ExtRepOfObj(v)) + asVec(v) = fromGap(GAP.Globals.ExtRepOfObj(v)) if any(iszero.(asVec.(ops))) error("ops should be non-zero") end diff --git a/experimental/basisLieHighestWeight/NewMonomial.jl b/experimental/basisLieHighestWeight/NewMonomial.jl index bcf7f9baf75c..1cef58b776eb 100644 --- a/experimental/basisLieHighestWeight/NewMonomial.jl +++ b/experimental/basisLieHighestWeight/NewMonomial.jl @@ -13,7 +13,6 @@ include("./LieAlgebras.jl") include("./MonomialOrder.jl") include("./WeylPolytope.jl") -G = Oscar.GAP.Globals fromGap = Oscar.GAP.gap_to_julia diff --git a/experimental/basisLieHighestWeight/RootConversion.jl b/experimental/basisLieHighestWeight/RootConversion.jl index 34ed98f11615..3226ae84e562 100644 --- a/experimental/basisLieHighestWeight/RootConversion.jl +++ b/experimental/basisLieHighestWeight/RootConversion.jl @@ -1,7 +1,6 @@ #using Gapjm using Oscar -G = Oscar.GAP.Globals fromGap = Oscar.GAP.gap_to_julia ############################################ @@ -76,9 +75,9 @@ function alpha_to_w(t, n, weight) end function get_CartanMatrix(t, n) - L = G.SimpleLieAlgebra(GAP.Obj(t), n, G.Rationals) - R = G.RootSystem(L) - C_list = fromGap(G.CartanMatrix(R)) + L = GAP.Globals.SimpleLieAlgebra(GAP.Obj(t), n, GAP.Globals.Rationals) + R = GAP.Globals.RootSystem(L) + C_list = fromGap(GAP.Globals.CartanMatrix(R)) C = zeros(n,n) for i in 1:n for j in 1:n diff --git a/experimental/basisLieHighestWeight/WeylPolytope.jl b/experimental/basisLieHighestWeight/WeylPolytope.jl index 735627329328..d9a57d76bd9d 100644 --- a/experimental/basisLieHighestWeight/WeylPolytope.jl +++ b/experimental/basisLieHighestWeight/WeylPolytope.jl @@ -3,7 +3,6 @@ using Oscar include("./RootConversion.jl") -G = Oscar.GAP.Globals fromGap = Oscar.GAP.gap_to_julia ######################### @@ -35,14 +34,14 @@ function orbit_weylgroup(t::String, n::Int, hw) # also possible with polymake orbit_polytope(Vector input_point, Group g), root_system(String type) to save the equations, constant summand missing # initialization L, CH = lieAlgebra(t, n) - W = G.WeylGroup(G.RootSystem(L)) - orb = G.WeylOrbitIterator(W, GAP.Obj(hw)) + W = GAP.Globals.WeylGroup(GAP.Globals.RootSystem(L)) + orb = GAP.Globals.WeylOrbitIterator(W, GAP.Obj(hw)) vertices = [] # operate with the weylgroup on hw - G.IsDoneIterator(orb) - while !(G.IsDoneIterator(orb)) - w = G.NextIterator(orb) + GAP.Globals.IsDoneIterator(orb) + while !(GAP.Globals.IsDoneIterator(orb)) + w = GAP.Globals.NextIterator(orb) push!(vertices, fromGap(w)) end From 6b081e35dcc1739d5789f281e75c879930d7ff44 Mon Sep 17 00:00:00 2001 From: Lars Kastner Date: Fri, 24 Mar 2023 13:42:09 +0100 Subject: [PATCH 07/19] Typo prevented tests from running --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index d682d42322aa..3bc7b7266608 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -125,7 +125,7 @@ include("Serialization/runtests.jl") include("StraightLinePrograms/runtests.jl") -include("experimental/basisLieHighestWeight/MB-test.jl") +include("Experimental/basisLieHighestWeight/MB-test.jl") @static if compiletimes Base.cumulative_compile_timing(false); From 0089ae0e00e1bcb0b53d34d0a00edafdcca6163f Mon Sep 17 00:00:00 2001 From: Lars Kastner Date: Fri, 24 Mar 2023 16:13:14 +0100 Subject: [PATCH 08/19] [BasisLieHighestWeight] First docs example --- .../src/Experimental/basisLieHighestWeight.md | 7 +++++-- .../BasisLieHighestWeight.jl | 21 ++++++++++++++++--- experimental/basisLieHighestWeight/main.jl | 2 +- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/docs/src/Experimental/basisLieHighestWeight.md b/docs/src/Experimental/basisLieHighestWeight.md index 391a1ec7305e..7fc64f8ce43c 100644 --- a/docs/src/Experimental/basisLieHighestWeight.md +++ b/docs/src/Experimental/basisLieHighestWeight.md @@ -1,9 +1,9 @@ ```@meta -CurrentModule = Oscar +CurrentModule = Oscar.BasisLieHighestWeight ``` ```@setup oscar -using Oscar +using Oscar.BasisLieHighestWeight ``` ```@contents @@ -11,3 +11,6 @@ Pages = ["basisLieHighestWeight.md"] ``` # Monomial bases for Lie algebras +```@docs +basisLieHighestWeight2 +``` diff --git a/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl b/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl index de9f766f79ff..db3f22e858b1 100644 --- a/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl +++ b/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl @@ -4,6 +4,7 @@ export is_fundamental using Polymake using Distributed +using Markdown #using CUDA #using CuArrays @@ -13,11 +14,25 @@ include("./NewMonomial.jl") fromGap = Oscar.GAP.gap_to_julia +@doc Markdown.doc""" + basisLieHighestWeight2(t, n, hw; ops = "regular", known_monomials = [], monomial_order = "GRevLex", cache_size::Int = 1000000, parallel::Bool = false, return_no_minkowski::Bool = false, return_ops::Bool = false) +Compute a monomial basis for the highest weight module with highest weight +``hw`` (in terms of the fundamental weights), for a simple Lie algebra of type +``t`` and rank ``n``. + +# Parameters +- `t`: Explain +- `n`: Explain +- `hw`: Explain + +# Examples +```jldoctest +julia> 1+1 +2 +``` +""" function basisLieHighestWeight2(t, n, hw; ops = "regular", known_monomials = [], monomial_order = "GRevLex", cache_size::Int = 1000000, parallel::Bool = false, return_no_minkowski::Bool = false, return_ops::Bool = false) - """ - Compute a monomial basis for the highest weight module with highest weight ``hw`` (in terms of the fundamental weights), for a simple Lie algebra of type ``t`` and rank ``n``. - """ # The function precomputes objects that are independent of the highest weight and can be used in all recursion steps. Then it starts the recursion and returns the result. # initialization diff --git a/experimental/basisLieHighestWeight/main.jl b/experimental/basisLieHighestWeight/main.jl index 4bfca765ad45..9a1de065dda7 100644 --- a/experimental/basisLieHighestWeight/main.jl +++ b/experimental/basisLieHighestWeight/main.jl @@ -1,2 +1,2 @@ include("BasisLieHighestWeight.jl") -export MB \ No newline at end of file +export BasisLieHighestWeight From 3c5545cf106337f2b74e86976e847e858b165612 Mon Sep 17 00:00:00 2001 From: Ben Wilop Date: Fri, 24 Mar 2023 18:19:50 +0100 Subject: [PATCH 09/19] partial fix for SparseArrays --- .../src/Experimental/basisLieHighestWeight.md | 4 ++ .../BasisLieHighestWeight.jl | 30 ++++++++-- .../basisLieHighestWeight/LieAlgebras.jl | 19 ++++-- .../basisLieHighestWeight/NewMonomial.jl | 2 +- .../basisLieHighestWeight/TensorModels.jl | 2 +- .../basisLieHighestWeight/VectorSpaceBases.jl | 26 +++----- experimental/basisLieHighestWeight/main.jl | 2 +- .../basisLieHighestWeight/MB-test.jl | 1 + .../basisLieHighestWeight/MBOld.jl | 59 ++++++++++++------- 9 files changed, 95 insertions(+), 50 deletions(-) diff --git a/docs/src/Experimental/basisLieHighestWeight.md b/docs/src/Experimental/basisLieHighestWeight.md index 391a1ec7305e..2b604942f9cb 100644 --- a/docs/src/Experimental/basisLieHighestWeight.md +++ b/docs/src/Experimental/basisLieHighestWeight.md @@ -11,3 +11,7 @@ Pages = ["basisLieHighestWeight.md"] ``` # Monomial bases for Lie algebras + +@docs``` + +``` diff --git a/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl b/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl index 9311c18652b1..df2d0d2850f5 100644 --- a/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl +++ b/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl @@ -4,6 +4,7 @@ export is_fundamental using Polymake using Distributed +using Markdown #using CUDA #using CuArrays @@ -15,6 +16,18 @@ G = Oscar.GAP.Globals forGap = Oscar.GAP.julia_to_gap fromGap = Oscar.GAP.gap_to_julia +Markdown.@doc doc""" +basisLieHighestWeight2(t, n, hw; ops, known_monomials, monomial_order, cache_size, parallel:Bool, return_no_minkowski:.Bool, return_ops::Bool) -> Int, Int + +Compute a monomial basis for the highest weight module with highest weight ``hw`` (in terms of the fundamental weights), for a simple Lie algebra of type ``t`` and rank ``n``. + +# Examples +```jldoctest +julia> basisLieHighestWeight2 +output +``` +""" + function basisLieHighestWeight2(t, n, hw; ops = "regular", known_monomials = [], monomial_order = "GRevLex", cache_size::Int = 1000000, parallel::Bool = false, return_no_minkowski::Bool = false, return_ops::Bool = false) """ @@ -30,7 +43,7 @@ function basisLieHighestWeight2(t, n, hw; ops = "regular", known_monomials = [], wts_eps = [w_to_eps(t, n, w) for w in wts] # this is another way of representing the weights and equivalent to wts, but some functionality is easier with those. calc_hw = Dict{Vector{Int}, Set{Vector{Int}}}([0 for i=1:n] => Set([[0 for i=1:n]])) no_minkowski = Set() # we save all highest weights, for which the Minkowski-sum did not suffice to gain all monomials - + # start recursion over hw res = compute_monomials(t, n, L, hw, ops, wts, wts_eps, monomial_order, calc_hw, cache_size, parallel, no_minkowski) @@ -99,6 +112,7 @@ function compute_monomials(t, n, L, hw, ops, wts, wts_eps, monomial_order, calc_ a part of M_{hw} by going through all partitions of hw and using the Minkowski-property. The base cases of the recursion are the fundamental weights hw = [0, ..., 1, ..., 0]. In this case, or if the Minkowski-property did not find enough monomials, we need to perform the computations "by hand". """ + #println("compute_monomials: ", t, n, L, hw, ops, wts, wts_eps, monomial_order, calc_hw) # simple cases if haskey(calc_hw, hw) # we already computed the result in a prior recursion step return calc_hw[hw] @@ -179,6 +193,8 @@ function compute_sub_weights(hw) end function add_known_monomials!(weightspace, set_mon_in_weightspace, m, wts, mats, calc_monomials, space, e, cache_size) + #println("add_known_monomials: ", weightspace, set_mon_in_weightspace, m, wts, mats, calc_monomials, space, e) + #println("") """ By using the Minkowski-sum, we know that all monomials in set_mon_in_weightspace are in our basis. Since we want to extend the weightspacse with missing monomials, we go need to calculate and add the vector of each monomial to our basis. @@ -187,7 +203,7 @@ function add_known_monomials!(weightspace, set_mon_in_weightspace, m, wts, mats, for mon in set_mon_in_weightspace[weight] #vec, wt = calc_new_mon!(mon, m, wts, mats, calc_monomials, space, e, cache_size) d = sz(mats[1]) - v0 = spzeros(Int, d); v0[1] = 1 # starting vector v + v0 = sparse_matrix(ZZ, []) # starting vector v vec = calc_vec(v0, mon, mats) wt = calc_wt(mon, wts) #println("vec:" , vec) @@ -207,6 +223,8 @@ function add_new_monomials!(t, n, mats, wts, monomial_order, weightspace, wts_ep lie in the weyl-polytope. Therefore, we only inspect the monomials that lie both in the weyl-polytope and the weightspace. Since the weyl-polytope is bounded these are finitely many, we can sort them and then go trough them, until we found enough. """ + #println("add_new_monomials: ", weightspace, set_mon_in_weightspace, m, wts, mats, calc_monomials, space, e) + #println("") #println("memory: ", Int(Base.Sys.free_memory()) / 2^20) weight = weightspace[1] dim_weightspace = weightspace[2] @@ -239,14 +257,14 @@ function add_new_monomials!(t, n, mats, wts, monomial_order, weightspace, wts_ep # calculate the vector and check if it extends the basis #vec, _ = calc_new_mon!(mon, m, wts, mats, calc_monomials, space, e, cache_size) d = sz(mats[1]) - v0 = spzeros(Int, d); v0[1] = 1 # starting vector v + v0 = sparse_row(ZZ, [(1,1)]) # starting vector v vec = calc_vec(v0, mon, mats) #println("vec:" , vec) if !haskey(space, weight) space[weight] = nullSpace() end vec_red = addAndReduce!(space[weight], vec) - if isempty(vec_red.nzind) # v0 == 0 + if isempty(vec_red) # v0 == 0 continue end @@ -271,6 +289,8 @@ function add_by_hand(t, n, L, hw, ops, wts, wts_eps, monomial_order, gapDim, set This function calculates the missing monomials by going through each non full weightspace and adding possible monomials manually by computing their corresponding vectors and checking if they enlargen the basis. """ + #println("add_by_hand: ", t, n, L, hw, ops, wts, wts_eps, monomial_order, gapDim, set_mon) + #println("") #println("") #println("add_by_hand: ", hw) # initialization @@ -279,7 +299,7 @@ function add_by_hand(t, n, L, hw, ops, wts, wts_eps, monomial_order, gapDim, set e = [(1:m .== i) for i in 1:m] # e_i space = Dict(0*wts[1] => nullSpace()) # span of basis vectors to keep track of the basis d = sz(mats[1]) - v0 = spzeros(Int, d); v0[1] = 1 # starting vector v + v0 = sparse_row(ZZ, [(1,1)]) # starting vector v calc_monomials = Dict{Vector{Int}, Tuple{TVec, Vector{Int}}}([0 for i in 1:m] => (v0, 0 * wts[1])) # saves the calculated vectors to decrease necessary matrix multiplicatons push!(set_mon, [0 for i in 1:m]) weightspaces = get_dim_weightspace(t,n, L, hw) # required monomials of each weightspace diff --git a/experimental/basisLieHighestWeight/LieAlgebras.jl b/experimental/basisLieHighestWeight/LieAlgebras.jl index c9bb8b20b100..800e3c85ee29 100644 --- a/experimental/basisLieHighestWeight/LieAlgebras.jl +++ b/experimental/basisLieHighestWeight/LieAlgebras.jl @@ -1,7 +1,7 @@ # ? using Oscar -using SparseArrays +#using SparseArrays G = Oscar.GAP.Globals forGap = Oscar.GAP.julia_to_gap @@ -17,8 +17,17 @@ function lieAlgebra(t::String, n::Int) end -gapReshape(A) = sparse(hcat(A...)) +gapReshape(A) = sparse_matrix(QQ, hcat(A...)) +#gapReshape(A) = sparse(hcat(A...)) +# temporary workaround for issue 2128 +function multiply_scalar(A::SMat{T}, d) where T + for i in 1:nrows(A) + scale_row!(A, i, T(d)) + end + return A + #return identity_matrix(SMat, QQ, size(A)[1])*A +end function matricesForOperators(L, hw, ops) """ @@ -27,8 +36,10 @@ function matricesForOperators(L, hw, ops) M = G.HighestWeightModule(L, forGap(hw)) mats = G.List(ops, o -> G.MatrixOfAction(G.Basis(M), o)) mats = gapReshape.(fromGap(mats)) - d = lcm(denominator.(union(mats...))) - mats = (A->ZZ.(A*d)).(mats) + denominators = map(y->denominator(y[2]), union(union(mats...)...)) + #d = convert(QQ, lcm(denominators)) + d = lcm(denominators)# // 1 + mats = (A->change_base_ring(ZZ, multiply_scalar(A, d))).(mats) return mats end diff --git a/experimental/basisLieHighestWeight/NewMonomial.jl b/experimental/basisLieHighestWeight/NewMonomial.jl index 4cc12b7782ca..d90d6714833d 100644 --- a/experimental/basisLieHighestWeight/NewMonomial.jl +++ b/experimental/basisLieHighestWeight/NewMonomial.jl @@ -33,7 +33,7 @@ function calc_vec(v0, mon, mats) vec = v0 for i in length(mon):-1:1 for j in 1:mon[i] - vec = mats[i]*vec + vec = mul(vec, transpose(mats[i])) end end return vec diff --git a/experimental/basisLieHighestWeight/TensorModels.jl b/experimental/basisLieHighestWeight/TensorModels.jl index 990c73dd0e69..5199005dc2f4 100644 --- a/experimental/basisLieHighestWeight/TensorModels.jl +++ b/experimental/basisLieHighestWeight/TensorModels.jl @@ -1,7 +1,7 @@ # ? using Oscar -using SparseArrays +#using SparseArrays # TODO: make the first one a symmetric product, or reduce more generally diff --git a/experimental/basisLieHighestWeight/VectorSpaceBases.jl b/experimental/basisLieHighestWeight/VectorSpaceBases.jl index 9cee6ca17734..b63c87885960 100644 --- a/experimental/basisLieHighestWeight/VectorSpaceBases.jl +++ b/experimental/basisLieHighestWeight/VectorSpaceBases.jl @@ -1,10 +1,9 @@ # manages the basisvectors and its linear independence using Oscar -using SparseArrays +# SparseArrays -ZZ = Int -TVec = SparseVector{ZZ, Int} # values ZZ, indices Int (TVec is datatype of basisvectors basisLieHighestWeight) +TVec = SRow{ZZRingElem} # values ZZ, indices Int (TVec is datatype of basisvectors basisLieHighestWeight) Short = UInt8 # for exponents of monomials; max. 255 struct VSBasis @@ -22,14 +21,13 @@ function normalize(v::TVec) divides vector by gcd of nonzero entries, returns vector and first nonzero index used: addAndReduce! """ - dropzeros!(v) - if isempty(v.nzind) + if is_empty(v) return (v, 0) end - pivot = v.nzind[1] # first nonzero element of vector + pivot = first(v)[1] # first nonzero element of vector - return v .÷ gcd(v.nzval), pivot + return divexact(v, gcd(map(y->y[2], union(v)))), pivot end @@ -44,21 +42,14 @@ function addAndReduce!(sp::VSBasis, v::TVec) invariants: the row of a pivotelement in any column in A is 0 (except the pivotelement) elements of A are integers, gcd of each column is 1 """ + #println("sp: ", sp) + #println("v: ", v) A = sp.A pivot = sp.pivot - dim = sp.dim - - if dim == [] # update dimension - insert!(dim, 1, length(v)) - end - - if length(A) == sp.dim[1] # space already full => linear dependence guaranteed - v = spzeros(ZZ, sp.dim[1]) - return v - end v, newPivot = normalize(v) if newPivot == 0 # v zero vector + return v end @@ -70,6 +61,7 @@ function addAndReduce!(sp::VSBasis, v::TVec) v = reduceCol(v, A[j], i) v, newPivot = normalize(v) if newPivot == 0 + #return 0 return v end end diff --git a/experimental/basisLieHighestWeight/main.jl b/experimental/basisLieHighestWeight/main.jl index 4bfca765ad45..9f49cb5b266f 100644 --- a/experimental/basisLieHighestWeight/main.jl +++ b/experimental/basisLieHighestWeight/main.jl @@ -1,2 +1,2 @@ include("BasisLieHighestWeight.jl") -export MB \ No newline at end of file +export BasisLieHighestWeight \ No newline at end of file diff --git a/test/Experimental/basisLieHighestWeight/MB-test.jl b/test/Experimental/basisLieHighestWeight/MB-test.jl index 2f0d33907c42..37af6cc81643 100644 --- a/test/Experimental/basisLieHighestWeight/MB-test.jl +++ b/test/Experimental/basisLieHighestWeight/MB-test.jl @@ -17,6 +17,7 @@ can compute with the weaker version. """ function compare_algorithms(dynkin::Char, n::Int64, lambda::Vector{Int64}) + print("TESTETSETSET", dynkin, n, lambda) dim, m, v = MBOld.basisLieHighestWeight(string(dynkin), n, lambda) # basic algorithm w = BasisLieHighestWeight.basisLieHighestWeight2(string(dynkin), n, lambda) # algorithm that needs to be tested L = G.SimpleLieAlgebra(forGap(string(dynkin)), n, G.Rationals) diff --git a/test/Experimental/basisLieHighestWeight/MBOld.jl b/test/Experimental/basisLieHighestWeight/MBOld.jl index 54141c18d2ed..b5f37300bcb0 100644 --- a/test/Experimental/basisLieHighestWeight/MBOld.jl +++ b/test/Experimental/basisLieHighestWeight/MBOld.jl @@ -6,12 +6,14 @@ module MBOld export basisLieHighestWeight # use parallel = true for parallel computing using Oscar -using SparseArrays + +G = Oscar.GAP.Globals +forGap = Oscar.GAP.julia_to_gap +fromGap = Oscar.GAP.gap_to_julia #### vector space bases -ZZ = Int -TVec = SparseVector{ZZ, Int} +TVec = SRow{ZZRingElem} Short = UInt8 struct VSBasis @@ -28,18 +30,17 @@ function normalize(v::TVec) divides vector by gcd of nonzero entries, returns vector and first nonzero index used: addAndReduce! """ - dropzeros!(v) - if isempty(v.nzind) + if isempty(v) return (0, 0) end - pivot = v.nzind[1] + pivot = first(v)[1] - return v .÷ gcd(v.nzval), pivot + return divexact(v, gcd(map(y->y[2], union(v)))), pivot end -reduceCol(a, b, i::Int) = a*b[i] - b*a[i] +reduceCol(a, b, i::Int) = a*b[i] - a[i]*b function addAndReduce!(sp::VSBasis, v::TVec) @@ -93,20 +94,35 @@ function lieAlgebra(t::String, n::Int) return L, G.ChevalleyBasis(L) end +# temporary workaround for issue 2128 +function multiply_scalar(A::SMat{T}, d) where T + for i in 1:nrows(A) + scale_row!(A, i, T(d)) + end + return A + #return identity_matrix(SMat, QQ, size(A)[1])*A +end -gapReshape(A) = sparse(hcat(A...)) - +gapReshape(A) = sparse_matrix(QQ, hcat(A...)) function matricesForOperators(L, hw, ops) + """ + used to create tensorMatricesForOperators + """ + println("L: ", L) + println("hw: ", hw) + println("ops: ", ops) M = G.HighestWeightModule(L, forGap(hw)) mats = G.List(ops, o -> G.MatrixOfAction(G.Basis(M), o)) mats = gapReshape.(fromGap(mats)) - d = lcm(denominator.(union(mats...))) - mats = (A->ZZ.(A*d)).(mats) + println("mats: ", mats) + denominators = map(y->denominator(y[2]), union(union(mats...)...)) + #d = convert(QQ, lcm(denominators)) + d = lcm(denominators)# // 1 + mats = (A->change_base_ring(ZZ, multiply_scalar(A, d))).(mats) return mats end - function weightsForOperators(L, cartan, ops) cartan = fromGap(cartan, recursive=false) ops = fromGap(ops, recursive=false) @@ -168,7 +184,7 @@ julia> dim, monomials, vectors = PolyBases.MB.basisLieHighestWeight("A", 2, [1,0 ``` """ -function basisLieHighestWeight(t::String, n::Int, hw::Vector{Int}; roots = [], parallel::Bool = false) #--- :: Tuple{Int64,Vector{Vector{Short}},Vector{TVec}} +function basisLieHighestWeight(t::String, n::Int, hw::Vector{Int}; roots = []) #--- :: Tuple{Int64,Vector{Vector{Short}},Vector{TVec}} # TODO: flag for root ordering L, CH = lieAlgebra(t, n) #--- L ist Lie Algebra vom Typ t, n (z.B: "A", 2) durch Funktion GAP.SimpleLieAlgebra(t,n) #--- G ist ChevalleyBasis von L durch GAP.ChevalleyBasis(L) @@ -200,10 +216,9 @@ function basisLieHighestWeight(t::String, n::Int, hw::Vector{Int}; roots = [], p # wts = (v->round(dot(rnd,v), sigdigits=4)).(wts) # display(wts) - d = sz(mats[1]) #display(mats) #display(d) - hwv = spzeros(ZZ, d); hwv[1] = 1 + hwv = sparse_row(ZZ, [(1,1)]) # TODO: (okay for now) # here we assume the first vector in G.Basis(M) is a highest weight vector #display(hwv) @@ -227,7 +242,7 @@ function basisLieHighestWeight(t::String, n::Int, hw::Vector{Int}; roots = [], p #display(wts) #println("") - res = compute(hwv, mats, wts, parallel = parallel) + res = compute(hwv, mats, wts) return length(res[1]), res... end @@ -244,9 +259,11 @@ function compute(v0, mats, wts::Vector{Vector{Int}}) #--- jedes Monom erhaelt id #--- id(mon) returnt die id des entsprechenden mon. id(mon) = sum((1 << (sum(mon[1:i])+i-1) for i in 1:m-1) , init = 1) # init = 1 for case m = 1 - e = [Short.(1:m .== i) for i in 1:m] #--- Einheitsvektoren z.B.: e = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] für m = 3 - maxid(deg) = id(deg.*e[1]) #--- returnt maximale id für Monom vom Grad deg (worst case ist [1, 0, 0], da dann erste Potenz in jedem Summanden ist) - + e = sparse_row(ZZ, [(1,1)]) #--- Einheitsvektoren z.B.: e = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] für m = 3 + #maxid(deg) = id(deg.*e[1]) #--- returnt maximale id für Monom vom Grad deg (worst case ist [1, 0, 0], da dann erste Potenz in jedem Summanden ist) + maxid(deg) = id(deg.*[1]) + # TODO + #--- Sperrung von Monome blacklists = [falses(maxid(0))] #--- Monome die bereits in der Basis enthalten sind, i-ter Eintrag ist Sperrung für Monome von Grad i blacklists[end][id(monomials[1])] = 1 #--- Für Grad 0, d.h. konstant, ist die letzte id gesperrt da 0-Polynom @@ -308,7 +325,7 @@ function compute(v0, mats, wts::Vector{Vector{Int}}) space[wt] = nullSpace() end - vec = mats[i] * vectors[p] #--- vec ist neuer potenzieller Kandidat für Basis. + vec = mul(vector[p], transpose(mats[i])) #--- vec ist neuer potenzieller Kandidat für Basis. vec = addAndReduce!(space[wt], vec) #--- vec ist altes vec ohne Anteil des bereits vorhandenen Erzeugnisses. Wenn 0, dann linear abhängig zu altem Unterraum if vec == 0 #--- wenn vec linear abhängig war, fügen wir vec nicht hinzu continue From 752f615e63d8fad15a7c2ee26148ae5f1f2f9b56 Mon Sep 17 00:00:00 2001 From: Ben Wilop Date: Sat, 8 Apr 2023 17:48:17 +0200 Subject: [PATCH 10/19] switched monomials to Oscar type --- Project.toml | 2 - .../BasisLieHighestWeight.jl | 110 ++++++------- .../basisLieHighestWeight/MonomialOrder.jl | 85 +--------- .../basisLieHighestWeight/NewMonomial.jl | 14 +- .../basisLieHighestWeight/RootConversion.jl | 30 ++-- .../basisLieHighestWeight/VectorSpaceBases.jl | 2 +- .../basisLieHighestWeight/WeylPolytope.jl | 76 ++++----- .../basisLieHighestWeight/MB-test.jl | 25 +-- .../basisLieHighestWeight/MBOld.jl | 152 ++++-------------- 9 files changed, 157 insertions(+), 339 deletions(-) diff --git a/Project.toml b/Project.toml index e99f663c802b..f8ad3f540c90 100644 --- a/Project.toml +++ b/Project.toml @@ -6,7 +6,6 @@ version = "0.12.0-DEV" [deps] AbstractAlgebra = "c3fe647b-3220-5bb0-a1ea-a7954cac585d" AlgebraicSolving = "66b61cbe-0446-4d5d-9090-1ff510639f9d" -Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" GAP = "c863536a-3901-11e9-33e7-d5cd0df7b904" Hecke = "3e1990a7-5d81-5526-99ce-9ba3ff248f21" @@ -20,7 +19,6 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" RandomExtensions = "fb686558-2515-59ef-acaa-46db3789a887" RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" Singular = "bcd08a7b-43d2-5ff7-b6d4-c458787f915c" -SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" TOPCOM_jll = "36f60fef-b880-50dc-9289-4aaecee93cc3" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" diff --git a/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl b/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl index 1de6291a3026..0797e17cc405 100644 --- a/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl +++ b/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl @@ -35,17 +35,20 @@ julia> 1+1 function basisLieHighestWeight2(t, n, hw; ops = "regular", known_monomials = [], monomial_order = "GRevLex", cache_size::Int = 1000000, parallel::Bool = false, return_no_minkowski::Bool = false, return_ops::Bool = false) # The function precomputes objects that are independent of the highest weight and can be used in all recursion steps. Then it starts the recursion and returns the result. - # initialization + # initialization of objects that can be precomputed L, CH = lieAlgebra(t, n) # L Lie Algebra of Type t,n and CH Chevalleybasis of L ops = get_ops(t, n, ops, L, CH) # operators that are represented by our monomials. x_i is connected to ops[i] wts = weightsForOperators(L, CH[3], ops) # weights of the operators wts = (v->Int.(v)).(wts) wts_eps = [w_to_eps(t, n, w) for w in wts] # this is another way of representing the weights and equivalent to wts, but some functionality is easier with those. - calc_hw = Dict{Vector{Int}, Set{Vector{Int}}}([0 for i=1:n] => Set([[0 for i=1:n]])) + ZZx, x = PolynomialRing(ZZ, length(ops)) + + # save computations from recursions + calc_hw = Dict{Vector{Int}, Set{ZZMPolyRingElem}}([0 for i=1:n] => Set([ZZx(1)])) no_minkowski = Set() # we save all highest weights, for which the Minkowski-sum did not suffice to gain all monomials # start recursion over hw - res = compute_monomials(t, n, L, hw, ops, wts, wts_eps, monomial_order, calc_hw, cache_size, parallel, no_minkowski) + res = compute_monomials(t, n, L, ZZx, x, hw, ops, wts, wts_eps, monomial_order, calc_hw, cache_size, parallel, no_minkowski) # output if return_no_minkowski && return_ops @@ -69,7 +72,7 @@ function sub_simple_refl(word, L, n) return ops end -function get_ops(t,n, ops, L, CH) +function get_ops(t, n, ops, L, CH) """ handles user input for ops "regular" for all operators @@ -80,6 +83,7 @@ function get_ops(t,n, ops, L, CH) if ops == "regular" # use ops as specified by GAP ops = CH[1] return ops + # The functionality longest-word required Coxetergroups from Gapjm.jl (https://github.com/jmichel7/Gapjm.jl and was temporarily deleted #elseif ops == "longest-word" # choose a random longest word. Created by extending by random not leftdescending reflections until total length is reached # ops = longest_weyl_word(t,n) # ops = sub_simple_refl(ops, L, n) @@ -103,7 +107,7 @@ function get_ops(t,n, ops, L, CH) return ops end -function compute_monomials(t, n, L, hw, ops, wts, wts_eps, monomial_order, calc_hw, cache_size::Int, parallel::Bool, no_minkowski) +function compute_monomials(t, n, L, ZZx, x, hw, ops, wts, wts_eps, monomial_order, calc_hw, cache_size::Int, parallel::Bool, no_minkowski) """ This function calculates the monomial basis M_{hw} recursively. The recursion saves all computed results in calc_hw and we first check, if we already encountered this highest weight in a prior step. If this is not the case, we need to perform computations. The recursion works by using the @@ -117,7 +121,7 @@ function compute_monomials(t, n, L, hw, ops, wts, wts_eps, monomial_order, calc_ if haskey(calc_hw, hw) # we already computed the result in a prior recursion step return calc_hw[hw] elseif hw == [0 for i=1:n] # we mathematically know the solution - return Set([0 for i=1:n]) + return Set(ZZx(1)) end # calculation required @@ -125,12 +129,12 @@ function compute_monomials(t, n, L, hw, ops, wts, wts_eps, monomial_order, calc_ # fundamental weights if is_fundamental(hw) # if hw is a fundamental weight, no partition into smaller summands is possible. This is the basecase of the recursion. push!(no_minkowski, hw) - set_mon = add_by_hand(t, n, L, hw, ops, wts, wts_eps, monomial_order, gapDim, Set(), cache_size, parallel) + set_mon = add_by_hand(t, n, L, ZZx, x, hw, ops, wts, wts_eps, monomial_order, gapDim, Set{ZZMPolyRingElem}(), cache_size, parallel) push!(calc_hw, hw => set_mon) return set_mon else # use Minkowski-Sum for recursion - set_mon = Set() + set_mon = Set{ZZMPolyRingElem}() i = 0 sub_weights = compute_sub_weights(hw) l = length(sub_weights) @@ -139,15 +143,16 @@ function compute_monomials(t, n, L, hw, ops, wts, wts_eps, monomial_order, calc_ i += 1 lambda_1 = sub_weights[i] lambda_2 = hw .- lambda_1 - mon_lambda_1 = compute_monomials(t, n, L, lambda_1, ops, wts, wts_eps, monomial_order, calc_hw, cache_size, parallel, no_minkowski) - mon_lambda_2 = compute_monomials(t, n, L, lambda_2, ops, wts, wts_eps, monomial_order, calc_hw, cache_size, parallel, no_minkowski) - mon_sum = Set([p .+ q for p in mon_lambda_1 for q in mon_lambda_2]) # Minkowski-sum: M_{lambda_1} + M_{lambda_2} subseteq M_{hw} + mon_lambda_1 = compute_monomials(t, n, L, ZZx, x, lambda_1, ops, wts, wts_eps, monomial_order, calc_hw, cache_size, parallel, no_minkowski) + mon_lambda_2 = compute_monomials(t, n, L, ZZx, x, lambda_2, ops, wts, wts_eps, monomial_order, calc_hw, cache_size, parallel, no_minkowski) + # Minkowski-sum: M_{lambda_1} + M_{lambda_2} subseteq M_{hw}, if monomials get identified with points in ZZ^n + mon_sum = Set([p*q for p in mon_lambda_1 for q in mon_lambda_2]) union!(set_mon, mon_sum) end # check if we found enough monomials if length(set_mon) < gapDim push!(no_minkowski, hw) - set_mon = add_by_hand(t, n, L, hw, ops, wts, wts_eps, monomial_order, gapDim, set_mon, cache_size, parallel) + set_mon = add_by_hand(t, n, L, ZZx, x, hw, ops, wts, wts_eps, monomial_order, gapDim, set_mon, cache_size, parallel) end push!(calc_hw, hw => set_mon) return set_mon @@ -213,27 +218,28 @@ function add_known_monomials!(weightspace, set_mon_in_weightspace, m, wts, mats, end addAndReduce!(space[wt], vec) end - GC.gc() + #GC.gc() end -function add_new_monomials!(t, n, mats, wts, monomial_order, weightspace, wts_eps, set_mon_in_weightspace, calc_monomials, space, e, cache_size, set_mon, m) +function add_new_monomials!(t, n, ZZx, x, mats, wts, monomial_order, weightspace, wts_eps, set_mon_in_weightspace, calc_monomials, space, e, cache_size, set_mon, m) """ If a weightspace is missing monomials, we need to calculate them by trial and error. We would like to go through all monomials in the order monomial_order and calculate the corresponding vector. If it extends the basis, we add it to the result and else we try the next one. We know, that all monomials that work lie in the weyl-polytope. Therefore, we only inspect the monomials that lie both in the weyl-polytope and the weightspace. Since the weyl-polytope is bounded these are finitely many, we can sort them and then go trough them, until we found enough. """ - #println("add_new_monomials: ", weightspace, set_mon_in_weightspace, m, wts, mats, calc_monomials, space, e) + #println("") + #println("add_new_monomials: ", t, n, ZZx, x, mats, wts, monomial_order, weightspace, wts_eps, set_mon_in_weightspace, calc_monomials, space, e, cache_size, set_mon, m) #println("") #println("memory: ", Int(Base.Sys.free_memory()) / 2^20) weight = weightspace[1] dim_weightspace = weightspace[2] # get monomials from weyl-polytope that are in the weightspace - poss_mon_in_weightspace = get_monomials_of_weightspace(wts_eps, w_to_eps(t, n, weight), t) - lt_function = lt_monomial_order(monomial_order) + poss_mon_in_weightspace = convert_lattice_points_to_monomials(ZZx, get_lattice_points_of_weightspace(wts_eps, w_to_eps(t, n, weight), t)) + lt_function = lt_monomial_order(monomial_order, ZZx, x) poss_mon_in_weightspace = sort(poss_mon_in_weightspace, lt=lt_function) - + # check which monomials should get added to the basis i=0 if weight == 0 # check if [0 0 ... 0] already in basis @@ -244,12 +250,7 @@ function add_new_monomials!(t, n, mats, wts, monomial_order, weightspace, wts_ep while number_mon_in_weightspace < dim_weightspace i += 1 - # get a new mon - if t in ["A", "G"] # necessary because of the structure of get_monomials_of_weightspace_An - mon = convert(Vector{Int64}, poss_mon_in_weightspace[i][2:end]) - else - mon = convert(Vector{Int64}, poss_mon_in_weightspace[i]) - end + mon = poss_mon_in_weightspace[i] if mon in set_mon continue end @@ -271,25 +272,25 @@ function add_new_monomials!(t, n, mats, wts, monomial_order, weightspace, wts_ep # save monom number_mon_in_weightspace += 1 push!(set_mon, mon) + end # Weirdly, removing this causes memory problems. The lines should not be necessary since the objects are not referenced # and the garbage collector should run automatically. If I find out what causes this, it will be removed. - weight = 0 - dim_weightspace = 0 - lt_function = 0 - number_mon_in_weightspace = 0 - poss_mon_in_weightspace = 0 - GC.gc() + #weight = 0 + #dim_weightspace = 0 + #lt_function = 0 + #number_mon_in_weightspace = 0 + #poss_mon_in_weightspace = 0 + #GC.gc() end -function add_by_hand(t, n, L, hw, ops, wts, wts_eps, monomial_order, gapDim, set_mon, cache_size::Int, parallel::Bool) +function add_by_hand(t, n, L, ZZx, x, hw, ops, wts, wts_eps, monomial_order, gapDim, set_mon, cache_size::Int, parallel::Bool) """ This function calculates the missing monomials by going through each non full weightspace and adding possible monomials manually by computing their corresponding vectors and checking if they enlargen the basis. """ - #println("add_by_hand: ", t, n, L, hw, ops, wts, wts_eps, monomial_order, gapDim, set_mon) #println("") #println("") #println("add_by_hand: ", hw) @@ -300,14 +301,14 @@ function add_by_hand(t, n, L, hw, ops, wts, wts_eps, monomial_order, gapDim, set space = Dict(0*wts[1] => nullSpace()) # span of basis vectors to keep track of the basis d = sz(mats[1]) v0 = sparse_row(ZZ, [(1,1)]) # starting vector v - calc_monomials = Dict{Vector{Int}, Tuple{TVec, Vector{Int}}}([0 for i in 1:m] => (v0, 0 * wts[1])) # saves the calculated vectors to decrease necessary matrix multiplicatons - push!(set_mon, [0 for i in 1:m]) - weightspaces = get_dim_weightspace(t,n, L, hw) # required monomials of each weightspace + calc_monomials = Dict{ZZMPolyRingElem, Tuple{TVec, Vector{Int}}}(ZZx(1) => (v0, 0 * wts[1])) # saves the calculated vectors to decrease necessary matrix multiplicatons + push!(set_mon, ZZx(1)) + weightspaces = get_dim_weightspace(t, n, L, hw) # required monomials of each weightspace # sort the monomials from the minkowski-sum by their weightspaces - set_mon_in_weightspace = Dict{Vector{Int}, Set{Vector{Int}}}() + set_mon_in_weightspace = Dict{Vector{Int}, Set{ZZMPolyRingElem}}() for (weight, _) in weightspaces - set_mon_in_weightspace[weight] = Set() + set_mon_in_weightspace[weight] = Set{ZZMPolyRingElem}() end for mon in set_mon weight = calc_wt(mon, wts) @@ -326,32 +327,13 @@ function add_by_hand(t, n, L, hw, ops, wts, wts_eps, monomial_order, gapDim, set # use parallel computations if parallel=true. The weightspaces could be calculated completely indepent. We just save # the computed monomials. # insert known monomials into basis - if parallel - @distributed for weightspace in weightspaces - add_known_monomials!(weightspace, set_mon_in_weightspace, m, wts, mats, calc_monomials, space, e, cache_size) - end - else - for weightspace in weightspaces - #println("known memory: ", Int(Base.Sys.free_memory()) / 2^20) - #println("size space: ", Int(Base.summarysize(space)) / 2^20) - #println("size calc_monomials: ", Int(Base.summarysize(calc_monomials)) / 2^20) - add_known_monomials!(weightspace, set_mon_in_weightspace, m, wts, mats, calc_monomials, space, e, cache_size) - end - end + for weightspace in weightspaces + add_known_monomials!(weightspace, set_mon_in_weightspace, m, wts, mats, calc_monomials, space, e, cache_size) + end # calculate new monomials - if parallel - @distributed for weightspace in weightspaces - add_new_monomials!(t, n, mats, wts, monomial_order, weightspace, wts_eps, set_mon_in_weightspace, calc_monomials, space, e, cache_size, set_mon, m) - end - else - for weightspace in weightspaces - #println("varinfo: ", InteractiveUtils.varinfo(MB3)) - #println("new memory: ", Int(Base.Sys.free_memory()) / 2^20) - #println("size space: ", Int(Base.summarysize(space)) / 2^20) - #println("size calc_monomials: ", Int(Base.summarysize(calc_monomials)) / 2^20) - add_new_monomials!(t, n, mats, wts, monomial_order, weightspace, wts_eps, set_mon_in_weightspace, calc_monomials, space, e, cache_size, set_mon, m) - end + for weightspace in weightspaces + add_new_monomials!(t, n, ZZx, x, mats, wts, monomial_order, weightspace, wts_eps, set_mon_in_weightspace, calc_monomials, space, e, cache_size, set_mon, m) end #println("calc_monomials: ", length(calc_monomials)) return set_mon @@ -361,7 +343,7 @@ function get_dim_weightspace(t, n, L, hw) """ calculates matrix, first row weights, second row dimension of corresponding weightspace GAP computes the dimension for all positive weights. The dimension is constant on orbits of the weylgroup, - and we can therefore calculate the dimension of each weightspace + and we can therefore calculate the dimension of each weightspace. """ # calculate dimension for dominant weights with GAP R = GAP.Globals.RootSystem(L) @@ -371,7 +353,7 @@ function get_dim_weightspace(t, n, L, hw) dim_weightspace = [] # calculate dimension for the rest by checking which positive weights lies in the orbit. - for i=1:length(dominant_weights) + for i in 1:length(dominant_weights) orbit_weights = orbit_weylgroup(t,n, dominant_weights[i]) dim = dominant_weights_dim[i] for weight in eachrow(orbit_weights) @@ -381,6 +363,4 @@ function get_dim_weightspace(t, n, L, hw) return dim_weightspace end - - end diff --git a/experimental/basisLieHighestWeight/MonomialOrder.jl b/experimental/basisLieHighestWeight/MonomialOrder.jl index 630d7e9a3226..93d04c55fabb 100644 --- a/experimental/basisLieHighestWeight/MonomialOrder.jl +++ b/experimental/basisLieHighestWeight/MonomialOrder.jl @@ -1,88 +1,19 @@ # manages methods for different orders of monomials -function lt_monomial_order(monomial_order) +function lt_monomial_order(monomial_order, ZZx, x) """ Returns the desired monomial_order function """ - if isa(monomial_order, Function) - return monomial_order - elseif monomial_order == "GRevLex" - return lt_grevlex + #if isa(monomial_order, Function) + # return monomial_order + if monomial_order == "GRevLex" + choosen_monomial_order = degrevlex(x) elseif monomial_order == "RevLex" - return lt_rlex + choosen_monomial_order = revlex(x) elseif monomial_order == "Lex" - return lt_lex - elseif monomial_order == "GLex" - return lt_glex + choosen_monomial_order = lex(x) else println("no suitable order picked") end + return (mon1, mon2) -> (cmp(choosen_monomial_order, mon1, mon2) == -1) end - -function lt_grevlex(mon1, mon2) - """ - graded reverse lexicographic order - returns true if mon1 is less than mon2 - """ - if sum(mon1) == sum(mon2) - for i=1:length(mon1) - if mon1[i] < mon2[i] - return false - elseif mon1[i] > mon2[i] - return true - end - end - return false - else - return sum(mon1) < sum(mon2) - end -end - -function lt_glex(mon1, mon2) - """ - graded lexicographic order - returns true if mon1 is less than mon2 - """ - if sum(mon1) == sum(mon2) - for i=length(mon1):-1:1 - if mon1[i] < mon2[i] - return true - elseif mon1[i] > mon2[i] - return false - end - end - return false - else - return sum(mon1) < sum(mon2) - end -end - -function lt_lex(mon1, mon2) - """ - lexicographic order - returns true if mon1 is less than mon2 - """ - for i=length(mon1):-1:1 - if mon1[i] < mon2[i] - return true - elseif mon1[i] > mon2[i] - return false - end - end - return false -end - -function lt_rlex(mon1, mon2) - """ - reverse lexicographic order - returns true if mon1 is less than mon2 - """ - for i=1:length(mon1) - if mon1[i] < mon2[i] - return true - elseif mon1[i] > mon2[i] - return false - end - end - return false -end \ No newline at end of file diff --git a/experimental/basisLieHighestWeight/NewMonomial.jl b/experimental/basisLieHighestWeight/NewMonomial.jl index 6fc26ed1956a..da2e9d573f8c 100644 --- a/experimental/basisLieHighestWeight/NewMonomial.jl +++ b/experimental/basisLieHighestWeight/NewMonomial.jl @@ -20,17 +20,19 @@ function calc_wt(mon, weights) """ """ + degree_mon = degrees(mon) wt = [0 for i in 1:length(weights[1])] - for i in 1:length(mon) - wt .+= mon[i] * weights[i] + for i in 1:length(degree_mon) + wt .+= degree_mon[i] * weights[i] end return wt end function calc_vec(v0, mon, mats) vec = v0 - for i in length(mon):-1:1 - for j in 1:mon[i] + degree_mon = degrees(mon) + for i in length(degree_mon):-1:1 + for j in 1:degree_mon[i] vec = mul(vec, transpose(mats[i])) end end @@ -106,12 +108,12 @@ function calc_new_mon!(mon, m, wts, mats, calc_monomials, space, e, cache_size) # check if the extended monomial can be deleted from calculated_monomials, i.e. the other possible extensions are already contained can_be_deleted = true k = m - for l = 1:m + for l in 1:m if (sub_mon_cur-e[i])[l] != 0 k = l end end - for l = 1:k + for l in 1:k can_be_deleted = can_be_deleted && haskey(calc_monomials, sub_mon_cur-e[i]+e[l]) end if can_be_deleted && sub_mon_cur != e[i] diff --git a/experimental/basisLieHighestWeight/RootConversion.jl b/experimental/basisLieHighestWeight/RootConversion.jl index 3226ae84e562..bb8f6ac1f51f 100644 --- a/experimental/basisLieHighestWeight/RootConversion.jl +++ b/experimental/basisLieHighestWeight/RootConversion.jl @@ -166,13 +166,13 @@ function alpha_to_eps_E6(weight) for E6, potentially wrong order or roots (1-2-3-5-6, 3-4) """ eps = [0.0 for i=1:6] - for i=1:4 + for i in 1:4 eps[i] += weight[i] eps[i+1] += - weight[i] end eps[4] += weight[5] eps[5] += weight[5] - for i=1:5 + for i in 1:5 eps[i] += -0.5*weight[6] end eps[6] += 0.5*sqrt(3)*weight[6] @@ -185,13 +185,13 @@ function eps_to_alpha_E6(weight) for E6 """ alpha = [0.0 for i=1:6] - for j=1:3 - for i=1:j + for j in 1:3 + for i in 1:j alpha[j] += weight[i] end alpha[j] += j*(sqrt(3) / 3) *weight[6] end - for i=1:4 + for i in 1:4 alpha[4] += 0.5*weight[i] alpha[5] += 0.5*weight[i] end @@ -207,13 +207,13 @@ function alpha_to_eps_E7(weight) for E7, potentially wrong order of roots (1-2-3-4-6-7, 4-5) """ eps = [0.0 for i=1:7] - for i=1:5 + for i in 1:5 eps[i] += weight[i] eps[i+1] += - weight[i] end eps[5] += weight[6] eps[6] += weight[6] - for i=1:6 + for i in 1:6 eps[i] += -0.5*weight[7] end eps[7] += 0.5*sqrt(2)*weight[7] @@ -226,13 +226,13 @@ function eps_to_alpha_E7(weight) for E7 """ alpha = [0.0 for i=1:7] - for j=1:4 - for i=1:j + for j in 1:4 + for i in 1:j alpha[j] += weight[i] end alpha[j] += j*(sqrt(2) / 2) *weight[7] end - for i=1:5 + for i in 1:5 alpha[5] += 0.5*weight[i] alpha[6] += 0.5*weight[i] end @@ -248,13 +248,13 @@ function alpha_to_eps_E8(weight) for E8 """ eps = [0.0 for i=1:8] - for i=1:6 + for i in 1:6 eps[i] += weight[i] eps[i+1] += - weight[i] end eps[6] += weight[7] eps[7] += weight[7] - for i=1:8 + for i in 1:8 eps[i] += -0.5*weight[8] end return eps @@ -265,13 +265,13 @@ function eps_to_alpha_E8(weight) for E8 """ alpha = [0.0 for i=1:8] - for j=1:5 - for i=1:j + for j in 1:5 + for i in 1:j alpha[j] += weight[i] end alpha[j] += -j*weight[8] end - for i=1:6 + for i in 1:6 alpha[6] += 0.5*weight[i] alpha[7] += 0.5*weight[i] end diff --git a/experimental/basisLieHighestWeight/VectorSpaceBases.jl b/experimental/basisLieHighestWeight/VectorSpaceBases.jl index ccdae590d9a8..75288085f41b 100644 --- a/experimental/basisLieHighestWeight/VectorSpaceBases.jl +++ b/experimental/basisLieHighestWeight/VectorSpaceBases.jl @@ -53,7 +53,7 @@ function addAndReduce!(sp::VSBasis, v::TVec) return v end - for j = 1:length(A) + for j in 1:length(A) i = pivot[j] if i != newPivot continue diff --git a/experimental/basisLieHighestWeight/WeylPolytope.jl b/experimental/basisLieHighestWeight/WeylPolytope.jl index d9a57d76bd9d..77c8e7ab923c 100644 --- a/experimental/basisLieHighestWeight/WeylPolytope.jl +++ b/experimental/basisLieHighestWeight/WeylPolytope.jl @@ -68,18 +68,29 @@ end # compute monomials for weightspace # ############################################# -function get_monomials_of_weightspace(wts, weight, t) - # TODO CHECK IF XN WORKS FOR ALL OTHER TYPES +function convert_lattice_points_to_monomials(ZZx, lattice_points_weightspace) + return [finish(push_term!(MPolyBuildCtx(ZZx), ZZ(1), convert(Vector{Int}, convert(Vector{Int64}, lattice_point)))) for lattice_point in lattice_points_weightspace] +end + +function get_lattice_points_of_weightspace(wts, weight, t) + """ + calculates all lattice points in a given weightspace for lie algebras of type t + input: + wts: the operator weights in eps_i + weight: lambda - mu + + output: all lattice points with weight weight + """ if t in ["A", "G"] - return get_monomials_of_weightspace_An(wts, weight) + return get_lattice_points_of_weightspace_A_G_n(wts, weight) else - return get_monomials_of_weightspace_Xn(wts, weight) + return get_lattice_points_of_weightspace_Xn(wts, weight) end end -function get_monomials_of_weightspace_An(wts, weight) +function get_lattice_points_of_weightspace_A_G_n(wts, weight) """ - calculates all monomials in a given weightspace for lie algebras that have type A + calculates all monomials in a given weightspace for lie algebras that have type A or G input: wts: the operator weights in eps_i weight: lambda - mu @@ -99,10 +110,7 @@ function get_monomials_of_weightspace_An(wts, weight) -> poly = polytope.Polytope(INEQUALITIES=[0 0 1 0 0; 0 0 0 1 0; 0 0 0 0 1], EQUATIONS=[-2 1 1 0 2; -1 1 -1 1 1; 0 1 0 -1 0]) => returns [[1 0 0], [1 1 0]] """ - #println("") - #println(weight) - #println(wts) - + # build linear (in-)equations wts = [reshape(w, 1, :) for w in wts] n = length(wts) ineq = zeros(Int64, n, n+2) @@ -111,47 +119,25 @@ function get_monomials_of_weightspace_An(wts, weight) end equ = cat([-i for i in vec(weight)], [1 for i=1:length(weight)], dims = (2,2)) equ = cat(equ, [transpose(w) for w in wts] ..., dims = (2,2)) - #println("ineq: ", ineq) - #println("equ: ", equ) + + # find integer solutions of linear (in-)equation as lattice points of polytope poly = polytope.Polytope(INEQUALITIES=ineq, EQUATIONS=equ) - #println(poly) - #println(typeof(poly)) - #println(poly.VERTICES) - #println(poly.INTERIOR_LATTICE_POINTS) - #monomials = convert(Matrix{Int64}, poly.INTERIOR_LATTICE_POINTS)[:, 3:end] # first coordinate is for homogenous coordinates and second one for eps_1 + ... + eps_k = 0 - - #println("") - #println("TEST") - #q = polytope.Polytope(INEQUALITIES=[0 0 1 0 0; 0 0 0 1 0; 0 0 0 0 1], EQUATIONS=[-2 1 2 1 2; -1 1 0 2 1; 0 1 1 0 0]) - #println(q) - #println(q.LATTICE_POINTS) - - #monomials = convert(Matrix{Int64}, poly.INTERIOR_LATTICE_POINTS)[:, 3:end] # first coordinate is for homogenous coordinates and second one for eps_1 + ... + eps_k = 0 - #println(poly.INTERIOR_LATTICE_POINTS[:, 3:end]) - #println(lattice_points(Polyhedron(poly))) - monomials = lattice_points(Polyhedron(poly)) - #println(length(monomials)) - ##@time monomials = c_time(monomials) #convert(Vector{Vector{Int64}}, monomials) - #println(typeof(monomials)) - #@time monomials = [convert(Vector{Int64}) for m in monomials] - #monomials = convert(Matrix{Int64}, lattice_points(Polyhedron(poly)))[:, 3:end] # first coordinate is for homogenous coordinates and second one for eps_1 + ... + eps_k = 0 - #monomials = [monomials[i,:] for i in 1:size(monomials,1)] - #println(mons) - return monomials - - #poly = polytope.Polytope(INEQUALITIES=[0 0 1 0 0; 0 0 0 1 0; 0 0 0 0 1], EQUATIONS=[0 1 2 0 1; 0 1 1 2 0; 0 1 2 1 0]) - #println("vertices: ", poly.VERTICES) - #println("lattice_points: ", poly.LATTICE_POINTs) + + # convert lattice-points to Oscar monomials + lattice_points_weightspace = lattice_points(Polyhedron(poly)) + lattice_points_weightspace = [lattice_point[2:end] for lattice_point in lattice_points_weightspace] + return lattice_points_weightspace + end -function get_monomials_of_weightspace_Xn(wts, weight) +function get_lattice_points_of_weightspace_Xn(wts, weight) """ - calculates all monomials in a given weightspace for lie algebras that don't have type A + calculates all lattice points in a given weightspace for lie algebras that don't have type A input: wts: the operator weights in eps_i weight: lambda - mu - output: all monomials with weight weight + output: all lattice points with weight weight works by calculating all integer solutions to the following linear program: [ | | ] [ x ] @@ -176,6 +162,6 @@ function get_monomials_of_weightspace_Xn(wts, weight) equ = [-i for i in vec(weight)] equ = cat(equ, [transpose(w) for w in wts] ..., dims = (2,2)) poly = polytope.Polytope(INEQUALITIES=ineq, EQUATIONS=equ) - monomials = lattice_points(Polyhedron(poly)) - return monomials + lattice_points_weightspace = lattice_points(Polyhedron(poly)) + return lattice_points_weightspace end diff --git a/test/Experimental/basisLieHighestWeight/MB-test.jl b/test/Experimental/basisLieHighestWeight/MB-test.jl index 46990bf125c1..bba8c52900b3 100644 --- a/test/Experimental/basisLieHighestWeight/MB-test.jl +++ b/test/Experimental/basisLieHighestWeight/MB-test.jl @@ -1,7 +1,6 @@ using Oscar using Test using TestSetExtensions -#using SparseArrays include("MBOld.jl") @@ -17,13 +16,19 @@ can compute with the weaker version. """ function compare_algorithms(dynkin::Char, n::Int64, lambda::Vector{Int64}) - #print("TESTETSETSET", dynkin, n, lambda) - dim, m, v = MBOld.basisLieHighestWeight(string(dynkin), n, lambda) # basic algorithm - w = BasisLieHighestWeight.basisLieHighestWeight2(string(dynkin), n, lambda) # algorithm that needs to be tested + #print("compare_algorithms", dynkin, n, lambda) + # old algorithm + mons_old = MBOld.basisLieHighestWeight(string(dynkin), n, lambda) # basic algorithm + + # new algorithm + mons_new = BasisLieHighestWeight.basisLieHighestWeight2(string(dynkin), n, lambda) # algorithm that needs to be tested L = G.SimpleLieAlgebra(forGap(string(dynkin)), n, G.Rationals) gapDim = G.DimensionOfHighestWeightModule(L, forGap(lambda)) # dimension - @test Set(m) == w # compare if result of basic and sophisticated algorithm match - @test gapDim == length(w) # check if dimension is correct + + # comparison + # convert set of monomials over different ring objects to string representation to compare for equality + @test issetequal(string.(mons_old), string.(mons_new)) # compare if result of basic and more sophisticated algorithm match + @test gapDim == length(mons_new) # check if dimension is correct end function check_dimension(dynkin::Char, n::Int64, lambda::Vector{Int64}, monomial_order::String) @@ -37,8 +42,10 @@ end @testset ExtendedTestSet "Test basisLieHighestWeight" begin # TODO: add test for basis (not just dimension) @testset "Known examples" begin - @test BasisLieHighestWeight.basisLieHighestWeight2("A", 2, [1,0]) == Set([[0,0,0], [0,0,1], [1,0,0]]) - @test BasisLieHighestWeight.basisLieHighestWeight2("A", 2, [1,0], ops=[1,2,1]) == Set([[0,0,0], [0,1,1], [1,0,0]]) + mons = BasisLieHighestWeight.basisLieHighestWeight2("A", 2, [1,0]) + @test issetequal(string.(mons), Set(["1", "x3", "x1"])) + mons = BasisLieHighestWeight.basisLieHighestWeight2("A", 2, [1,0], ops=[1,2,1]) + @test issetequal(string.(mons), Set(["1", "x2*x3", "x3"])) end @testset "Compare with simple algorithm and check dimension" begin @testset "Dynkin type $dynkin" for dynkin in ('A', 'B', 'C', 'D') @@ -64,7 +71,7 @@ end end end @testset "Check dimension" begin - @testset "Monomial order $monomial_order" for monomial_order in ("Lex", "GLex", "GRevLex", "GRevLex") + @testset "Monomial order $monomial_order" for monomial_order in ("Lex", "RevLex", "GRevLex") #@testset "Operators $ops" for ops in ("regular", "longest-word") check_dimension('A', 3, [1,1,1], monomial_order) # #check_dimension('B', 3, [2,1,0], monomial_order, ops) diff --git a/test/Experimental/basisLieHighestWeight/MBOld.jl b/test/Experimental/basisLieHighestWeight/MBOld.jl index fd25caaeafa5..061396036875 100644 --- a/test/Experimental/basisLieHighestWeight/MBOld.jl +++ b/test/Experimental/basisLieHighestWeight/MBOld.jl @@ -3,7 +3,7 @@ module MBOld -export basisLieHighestWeight # use parallel = true for parallel computing +export basisLieHighestWeight using Oscar @@ -12,8 +12,6 @@ G = Oscar.GAP.Globals forGap = Oscar.GAP.julia_to_gap fromGap = Oscar.GAP.gap_to_julia -#### vector space bases - TVec = SRow{ZZRingElem} Short = UInt8 @@ -149,9 +147,6 @@ function kron(A, B) setindex!(res, new_row, (j-1)*nrows(B)+i) end end - #println("ncols(res): ", ncols(res)) - #println("nrows(res): ", nrows(res)) - return res end @@ -165,12 +160,8 @@ function tensorProduct(A, B) return res end -# TODO: make the first one a symmetric product, or reduce more generally - -#spid(n) = spdiagm(0 => [ZZ(1) for _ in 1:n]) spid(n) = identity_matrix(SMat, ZZ, n) -sz(A) = nrows(A) #size(A)[1] -#tensorProduct(A, B) = kron(A, spid(sz(B))) + kron(spid(sz(A)), B) +sz(A) = nrows(A) tensorProducts(As, Bs) = (AB->tensorProduct(AB[1], AB[2])).(zip(As, Bs)) tensorPower(A, n) = (n == 1) ? A : tensorProduct(tensorPower(A, n-1), A) tensorPowers(As, n) = (A->tensorPower(A, n)).(As) @@ -184,7 +175,6 @@ function tensorMatricesForOperators(L, hw, ops) mats = [] for i in 1:length(hw) - #println("hw[i]: ", hw[i]) if hw[i] <= 0 continue end @@ -194,12 +184,8 @@ function tensorMatricesForOperators(L, hw, ops) if size(mats)[1] > 0 A = _mats[1] B = mats[1] - #println("Addition cols ", ncols(kron(A, spid(sz(B))) + kron(spid(sz(A)), B))) - #println("Addition rows ",nrows(kron(A, spid(sz(B))) + kron(spid(sz(A)), B))) end mats = mats == [] ? _mats : tensorProducts(mats, _mats) - #println(spdiagm(0 => [ZZ(1) for _ in 1:5])agm) - #display(mats) end return mats end @@ -224,139 +210,69 @@ julia> dim, monomials, vectors = PolyBases.MB.basisLieHighestWeight("A", 2, [1,0 """ function basisLieHighestWeight(t::String, n::Int, hw::Vector{Int}; roots = []) #--- :: Tuple{Int64,Vector{Vector{Short}},Vector{TVec}} - # TODO: flag for root ordering - L, CH = lieAlgebra(t, n) #--- L ist Lie Algebra vom Typ t, n (z.B: "A", 2) durch Funktion GAP.SimpleLieAlgebra(t,n) - #--- G ist ChevalleyBasis von L durch GAP.ChevalleyBasis(L) - #--- CH[1] obere strikte Dreiecksmatrizen, CH[2] untere strikte Dreiecksmatrizen, CH[3] Diagonalmatrizen - + L, CH = lieAlgebra(t, n) ops = CH[1] # positive root vectors # .. reorder.. wts = weightsForOperators(L, CH[3], ops) wts = (v->Int.(v)).(wts) - - # Keep only elements of ops which weights are listed in roots, in order of roots - #if !isempty(roots) - # ops = fromGap(ops, recursive = false) - # ops_vec = [] - # for i in 1:length(wts) - # if wts[i] in roots - # push!(ops_vec, ops[i]) - # end - # end - # ops = forGap(ops_vec, recursive = false) - #end - #--- mats speichert die Matrizen g_i für (g_1^a_1 * ... * g_k^a_k)*v0 ab. mats = tensorMatricesForOperators(L, hw, ops) - # display(wts) - # rnd = rand(length(wts[1])) - # rnd /= norm(rnd) - # wts = (v->round(dot(rnd,v), sigdigits=4)).(wts) - # display(wts) - - #display(mats) - #display(d) hwv = sparse_row(ZZ, [(1,1)]) - # TODO: (okay for now) - # here we assume the first vector in G.Basis(M) is a highest weight vector - #display(hwv) - #display.(1. .* (mats)) - - #--- - #println("--------------------------------------") - #println("Parameter für compute(hwv, mats, wts)") - #println("") - #println("hwv:") - #display(collect(hwv)) - #println("") - #println("mats:") - #for i=1:length(mats) - # println(string("mats[", i, "]:")) - # #display(collect(mats[i])) - # display(mats[i]) - #end - #println("") - #println("wts:") - #display(wts) - #println("") - - res = compute(hwv, mats, wts) - - return length(res[1]), res... + + monomials = compute(hwv, mats, wts) + ZZx, x = PolynomialRing(ZZ, length(monomials[1])) + monomials = [finish(push_term!(MPolyBuildCtx(ZZx), ZZ(1), convert(Vector{Int}, mon))) for mon in monomials] + monomials = Set(monomials) + return monomials end nullMon(m) = zeros(Short, m) function compute(v0, mats, wts::Vector{Vector{Int}}) - m = length(mats) #--- - monomials = [nullMon(m)] #--- hier speichern wir die Monombasis. Ein Eintrag steht für Potenzen unserer Basiselemente - #--- nullMon ist leeres Monom, also nur m-Nullen bzw. die Identität - lastPos = 0 #--- speichert für die untere while-Schleife die Anzahl der Basiselemente nach dem letzten Durchlauf - - #--- jedes Monom erhaelt id - #--- id(mon) returnt die id des entsprechenden mon. - id(mon) = sum((1 << (sum(mon[1:i])+i-1) for i in 1:m-1) , init = 1) # init = 1 for case m = 1 - #e = [sparse_row(ZZ, [(i,1)]) for i=1:m] #--- Einheitsvektoren z.B.: e = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] für m = 3 + m = length(mats) + monomials = [nullMon(m)] + lastPos = 0 + id(mon) = sum((1 << (sum(mon[1:i])+i-1) for i in 1:m-1) , init = 1) e = [Short.(1:m .== i) for i in 1:m] - #maxid(deg) = id(deg.*e[1]) #--- returnt maximale id für Monom vom Grad deg (worst case ist [1, 0, 0], da dann erste Potenz in jedem Summanden ist) maxid(deg) = id(deg.*e[1]) - #maxid(deg) = id(sparse_row(ZZ, [(1,deg)])) - # TODO - - #--- Sperrung von Monome - blacklists = [falses(maxid(0))] #--- Monome die bereits in der Basis enthalten sind, i-ter Eintrag ist Sperrung für Monome von Grad i - blacklists[end][id(monomials[1])] = 1 #--- Für Grad 0, d.h. konstant, ist die letzte id gesperrt da 0-Polynom - newMons(deg) = (push!(blacklists, falses(maxid(deg)))) # Neuer Eintrag um Sperrung der Monome von Grad deg zu speichern - checkMon(mon) = blacklists[end-1][id(mon)] #--- returnt ob Monom gesperrt ist. Man nimmt sich den vorletzten Eintrag, weil in der Berechnung - #--- im while-Loop der letzte Eintrag immer der Eintrag für den derzeitigen Grad ist - setMon(mon) = (blacklists[end][id(mon)] = true) #--- sperrt monom (im while loop ist deg immer maximal für mon und damit im letzten Eintrag von blacklists) + blacklists = [falses(maxid(0))] + blacklists[end][id(monomials[1])] = 1 + newMons(deg) = (push!(blacklists, falses(maxid(deg)))) + checkMon(mon) = blacklists[end-1][id(mon)] + setMon(mon) = (blacklists[end][id(mon)] = true) - #--- Speicher für while-loop - vectors = [v0] #--- von Monombasis mit (g_1^a_1 * ... * g_k^a_k)*v0 erzeugte Basisvektoren von V=R^(n+1) + vectors = [v0] weights = [0 * wts[1]] - space = Dict(weights[1] => nullSpace()) #--- Erzeugnis der bisherigen Basisvektoren. - addAndReduce!(space[weights[1]], v0) #--- Fügt Span von Basisvektor v0 ein + space = Dict(weights[1] => nullSpace()) + addAndReduce!(space[weights[1]], v0) deg = 0 - - #--- iteriere durch alle Monome in reverse lexicographical order - #--- Bsp: [[0, 0], [1, 0], [0, 1], [2, 0], [1, 1], [0, 2]] - #--- while-loop iteriert durch Grad deg, also Summe der Einträge - #--- i iteriert durch ersten nicht-null Index - #--- di ist neue Potenz an Stelle i (d.h. 1 höher als vorher) - #--- p durchläuft alle Monomome mit deg-1 (monomials[startPos:newPos]), um durch Addition eines e[i] alle Monome von deg erreichen - #--- innerster Durchlauf: Erhöhe bei allen bereits verwendeten Monomen Potenz i um 1 auf di, ansonsten mache nichts - #--- solange bis für einen Grad kein Polynom mehr hinzugefügt worden ist while length(monomials) > lastPos startPos = lastPos + 1 newPos = length(monomials) deg = deg + 1 - newMons(deg) #--- Schaffung neues Speicherplatzes in blacklists. Muss iterativ erweitert werden, weil der maximale Grad der Basis unbekannt ist - + newMons(deg) for i in 1:m, di in deg:-1:1 - for p in startPos:newPos #--- monomials[startPos:newPos] sind alle hinzugefügten Monome von deg-1 + for p in startPos:newPos - #--- Siebe Monome für rev-lex Ordnung - if !all(monomials[p][1:i-1] .== 0) #--- Monome mit nicht-null vor Index i wurden bereits mit kleinerem i getroffen + if !all(monomials[p][1:i-1] .== 0) continue end - #--- neues monom soll an Stelle i Potenz di haben + if monomials[p][i]+1 > di - startPos = p+1 #--- wegen rev-lex Ordnung wird dieses Monom nie wieder erweitert -> für Grad deg immer erst danach beginnen + startPos = p+1 continue end if monomials[p][i]+1 < di - break #--- break, da monomials bereits rev-lex geordnet ist und alle späteren von Grad deg-1 noch kleinere Potenz bei i haben + break end - mon = monomials[p] + e[i] #--- mögliches neues Monom + mon = monomials[p] + e[i] - #--- nur mon behalten, falls jeder Index != 0 durch verwendetes Monom des vorherigen Schrittes mit +e[j] hervorging. - #--- folgt nicht automatisch induktiv, da mon-e[j] zwar überprüft worden ist, aber vielleicht neuer Vektor linear abhängig war if any(i != j && mon[j] > 0 && !checkMon(mon-e[j]) for j in 1:m) continue end @@ -366,15 +282,13 @@ function compute(v0, mats, wts::Vector{Vector{Int}}) space[wt] = nullSpace() end - vec = mul(vectors[p], transpose(mats[i])) #--- vec ist neuer potenzieller Kandidat für Basis. - vec = addAndReduce!(space[wt], vec) #--- vec ist altes vec ohne Anteil des bereits vorhandenen Erzeugnisses. Wenn 0, dann linear abhängig zu altem Unterraum - if vec == 0 #--- wenn vec linear abhängig war, fügen wir vec nicht hinzu + vec = mul(vectors[p], transpose(mats[i])) + vec = addAndReduce!(space[wt], vec) + if vec == 0 continue end - #display(v) - #display(1. .* space.A) - setMon(mon) #--- wenn vec linear unabhängig war wird vec zur Basis hinzugefügt und das zugehörige Monom gespeichert + setMon(mon) push!(monomials, mon) push!(weights, wt) push!(vectors, vec) @@ -383,7 +297,7 @@ function compute(v0, mats, wts::Vector{Vector{Int}}) lastPos = newPos end - return monomials, vectors + return monomials end end # module From 0a30aab26da5b98f632894ab26827e34de9a30e4 Mon Sep 17 00:00:00 2001 From: Lars Kastner Date: Mon, 3 Apr 2023 22:19:05 +0200 Subject: [PATCH 11/19] [BasisLieHighestWeight] Adjusted to new structure --- docs/doc.main | 1 - experimental/BasisLieHighestWeight/docs/doc.main | 3 +++ .../BasisLieHighestWeight/docs/src}/basisLieHighestWeight.md | 0 .../src}/BasisLieHighestWeight.jl | 1 + .../src}/LieAlgebras.jl | 0 .../src}/MonomialOrder.jl | 0 .../src}/NewMonomial.jl | 0 .../src}/RootConversion.jl | 0 .../src}/TensorModels.jl | 0 .../src}/VectorSpaceBases.jl | 0 .../src}/WeylPolytope.jl | 0 .../BasisLieHighestWeight/test}/MBOld.jl | 0 .../BasisLieHighestWeight/test/runtests.jl | 0 experimental/basisLieHighestWeight/main.jl | 2 -- test/runtests.jl | 2 -- 15 files changed, 4 insertions(+), 5 deletions(-) create mode 100644 experimental/BasisLieHighestWeight/docs/doc.main rename {docs/src/Experimental => experimental/BasisLieHighestWeight/docs/src}/basisLieHighestWeight.md (100%) rename experimental/{basisLieHighestWeight => BasisLieHighestWeight/src}/BasisLieHighestWeight.jl (99%) rename experimental/{basisLieHighestWeight => BasisLieHighestWeight/src}/LieAlgebras.jl (100%) rename experimental/{basisLieHighestWeight => BasisLieHighestWeight/src}/MonomialOrder.jl (100%) rename experimental/{basisLieHighestWeight => BasisLieHighestWeight/src}/NewMonomial.jl (100%) rename experimental/{basisLieHighestWeight => BasisLieHighestWeight/src}/RootConversion.jl (100%) rename experimental/{basisLieHighestWeight => BasisLieHighestWeight/src}/TensorModels.jl (100%) rename experimental/{basisLieHighestWeight => BasisLieHighestWeight/src}/VectorSpaceBases.jl (100%) rename experimental/{basisLieHighestWeight => BasisLieHighestWeight/src}/WeylPolytope.jl (100%) rename {test/Experimental/basisLieHighestWeight => experimental/BasisLieHighestWeight/test}/MBOld.jl (100%) rename test/Experimental/basisLieHighestWeight/MB-test.jl => experimental/BasisLieHighestWeight/test/runtests.jl (100%) delete mode 100644 experimental/basisLieHighestWeight/main.jl diff --git a/docs/doc.main b/docs/doc.main index adc2afcd9cd3..d9088aebd583 100644 --- a/docs/doc.main +++ b/docs/doc.main @@ -194,7 +194,6 @@ ], "Miscellaneous" => [ "AlgebraicGeometry/Miscellaneous/miscellaneous.md", - "Experimental/basisLieHighestWeight.md", ] ], diff --git a/experimental/BasisLieHighestWeight/docs/doc.main b/experimental/BasisLieHighestWeight/docs/doc.main new file mode 100644 index 000000000000..d4c956dfab8b --- /dev/null +++ b/experimental/BasisLieHighestWeight/docs/doc.main @@ -0,0 +1,3 @@ +[ + "basisLieHighestWeight.md" +] diff --git a/docs/src/Experimental/basisLieHighestWeight.md b/experimental/BasisLieHighestWeight/docs/src/basisLieHighestWeight.md similarity index 100% rename from docs/src/Experimental/basisLieHighestWeight.md rename to experimental/BasisLieHighestWeight/docs/src/basisLieHighestWeight.md diff --git a/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl b/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl similarity index 99% rename from experimental/basisLieHighestWeight/BasisLieHighestWeight.jl rename to experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl index 0797e17cc405..a643cc12d35a 100644 --- a/experimental/basisLieHighestWeight/BasisLieHighestWeight.jl +++ b/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl @@ -364,3 +364,4 @@ function get_dim_weightspace(t, n, L, hw) end end +export BasisLieHighestWeight diff --git a/experimental/basisLieHighestWeight/LieAlgebras.jl b/experimental/BasisLieHighestWeight/src/LieAlgebras.jl similarity index 100% rename from experimental/basisLieHighestWeight/LieAlgebras.jl rename to experimental/BasisLieHighestWeight/src/LieAlgebras.jl diff --git a/experimental/basisLieHighestWeight/MonomialOrder.jl b/experimental/BasisLieHighestWeight/src/MonomialOrder.jl similarity index 100% rename from experimental/basisLieHighestWeight/MonomialOrder.jl rename to experimental/BasisLieHighestWeight/src/MonomialOrder.jl diff --git a/experimental/basisLieHighestWeight/NewMonomial.jl b/experimental/BasisLieHighestWeight/src/NewMonomial.jl similarity index 100% rename from experimental/basisLieHighestWeight/NewMonomial.jl rename to experimental/BasisLieHighestWeight/src/NewMonomial.jl diff --git a/experimental/basisLieHighestWeight/RootConversion.jl b/experimental/BasisLieHighestWeight/src/RootConversion.jl similarity index 100% rename from experimental/basisLieHighestWeight/RootConversion.jl rename to experimental/BasisLieHighestWeight/src/RootConversion.jl diff --git a/experimental/basisLieHighestWeight/TensorModels.jl b/experimental/BasisLieHighestWeight/src/TensorModels.jl similarity index 100% rename from experimental/basisLieHighestWeight/TensorModels.jl rename to experimental/BasisLieHighestWeight/src/TensorModels.jl diff --git a/experimental/basisLieHighestWeight/VectorSpaceBases.jl b/experimental/BasisLieHighestWeight/src/VectorSpaceBases.jl similarity index 100% rename from experimental/basisLieHighestWeight/VectorSpaceBases.jl rename to experimental/BasisLieHighestWeight/src/VectorSpaceBases.jl diff --git a/experimental/basisLieHighestWeight/WeylPolytope.jl b/experimental/BasisLieHighestWeight/src/WeylPolytope.jl similarity index 100% rename from experimental/basisLieHighestWeight/WeylPolytope.jl rename to experimental/BasisLieHighestWeight/src/WeylPolytope.jl diff --git a/test/Experimental/basisLieHighestWeight/MBOld.jl b/experimental/BasisLieHighestWeight/test/MBOld.jl similarity index 100% rename from test/Experimental/basisLieHighestWeight/MBOld.jl rename to experimental/BasisLieHighestWeight/test/MBOld.jl diff --git a/test/Experimental/basisLieHighestWeight/MB-test.jl b/experimental/BasisLieHighestWeight/test/runtests.jl similarity index 100% rename from test/Experimental/basisLieHighestWeight/MB-test.jl rename to experimental/BasisLieHighestWeight/test/runtests.jl diff --git a/experimental/basisLieHighestWeight/main.jl b/experimental/basisLieHighestWeight/main.jl deleted file mode 100644 index 9a1de065dda7..000000000000 --- a/experimental/basisLieHighestWeight/main.jl +++ /dev/null @@ -1,2 +0,0 @@ -include("BasisLieHighestWeight.jl") -export BasisLieHighestWeight diff --git a/test/runtests.jl b/test/runtests.jl index 5aa67152c73d..df27d656383c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -127,8 +127,6 @@ include("Serialization/runtests.jl") include("StraightLinePrograms/runtests.jl") -include("Experimental/basisLieHighestWeight/MB-test.jl") - @static if compiletimes Base.cumulative_compile_timing(false); end From fcc38fb1286210e22653a1e0f124850462bb1ccf Mon Sep 17 00:00:00 2001 From: Lars Kastner Date: Sun, 9 Apr 2023 02:01:54 +0200 Subject: [PATCH 12/19] [BasisLieHighestWeight] Forgotten removal of 'using Distributed'? --- experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl b/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl index a643cc12d35a..1aeb8b1cd793 100644 --- a/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl +++ b/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl @@ -3,7 +3,7 @@ export basisLieHighestWeight2 export is_fundamental using Polymake -using Distributed +# using Distributed using Markdown #using CUDA #using CuArrays From 14f5cc44bcf43574a8511b71d9c2076c272b19ad Mon Sep 17 00:00:00 2001 From: Lars Kastner Date: Sun, 9 Apr 2023 09:05:05 +0200 Subject: [PATCH 13/19] [BasisLieHighestWeight] Remove TestSetExtension --- experimental/BasisLieHighestWeight/test/runtests.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/experimental/BasisLieHighestWeight/test/runtests.jl b/experimental/BasisLieHighestWeight/test/runtests.jl index bba8c52900b3..0a10ea2dc689 100644 --- a/experimental/BasisLieHighestWeight/test/runtests.jl +++ b/experimental/BasisLieHighestWeight/test/runtests.jl @@ -1,6 +1,6 @@ using Oscar using Test -using TestSetExtensions +# using TestSetExtensions include("MBOld.jl") @@ -39,7 +39,7 @@ function check_dimension(dynkin::Char, n::Int64, lambda::Vector{Int64}, monomial end -@testset ExtendedTestSet "Test basisLieHighestWeight" begin +@testset "Test basisLieHighestWeight" begin # TODO: add test for basis (not just dimension) @testset "Known examples" begin mons = BasisLieHighestWeight.basisLieHighestWeight2("A", 2, [1,0]) From 3ae434fc929d9d354a45d7c1d1a20b3e14b137f8 Mon Sep 17 00:00:00 2001 From: Ben Wilop Date: Mon, 10 Apr 2023 17:21:39 +0200 Subject: [PATCH 14/19] more explanatory variable names and type declaration for functions --- .../src/BasisLieHighestWeight.jl | 376 ++++++++++-------- .../BasisLieHighestWeight/src/LieAlgebras.jl | 40 +- .../src/MonomialOrder.jl | 33 +- .../BasisLieHighestWeight/src/NewMonomial.jl | 84 ++-- .../src/RootConversion.jl | 213 +++++----- .../BasisLieHighestWeight/src/TensorModels.jl | 47 +-- .../src/VectorSpaceBases.jl | 54 ++- .../BasisLieHighestWeight/src/WeylPolytope.jl | 115 +++--- .../BasisLieHighestWeight/test/runtests.jl | 38 +- 9 files changed, 492 insertions(+), 508 deletions(-) diff --git a/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl b/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl index 1aeb8b1cd793..02098bffa1d7 100644 --- a/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl +++ b/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl @@ -1,170 +1,221 @@ module BasisLieHighestWeight -export basisLieHighestWeight2 +export basisLieHighestWeight export is_fundamental using Polymake # using Distributed using Markdown -#using CUDA -#using CuArrays include("./NewMonomial.jl") -#include("./VectorSpaceBases.jl") #--- bekommt gerade noch ZZ, Short und TVEC aus VectorSpaceBases - fromGap = Oscar.GAP.gap_to_julia @doc Markdown.doc""" - basisLieHighestWeight2(t, n, hw; ops = "regular", known_monomials = [], monomial_order = "GRevLex", cache_size::Int = 1000000, parallel::Bool = false, return_no_minkowski::Bool = false, return_ops::Bool = false) + basisLieHighestWeight(type::String, rank::Int, heighest_weight::Vector{Int}; + operators::Union{String, Vector{Int}} = "regular", + monomial_order::Union{String, Function} = "GRevLex", cache_size::Int = 0, + parallel::Bool = false, return_no_minkowski::Bool = false, + return_operators::Bool = false) -Compute a monomial basis for the highest weight module with highest weight -``hw`` (in terms of the fundamental weights), for a simple Lie algebra of type -``t`` and rank ``n``. +Computes a monomial basis for the highest weight module with highest weight +``heighest_weight`` (in terms of the fundamental weights), for a simple Lie algebra of type +``type`` and rank ``rank``. # Parameters -- `t`: Explain -- `n`: Explain -- `hw`: Explain +- `type`: type of liealgebra we want to investigate, one of "A", "B", "C", "D", "E", "F", "G" +- `rank`: rank of liealgebra +- `operators`: currently not implemented, because we used https://github.com/jmichel7/Gapjm.jl to work with coxeter + groups and get left descending elements +- `monomial_order`: highest weight +- `cache_size`: number of computed monomials we want to cache, default is 0 +- `parallel`: currently not implemented, because we used Distributed.jl, but if true parts of the algorithms can be + parallelized +- `return_no_minkowski`: if true return monomials for which Monkowski-property did not suffice to find all monomials +- `return_operators`: if true return the GAP objects operators # Examples ```jldoctest -julia> 1+1 -2 +julia> BasisLieHighestWeight.basisLieHighestWeight("A", 2, [1,0]) +Set{ZZMPolyRingElem} with 3 elements: + 1 + x1 + x3 ``` """ -function basisLieHighestWeight2(t, n, hw; ops = "regular", known_monomials = [], monomial_order = "GRevLex", cache_size::Int = 1000000, parallel::Bool = false, return_no_minkowski::Bool = false, return_ops::Bool = false) - # The function precomputes objects that are independent of the highest weight and can be used in all recursion steps. Then it starts the recursion and returns the result. +function basisLieHighestWeight(type::String, rank::Int, heighest_weight::Vector{Int}; + operators::Union{String, Vector{Int}} = "regular", + monomial_order::Union{String, Function} = "GRevLex", cache_size::Int = 0, + parallel::Bool = false, return_no_minkowski::Bool = false, + return_operators::Bool = false) + # The function precomputes objects that are independent of the highest weight and can be used in all recursion + # steps. Then it starts the recursion and returns the result. # initialization of objects that can be precomputed - L, CH = lieAlgebra(t, n) # L Lie Algebra of Type t,n and CH Chevalleybasis of L - ops = get_ops(t, n, ops, L, CH) # operators that are represented by our monomials. x_i is connected to ops[i] - wts = weightsForOperators(L, CH[3], ops) # weights of the operators - wts = (v->Int.(v)).(wts) - wts_eps = [w_to_eps(t, n, w) for w in wts] # this is another way of representing the weights and equivalent to wts, but some functionality is easier with those. - ZZx, x = PolynomialRing(ZZ, length(ops)) + lie_algebra, chevalley_basis = lieAlgebra(type, rank) # lie_algebra of type, rank and its chevalley_basis + # operators that are represented by our monomials. x_i is connected to operators[i] + operators = get_operators(type, rank, operators, lie_algebra, chevalley_basis) + weights = weightsForOperators(lie_algebra, chevalley_basis[3], operators) # weights of the operators + weights = (weight->Int.(weight)).(weights) + weights_eps = [w_to_eps(type, rank, w) for w in weights] + ZZx, x = PolynomialRing(ZZ, length(operators)) # for our monomials + monomial_order_lt = get_monomial_order_lt(monomial_order, ZZx, x) # less than function to sort monomials by order # save computations from recursions - calc_hw = Dict{Vector{Int}, Set{ZZMPolyRingElem}}([0 for i=1:n] => Set([ZZx(1)])) - no_minkowski = Set() # we save all highest weights, for which the Minkowski-sum did not suffice to gain all monomials + calc_heighest_weight = Dict{Vector{Int}, Set{ZZMPolyRingElem}}([0 for i in 1:rank] => Set([ZZx(1)])) + # we save all highest weights, for which the Minkowski-sum did not suffice to gain all monomials + no_minkowski = Set{Vector{Int}}() - # start recursion over hw - res = compute_monomials(t, n, L, ZZx, x, hw, ops, wts, wts_eps, monomial_order, calc_hw, cache_size, parallel, no_minkowski) + # start recursion over heighest_weight + monomial_basis = compute_monomials(type, rank, lie_algebra, ZZx, x, heighest_weight, operators, weights, + weights_eps, monomial_order_lt, calc_heighest_weight, cache_size, parallel, no_minkowski) # output - if return_no_minkowski && return_ops - return res, no_minkowski, ops + if return_no_minkowski && return_operators + return monomial_basis, no_minkowski, operators elseif return_no_minkowski - return res, no_minkowski - elseif return_ops - return res, ops + return monomial_basis, no_minkowski + elseif return_operators + return monomial_basis, operators else - return res + return monomial_basis end end -function sub_simple_refl(word, L, n) +function sub_simple_refl(word::Vector{Int}, lie_algebra::GAP.Obj)::GAP.Obj """ substitute simple reflections (i,i+1), saved in dec by i, with E_{i,i+1} """ - R = GAP.Globals.RootSystem(L) - CG = fromGap(GAP.Globals.CanonicalGenerators(R)[1], recursive = false) - ops = GAP.Obj([CG[i] for i in word], recursive = false) - return ops + root_system = GAP.Globals.RootSystem(lie_algebra) + canonical_generators = fromGap(GAP.Globals.CanonicalGenerators(root_system)[1], recursive = false) + operators = GAP.Obj([canonical_generators[i] for i in word], recursive = false) + return operators end -function get_ops(t, n, ops, L, CH) +function get_operators(type::String, rank::Int, operators::Union{String, Vector{Int}}, lie_algebra::GAP.Obj, + chevalley_basis::GAP.Obj)::GAP.Obj """ - handles user input for ops + handles user input for operators "regular" for all operators "longest-word" for random longest-word in Weyl-group - ops::Vector{Int} for explicit longest-word + operators::Vector{Int} for explicit longest-word """ - # create standard ops - if ops == "regular" # use ops as specified by GAP - ops = CH[1] - return ops - # The functionality longest-word required Coxetergroups from Gapjm.jl (https://github.com/jmichel7/Gapjm.jl and was temporarily deleted - #elseif ops == "longest-word" # choose a random longest word. Created by extending by random not leftdescending reflections until total length is reached - # ops = longest_weyl_word(t,n) - # ops = sub_simple_refl(ops, L, n) - # return ops + # create standard operators + if operators == "regular" # use operators as specified by GAP + operators = chevalley_basis[1] + return operators + # The functionality longest-word required Coxetergroups from Gapjm.jl (https://github.com/jmichel7/Gapjm.jl and was + # temporarily deleted + # choose a random longest word. Created by extending by random not leftdescending reflections until total length is + # reached + #elseif operators == "longest-word" + # operators = longest_weyl_word(t,n) + # operators = sub_simple_refl(operators, lie_algebra, n) + # return operators end - # use user defined ops + # use user defined operators # wrong input - if !(typeof(ops) == Vector{Int}) - println("ops needs to of type Vector{Int}") + if !(typeof(operators) == Vector{Int}) + println("operators needs to be of type Vector{Int}") return -1 end - if !(all([(1 <= i <= n) for i in ops])) - println("all values of ops need to between 1 and the rank of the lie algebra.") + if !(all([(1 <= i <= rank) for i in operators])) + println("all values of operators need to between 1 and the rank of the lie algebra.") end - # If one of the conditions is met, the algorithms works for sure. Otherwise a warning is printed (and can be ignored). - #if !(is_longest_weyl_word(t, n, ops)) && !(Set(ops) == [i for i=1:n]) - # println("WARNING: ops may be incorrect input.") + # If one of the conditions is met, the algorithms works. Otherwise a warning is printed (and can be ignored). + #if !(is_longest_weyl_word(type, rank, operators)) && !(Set(operators) == [i for i=1:n]) + # println("WARNING: operators may be incorrect input.") #end - ops = sub_simple_refl(ops, L, n) - return ops + operators = sub_simple_refl(operators, lie_algebra) + return operators end -function compute_monomials(t, n, L, ZZx, x, hw, ops, wts, wts_eps, monomial_order, calc_hw, cache_size::Int, parallel::Bool, no_minkowski) +function compute_monomials(type::String, rank::Int, lie_algebra::GAP.Obj, ZZx::ZZMPolyRing, x::Vector{ZZMPolyRingElem}, + heighest_weight::Vector{Int}, operators::GAP.Obj, weights::Vector{Vector{Int64}}, + weights_eps::Vector{Vector{Int64}}, monomial_order_lt::Function, + calc_heighest_weight::Dict{Vector{Int64}, Set{ZZMPolyRingElem}}, cache_size::Int, + parallel::Bool, no_minkowski::Set{Vector{Int}})::Set{ZZMPolyRingElem} """ - This function calculates the monomial basis M_{hw} recursively. The recursion saves all computed results in calc_hw and we first check, if we already - encountered this highest weight in a prior step. If this is not the case, we need to perform computations. The recursion works by using the - Minkowski-sum. If M_{hw} is the desired set of monomials (identified by the exponents as lattice points), it is know that for lambda_1 + lambda_2 = hw - we have M_{lambda_1} + M_{lambda_2} subseteq M_{hw}. The complexity grows exponentially in the size of hw. Therefore, it is very helpful to obtain - a part of M_{hw} by going through all partitions of hw and using the Minkowski-property. The base cases of the recursion are the fundamental weights - hw = [0, ..., 1, ..., 0]. In this case, or if the Minkowski-property did not find enough monomials, we need to perform the computations "by hand". + This function calculates the monomial basis M_{heighest_weight} recursively. The recursion saves all computed + results in calc_heighest_weight and we first check, if we already encountered this highest weight in a prior step. + If this is not the case, we need to perform computations. The recursion works by using the Minkowski-sum. + If M_{heighest_weight} is the desired set of monomials (identified by the exponents as lattice points), it is know + that for lambda_1 + lambda_2 = heighest_weight we have M_{lambda_1} + M_{lambda_2} subseteq M_{heighest_weight}. + The complexity grows exponentially in the size of heighest_weight. Therefore, it is very helpful to obtain a part of + M_{heighest_weight} by going through all partitions of heighest_weight and using the Minkowski-property. The base + cases of the recursion are the fundamental weights heighest_weight = [0, ..., 1, ..., 0]. In this case, or if the + Minkowski-property did not find enough monomials, we need to perform the computations "by hand". """ - #println("compute_monomials: ", t, n, L, hw, ops, wts, wts_eps, monomial_order, calc_hw) # simple cases - if haskey(calc_hw, hw) # we already computed the result in a prior recursion step - return calc_hw[hw] - elseif hw == [0 for i=1:n] # we mathematically know the solution + # we already computed the heighest_weight result in a prior recursion step + if haskey(calc_heighest_weight, heighest_weight) + return calc_heighest_weight[heighest_weight] + elseif heighest_weight == [0 for i=1:rank] # we mathematically know the solution return Set(ZZx(1)) end # calculation required - gapDim = GAP.Globals.DimensionOfHighestWeightModule(L, GAP.Obj(hw)) # number of monomials that we need to find, i.e. |M_{hw}|. - # fundamental weights - if is_fundamental(hw) # if hw is a fundamental weight, no partition into smaller summands is possible. This is the basecase of the recursion. - push!(no_minkowski, hw) - set_mon = add_by_hand(t, n, L, ZZx, x, hw, ops, wts, wts_eps, monomial_order, gapDim, Set{ZZMPolyRingElem}(), cache_size, parallel) - push!(calc_hw, hw => set_mon) + # number of monomials that we need to find, i.e. |M_{heighest_weight}|. + # if heighest_weight is a fundamental weightype, ranko partition into smaller summands is possible. This is the + # basecase of the recursion. + gapDim = GAP.Globals.DimensionOfHighestWeightModule(lie_algebra, GAP.Obj(heighest_weight)) # fundamental weights + if is_fundamental(heighest_weight) || sum(abs.(heighest_weight)) == 0 + push!(no_minkowski, heighest_weight) + set_mon = add_by_hand(type, rank, lie_algebra, ZZx, x, heighest_weight, operators, weights, weights_eps, + monomial_order_lt, gapDim, Set{ZZMPolyRingElem}(), cache_size, parallel) + push!(calc_heighest_weight, heighest_weight => set_mon) return set_mon else # use Minkowski-Sum for recursion set_mon = Set{ZZMPolyRingElem}() i = 0 - sub_weights = compute_sub_weights(hw) + sub_weights = compute_sub_weights(heighest_weight) l = length(sub_weights) - # go through partitions lambda_1 + lambda_2 = hw until we have monomials enough monomials or used all partitions + # go through all partitions lambda_1 + lambda_2 = heighest_weight until we have enough monomials or used all + # partitions while length(set_mon) < gapDim && i < l i += 1 lambda_1 = sub_weights[i] - lambda_2 = hw .- lambda_1 - mon_lambda_1 = compute_monomials(t, n, L, ZZx, x, lambda_1, ops, wts, wts_eps, monomial_order, calc_hw, cache_size, parallel, no_minkowski) - mon_lambda_2 = compute_monomials(t, n, L, ZZx, x, lambda_2, ops, wts, wts_eps, monomial_order, calc_hw, cache_size, parallel, no_minkowski) - # Minkowski-sum: M_{lambda_1} + M_{lambda_2} subseteq M_{hw}, if monomials get identified with points in ZZ^n + lambda_2 = heighest_weight .- lambda_1 + mon_lambda_1 = compute_monomials(type, rank, lie_algebra, ZZx, x, lambda_1, operators, weights, weights_eps, + monomial_order_lt, calc_heighest_weight, cache_size, parallel, + no_minkowski) + mon_lambda_2 = compute_monomials(type, rank, lie_algebra, ZZx, x, lambda_2, operators, weights, weights_eps, + monomial_order_lt, calc_heighest_weight, cache_size, parallel, + no_minkowski) + # Minkowski-sum: M_{lambda_1} + M_{lambda_2} subseteq M_{heighest_weight}, if monomials get identified with + # points in ZZ^n mon_sum = Set([p*q for p in mon_lambda_1 for q in mon_lambda_2]) union!(set_mon, mon_sum) end # check if we found enough monomials if length(set_mon) < gapDim - push!(no_minkowski, hw) - set_mon = add_by_hand(t, n, L, ZZx, x, hw, ops, wts, wts_eps, monomial_order, gapDim, set_mon, cache_size, parallel) + push!(no_minkowski, heighest_weight) + set_mon = add_by_hand(type, rank, lie_algebra, ZZx, x, heighest_weight, operators, weights, weights_eps, + monomial_order_lt, gapDim, set_mon, cache_size, parallel) end - push!(calc_hw, hw => set_mon) + push!(calc_heighest_weight, heighest_weight => set_mon) return set_mon end end -function is_fundamental(hw) - """ - returns true if hw is fundamental weight, i.e. hw = [0, ..., 1, ..., 0] (or hw = [0, ..., 0]) - """ +@doc Markdown.doc""" + is_fundamental(heighest_weight::Vector{Int})::Bool + + returns true if ``heighest_weight`` is fundamental, i.e. [0, ..., 1, ..., 0] + +# Examples +```jldoctest +julia> BasisLieHighestWeight.is_fundamental([0, 1, 0]) +true + +julia> BasisLieHighestWeight.is_fundamental([0, 1, 1]) +false +``` +""" +function is_fundamental(heighest_weight::Vector{Int})::Bool one = false - for i in hw + for i in heighest_weight if i > 0 if one || i > 1 return false @@ -173,72 +224,79 @@ function is_fundamental(hw) end end end - return true + return false end -function order_sub_weights(hw, sub_weights) +function order_sub_weights(heighest_weight::Vector{Int}, sub_weights::Vector{Any})::Vector{Vector{Int}} """ sort weights incrasing by their 2-norm """ sort!(sub_weights, by=x->sum((x).^2)) end -function compute_sub_weights(hw) +function compute_sub_weights(heighest_weight::Vector{Int})::Vector{Vector{Int}} """ - returns list of weights w != 0 with 0 <= w <= hw elementwise + returns list of weights w != 0 with 0 <= w <= heighest_weight elementwise """ sub_weights = [] - foreach(Iterators.product((0:x for x in hw)...)) do i + foreach(Iterators.product((0:x for x in heighest_weight)...)) do i push!(sub_weights, [i...]) end popfirst!(sub_weights) # [0, ..., 0] - pop!(sub_weights) # hw - order_sub_weights(hw, sub_weights) + pop!(sub_weights) # heighest_weight + order_sub_weights(heighest_weight, sub_weights) return sub_weights end -function add_known_monomials!(weightspace, set_mon_in_weightspace, m, wts, mats, calc_monomials, space, e, cache_size) - #println("add_known_monomials: ", weightspace, set_mon_in_weightspace, m, wts, mats, calc_monomials, space, e) - #println("") +function add_known_monomials!(weightspace::Vector{Any}, set_mon_in_weightspace::Dict{Vector{Int64}, + Set{ZZMPolyRingElem}}, number_of_operators::Int, weights::Vector{Vector{Int64}}, + matrices_of_operators::Vector{SMat{ZZRingElem}}, calc_monomials::Dict{ZZMPolyRingElem, + Tuple{TVec, Vector{Int}}}, + space::Dict{Vector{Int64}, Oscar.BasisLieHighestWeight.VSBasis}, e::Vector{Vector{Int}}, + cache_size::Int) """ - By using the Minkowski-sum, we know that all monomials in set_mon_in_weightspace are in our basis. Since we want to extend the weightspacse with - missing monomials, we go need to calculate and add the vector of each monomial to our basis. + By using the Minkowski-sum, we know that all monomials in set_mon_in_weightspace are in our basis. Since we want to + extend the weightspacse with missing monomials, we go need to calculate and add the vector of each monomial to our + basis. """ weight = weightspace[1] for mon in set_mon_in_weightspace[weight] - #vec, wt = calc_new_mon!(mon, m, wts, mats, calc_monomials, space, e, cache_size) - d = sz(mats[1]) + #vec, wt = calc_new_mon!(mon, number_of_operators, weights, matrices_of_operators, calc_monomials, space, e, + # cache_size) + d = sz(matrices_of_operators[1]) v0 = sparse_row(ZZ, [(1,1)]) # starting vector v - vec = calc_vec(v0, mon, mats) - wt = calc_wt(mon, wts) + vec = calc_vec(v0, mon, matrices_of_operators) + wt = calc_weight(mon, weights) #println("vec:" , vec) #println("wt: ", wt) if !haskey(space, wt) space[wt] = nullSpace() end - addAndReduce!(space[wt], vec) + add_and_reduce!(space[wt], vec) end - #GC.gc() end -function add_new_monomials!(t, n, ZZx, x, mats, wts, monomial_order, weightspace, wts_eps, set_mon_in_weightspace, calc_monomials, space, e, cache_size, set_mon, m) +function add_new_monomials!(type::String, rank::Int, ZZx::ZZMPolyRing, x::Vector{ZZMPolyRingElem}, + matrices_of_operators::Vector{SMat{ZZRingElem}}, weights::Vector{Vector{Int}}, + monomial_order_lt::Function, weightspace::Vector{Any}, weights_eps::Vector{Vector{Int}}, + set_mon_in_weightspace::Dict{Vector{Int64}, Set{ZZMPolyRingElem}}, + calc_monomials::Dict{ZZMPolyRingElem, Tuple{TVec, Vector{Int}}}, space::Dict{Vector{Int64}, + Oscar.BasisLieHighestWeight.VSBasis}, e::Vector{Vector{Int}}, cache_size::Int, + set_mon::Set{ZZMPolyRingElem}) """ - If a weightspace is missing monomials, we need to calculate them by trial and error. We would like to go through all monomials in the order monomial_order - and calculate the corresponding vector. If it extends the basis, we add it to the result and else we try the next one. We know, that all monomials that work - lie in the weyl-polytope. Therefore, we only inspect the monomials that lie both in the weyl-polytope and the weightspace. Since the weyl-polytope is bounded - these are finitely many, we can sort them and then go trough them, until we found enough. + If a weightspace is missing monomials, we need to calculate them by trial and error. We would like to go through all + monomials in the order monomial_order_lt and calculate the corresponding vector. If it extends the basis, we add it + to the result and else we try the next one. We know, that all monomials that work lay in the weyl-polytope. + Therefore, we only inspect the monomials that lie both in the weyl-polytope and the weightspace. Since the weyl- + polytope is bounded these are finitely many, we can sort them and then go trough them, until we found enough. """ - #println("") - #println("add_new_monomials: ", t, n, ZZx, x, mats, wts, monomial_order, weightspace, wts_eps, set_mon_in_weightspace, calc_monomials, space, e, cache_size, set_mon, m) - #println("") - #println("memory: ", Int(Base.Sys.free_memory()) / 2^20) weight = weightspace[1] dim_weightspace = weightspace[2] # get monomials from weyl-polytope that are in the weightspace - poss_mon_in_weightspace = convert_lattice_points_to_monomials(ZZx, get_lattice_points_of_weightspace(wts_eps, w_to_eps(t, n, weight), t)) - lt_function = lt_monomial_order(monomial_order, ZZx, x) - poss_mon_in_weightspace = sort(poss_mon_in_weightspace, lt=lt_function) + poss_mon_in_weightspace = convert_lattice_points_to_monomials(ZZx, + get_lattice_points_of_weightspace(weights_eps, w_to_eps(type, rank, weight), type)) + poss_mon_in_weightspace = sort(poss_mon_in_weightspace, lt=monomial_order_lt) # check which monomials should get added to the basis i=0 @@ -256,15 +314,15 @@ function add_new_monomials!(t, n, ZZx, x, mats, wts, monomial_order, weightspace end # calculate the vector and check if it extends the basis - #vec, _ = calc_new_mon!(mon, m, wts, mats, calc_monomials, space, e, cache_size) - d = sz(mats[1]) + #vec, _ = calc_new_mon!(mon, m, weights, matrices_of_operators, calc_monomials, space, e, cache_size) + d = sz(matrices_of_operators[1]) v0 = sparse_row(ZZ, [(1,1)]) # starting vector v - vec = calc_vec(v0, mon, mats) + vec = calc_vec(v0, mon, matrices_of_operators) #println("vec:" , vec) if !haskey(space, weight) space[weight] = nullSpace() end - vec_red = addAndReduce!(space[weight], vec) + vec_red = add_and_reduce!(space[weight], vec) if isempty(vec_red) # v0 == 0 continue end @@ -272,38 +330,30 @@ function add_new_monomials!(t, n, ZZx, x, mats, wts, monomial_order, weightspace # save monom number_mon_in_weightspace += 1 push!(set_mon, mon) - end - - # Weirdly, removing this causes memory problems. The lines should not be necessary since the objects are not referenced - # and the garbage collector should run automatically. If I find out what causes this, it will be removed. - #weight = 0 - #dim_weightspace = 0 - #lt_function = 0 - #number_mon_in_weightspace = 0 - #poss_mon_in_weightspace = 0 - #GC.gc() end -function add_by_hand(t, n, L, ZZx, x, hw, ops, wts, wts_eps, monomial_order, gapDim, set_mon, cache_size::Int, parallel::Bool) +function add_by_hand(type::String, rank::Int, lie_algebra::GAP.Obj, ZZx::ZZMPolyRing, x::Vector{ZZMPolyRingElem}, + heighest_weight::Vector{Int}, operators::GAP.Obj, weights::Vector{Vector{Int64}}, + weights_eps::Vector{Vector{Int64}}, monomial_order_lt::Function, gapDim::Int, + set_mon::Set{ZZMPolyRingElem}, cache_size::Int, parallel::Bool)::Set{ZZMPolyRingElem} """ - This function calculates the missing monomials by going through each non full weightspace and adding possible monomials - manually by computing their corresponding vectors and checking if they enlargen the basis. + This function calculates the missing monomials by going through each non full weightspace and adding possible + monomials manually by computing their corresponding vectors and checking if they enlargen the basis. """ - #println("") - #println("") - #println("add_by_hand: ", hw) # initialization - mats = tensorMatricesForOperators(L, hw, ops) # matrices g_i for (g_1^a_1 * ... * g_k^a_k)*v - m = length(mats) - e = [(1:m .== i) for i in 1:m] # e_i - space = Dict(0*wts[1] => nullSpace()) # span of basis vectors to keep track of the basis - d = sz(mats[1]) + # matrices g_i for (g_1^a_1 * ... * g_k^a_k)*v + matrices_of_operators = tensorMatricesForOperators(lie_algebra, heighest_weight, operators) + number_of_operators = length(matrices_of_operators) + e = [1*(1:number_of_operators .== i) for i in 1:number_of_operators] # e_i + space = Dict(0*weights[1] => nullSpace()) # span of basis vectors to keep track of the basis v0 = sparse_row(ZZ, [(1,1)]) # starting vector v - calc_monomials = Dict{ZZMPolyRingElem, Tuple{TVec, Vector{Int}}}(ZZx(1) => (v0, 0 * wts[1])) # saves the calculated vectors to decrease necessary matrix multiplicatons + # saves the calculated vectors to decrease necessary matrix multiplicatons + calc_monomials = Dict{ZZMPolyRingElem, Tuple{TVec, Vector{Int}}}(ZZx(1) => (v0, 0 * weights[1])) push!(set_mon, ZZx(1)) - weightspaces = get_dim_weightspace(t, n, L, hw) # required monomials of each weightspace + # required monomials of each weightspace + weightspaces = get_dim_weightspace(type, rank, lie_algebra, heighest_weight) # sort the monomials from the minkowski-sum by their weightspaces set_mon_in_weightspace = Dict{Vector{Int}, Set{ZZMPolyRingElem}}() @@ -311,7 +361,7 @@ function add_by_hand(t, n, L, ZZx, x, hw, ops, wts, wts_eps, monomial_order, gap set_mon_in_weightspace[weight] = Set{ZZMPolyRingElem}() end for mon in set_mon - weight = calc_wt(mon, wts) + weight = calc_weight(mon, weights) push!(set_mon_in_weightspace[weight], mon) end @@ -323,41 +373,41 @@ function add_by_hand(t, n, L, ZZx, x, hw, ops, wts, wts_eps, monomial_order, gap deleteat!(weightspaces, full_weightspaces) weightsapces = full_weightspaces - - # use parallel computations if parallel=true. The weightspaces could be calculated completely indepent. We just save - # the computed monomials. - # insert known monomials into basis + # use parallel computations if parallel=true. The weightspaces could be calculated completely indepent. This is not + # implemented, since I used the package Distributed.jl for this, which is not in the Oscar dependencies. But I plan + # to reimplement this. insert known monomials into basis for weightspace in weightspaces - add_known_monomials!(weightspace, set_mon_in_weightspace, m, wts, mats, calc_monomials, space, e, cache_size) + add_known_monomials!(weightspace, set_mon_in_weightspace, number_of_operators, weights, matrices_of_operators, + calc_monomials, space, e, cache_size) end # calculate new monomials for weightspace in weightspaces - add_new_monomials!(t, n, ZZx, x, mats, wts, monomial_order, weightspace, wts_eps, set_mon_in_weightspace, calc_monomials, space, e, cache_size, set_mon, m) + add_new_monomials!(type, rank, ZZx, x, matrices_of_operators, weights, monomial_order_lt, weightspace, + weights_eps, set_mon_in_weightspace, calc_monomials, space, e, cache_size, set_mon) end - #println("calc_monomials: ", length(calc_monomials)) return set_mon end -function get_dim_weightspace(t, n, L, hw) +function get_dim_weightspace(type::String, rank::Int, lie_algebra::GAP.Obj, heighest_weight::Vector{Int})::Vector{Any} """ calculates matrix, first row weights, second row dimension of corresponding weightspace GAP computes the dimension for all positive weights. The dimension is constant on orbits of the weylgroup, and we can therefore calculate the dimension of each weightspace. """ # calculate dimension for dominant weights with GAP - R = GAP.Globals.RootSystem(L) - W = fromGap(GAP.Globals.DominantCharacter(R, GAP.Obj(hw))) - dominant_weights = W[1] - dominant_weights_dim = W[2] + root_system = GAP.Globals.RootSystem(lie_algebra) + dominant_weights, dominant_weights_dim = fromGap(GAP.Globals.DominantCharacter(root_system, + GAP.Obj(heighest_weight))) + dominant_weights = convert(Vector{Vector{Int}}, dominant_weights) dim_weightspace = [] # calculate dimension for the rest by checking which positive weights lies in the orbit. for i in 1:length(dominant_weights) - orbit_weights = orbit_weylgroup(t,n, dominant_weights[i]) + orbit_weights = orbit_weylgroup(type, rank, lie_algebra, dominant_weights[i]) dim = dominant_weights_dim[i] - for weight in eachrow(orbit_weights) - append!(dim_weightspace, [[hw-eps_to_w(t,n,weight), dim]]) + for weight in orbit_weights + append!(dim_weightspace, [[heighest_weight - weight, dim]]) end end return dim_weightspace diff --git a/experimental/BasisLieHighestWeight/src/LieAlgebras.jl b/experimental/BasisLieHighestWeight/src/LieAlgebras.jl index f02630cce6de..57aa9bf87517 100644 --- a/experimental/BasisLieHighestWeight/src/LieAlgebras.jl +++ b/experimental/BasisLieHighestWeight/src/LieAlgebras.jl @@ -1,22 +1,18 @@ -# ? - using Oscar -#using SparseArrays fromGap = Oscar.GAP.gap_to_julia -function lieAlgebra(t::String, n::Int) +function lieAlgebra(type::String, rank::Int)::Tuple{GAP.Obj, GAP.Obj} """ Creates the Lie-algebra as a GAP object that gets used for a lot other computations with GAP """ - L = GAP.Globals.SimpleLieAlgebra(GAP.Obj(t), n, GAP.Globals.Rationals) - return L, GAP.Globals.ChevalleyBasis(L) + lie_algebra = GAP.Globals.SimpleLieAlgebra(GAP.Obj(type), rank, GAP.Globals.Rationals) + return lie_algebra, GAP.Globals.ChevalleyBasis(lie_algebra) end gapReshape(A) = sparse_matrix(QQ, hcat(A...)) -#gapReshape(A) = sparse(hcat(A...)) # temporary workaround for issue 2128 function multiply_scalar(A::SMat{T}, d) where T @@ -24,39 +20,35 @@ function multiply_scalar(A::SMat{T}, d) where T scale_row!(A, i, T(d)) end return A - #return identity_matrix(SMat, QQ, size(A)[1])*A end -function matricesForOperators(L, hw, ops) +function matricesForOperators(lie_algebra::GAP.Obj, heighest_weight::Vector{Int}, + ops::GAP.Obj)::Vector{SMat{ZZRingElem}} """ used to create tensorMatricesForOperators """ - #M = GAP.Globals.HighestWeightModule(L, GAP.Obj(hw)) - #mats = GAP.Globals.List(ops, o -> GAP.Globals.MatrixOfAction(GAP.Globals.Basis(M), o)) - M = Oscar.GAP.Globals.HighestWeightModule(L, Oscar.GAP.julia_to_gap(hw)) - mats = Oscar.GAP.Globals.List(ops, o -> Oscar.GAP.Globals.MatrixOfAction(GAP.Globals.Basis(M), o)) - #mats = gapReshape.(fromGap(mats)) - mats = gapReshape.( Oscar.GAP.gap_to_julia(mats)) - denominators = map(y->denominator(y[2]), union(union(mats...)...)) - #d = convert(QQ, lcm(denominators)) - d = lcm(denominators)# // 1 - mats = (A->change_base_ring(ZZ, multiply_scalar(A, d))).(mats) - return mats + M = Oscar.GAP.Globals.HighestWeightModule(lie_algebra, Oscar.GAP.julia_to_gap(heighest_weight)) + matrices_of_operators = Oscar.GAP.Globals.List(ops, o -> Oscar.GAP.Globals.MatrixOfAction(GAP.Globals.Basis(M), o)) + matrices_of_operators = gapReshape.( Oscar.GAP.gap_to_julia(matrices_of_operators)) + denominators = map(y->denominator(y[2]), union(union(matrices_of_operators...)...)) + common_denominator = lcm(denominators)# // 1 + matrices_of_operators = (A->change_base_ring(ZZ, multiply_scalar(A, common_denominator))).(matrices_of_operators) + return matrices_of_operators end -function weightsForOperators(L, cartan, ops) +function weightsForOperators(lie_algebra::GAP.Obj, cartan::GAP.Obj, operators::GAP.Obj)::Vector{Vector{Int}} """ Calculates the weight wts[i] for each operator ops[i] """ cartan = fromGap(cartan, recursive=false) - ops = fromGap(ops, recursive=false) + operators = fromGap(operators, recursive=false) asVec(v) = fromGap(GAP.Globals.ExtRepOfObj(v)) - if any(iszero.(asVec.(ops))) + if any(iszero.(asVec.(operators))) error("ops should be non-zero") end nzi(v) = findfirst(asVec(v) .!= 0) return [ - [asVec(h*v)[nzi(v)] / asVec(v)[nzi(v)] for h in cartan] for v in ops + [asVec(h*v)[nzi(v)] / asVec(v)[nzi(v)] for h in cartan] for v in operators ] end diff --git a/experimental/BasisLieHighestWeight/src/MonomialOrder.jl b/experimental/BasisLieHighestWeight/src/MonomialOrder.jl index 93d04c55fabb..617764e72387 100644 --- a/experimental/BasisLieHighestWeight/src/MonomialOrder.jl +++ b/experimental/BasisLieHighestWeight/src/MonomialOrder.jl @@ -1,19 +1,20 @@ # manages methods for different orders of monomials -function lt_monomial_order(monomial_order, ZZx, x) - """ - Returns the desired monomial_order function - """ - #if isa(monomial_order, Function) - # return monomial_order - if monomial_order == "GRevLex" - choosen_monomial_order = degrevlex(x) - elseif monomial_order == "RevLex" - choosen_monomial_order = revlex(x) - elseif monomial_order == "Lex" - choosen_monomial_order = lex(x) - else - println("no suitable order picked") - end - return (mon1, mon2) -> (cmp(choosen_monomial_order, mon1, mon2) == -1) +function get_monomial_order_lt(monomial_order::Union{String, Function}, ZZx::ZZMPolyRing, + x::Vector{ZZMPolyRingElem})::Function +""" +Returns the desired monomial_order function +""" +#if isa(monomial_order, Function) +# return monomial_order +if monomial_order == "GRevLex" +choosen_monomial_order = degrevlex(x) +elseif monomial_order == "RevLex" +choosen_monomial_order = revlex(x) +elseif monomial_order == "Lex" +choosen_monomial_order = lex(x) +else +println("no suitable order picked") +end +return (mon1, mon2) -> (cmp(choosen_monomial_order, mon1, mon2) == -1) end diff --git a/experimental/BasisLieHighestWeight/src/NewMonomial.jl b/experimental/BasisLieHighestWeight/src/NewMonomial.jl index da2e9d573f8c..f0e8e17f7be8 100644 --- a/experimental/BasisLieHighestWeight/src/NewMonomial.jl +++ b/experimental/BasisLieHighestWeight/src/NewMonomial.jl @@ -1,12 +1,3 @@ -# main file -#--- bekommt gerade noch ZZ, Short und TVEC aus VectorSpaceBases - - -# TODO use dimension of weightspace to stop unnecessary calculations -# TODO use UInt8 instead of Int for polynomials again - -# module MB2 - include("./VectorSpaceBases.jl") include("./TensorModels.jl") include("./LieAlgebras.jl") @@ -16,19 +7,22 @@ include("./WeylPolytope.jl") fromGap = Oscar.GAP.gap_to_julia -function calc_wt(mon, weights) +function calc_weight(mon::ZZMPolyRingElem, weights::Vector{Vector{Int}})::Vector{Int} """ - + calculates weight associated with monomial mon """ degree_mon = degrees(mon) - wt = [0 for i in 1:length(weights[1])] + weight = [0 for i in 1:length(weights[1])] for i in 1:length(degree_mon) - wt .+= degree_mon[i] * weights[i] + weight .+= degree_mon[i] * weights[i] end - return wt + return weight end -function calc_vec(v0, mon, mats) +function calc_vec(v0::SRow{ZZRingElem}, mon::ZZMPolyRingElem, mats)::SRow{ZZRingElem} + """ + calculates vector associated with monomial mon + """ vec = v0 degree_mon = degrees(mon) for i in length(degree_mon):-1:1 @@ -39,7 +33,8 @@ function calc_vec(v0, mon, mats) return vec end -function highest_calc_sub_monomial(mon::Vector{Int}, calc_monomials) +function highest_calc_sub_monomial(mon::ZZMPolyRingElem, + calc_monomials::Dict{ZZMPolyRingElem, Tuple{TVec, Vector{Int}}})::ZZMPolyRingElem """ returns the key in calc_monomials that can be extended by the least amount of left-operations to mon """ @@ -48,8 +43,6 @@ function highest_calc_sub_monomial(mon::Vector{Int}, calc_monomials) m = length(mon) for i in 1:m while sub_mon[i] > 0 - #println(sub_mon) - #println(calc_monomials) if haskey(calc_monomials, sub_mon) return sub_mon else @@ -57,59 +50,49 @@ function highest_calc_sub_monomial(mon::Vector{Int}, calc_monomials) end end end - #println(sub_mon) - return sub_mon # [0 for i in 1:m] + return sub_mon end -function calc_new_mon!(mon, m, wts, mats, calc_monomials, space, e, cache_size) +function calc_new_mon!(mon::ZZMPolyRingElem, number_of_operators::Int, weights::Vector{Int}, + matrices_of_operators::Vector{SMat{ZZRingElem}}, + calc_monomials::Dict{ZZMPolyRingElem, Tuple{TVec, Vector{Int}}}, + space::Dict{Vector{Int64}, Oscar.BasisLieHighestWeight.VSBasis}, e::Vector{Vector{Int}}, + cache_size::Int)::Tuple{SRow{ZZRingElem}, Vector{Int}} # calculate vector of mon by extending a previous calculated vector to a # monom that differs only by left-multiplication, save results in calc_monomials sub_mon = highest_calc_sub_monomial(mon, calc_monomials) #println("sub_mon: ", sub_mon) sub_mon_cur = copy(sub_mon) - if !haskey(calc_monomials, sub_mon_cur) - println("ERROR IN calc_new_mon") - println(mon) - println(sub_mon_cur) - println(calc_monomials) - end - (vec, wt) = calc_monomials[sub_mon] - - # this block cannot be used in MB3 because we don't iterate through monomials in universal order, - # but instead in the monomial-order for each weightspace - #if mon == sub_mon # mon already contained so we need to reduce it to 0 - # return spzeros(ZZ, m), wt - #end - - #needs_to_be_saved = true - for i in m:-1:1 + (vec, weight) = calc_monomials[sub_mon] + for i in number_of_operators:-1:1 for k in sub_mon[i]:(mon[i]-1) sub_mon_cur += e[i] - wt += wts[i] - if !haskey(space, wt) - space[wt] = nullSpace() + weight += weights[i] + if !haskey(space, weight) + space[weight] = nullSpace() end #if isempty(vec.nzind) # v already 0 # needs_to_be_saved = false #else # vec = mats[i] * vec #end - #vec = addAndReduce!(space[wt], vec) + #vec = add_and_reduce!(space[weight], vec) #println(sub_mon_cur) #if needs_to_be_saved - # calc_monomials[sub_mon_cur] = (vec, wt) + # calc_monomials[sub_mon_cur] = (vec, weight) #end #mul!(A, vec) - vec = mats[i] * vec + vec = matrices_of_operators[i] * vec if length(calc_monomials) < cache_size - calc_monomials[sub_mon_cur] = (vec, wt) + calc_monomials[sub_mon_cur] = (vec, weight) end - # check if the extended monomial can be deleted from calculated_monomials, i.e. the other possible extensions are already contained + # check if the extended monomial can be deleted from calculated_monomials, i.e. the other possible + # extensions are already contained can_be_deleted = true - k = m - for l in 1:m - if (sub_mon_cur-e[i])[l] != 0 + k = number_of_operators + for l in 1:number_of_operators + if (sub_mon_cur - e[i])[l] != 0 k = l end end @@ -121,7 +104,8 @@ function calc_new_mon!(mon, m, wts, mats, calc_monomials, space, e, cache_size) end end end - # calc_monomials[sub_mon_cur] = (vec, wt) this position is for graded_reverse_lexicographic enough instead of the one above - return vec, wt + # calc_monomials[sub_mon_cur] = (vec, weight) this position is for graded_reverse_lexicographic enough instead of + # the one above + return vec, weight end diff --git a/experimental/BasisLieHighestWeight/src/RootConversion.jl b/experimental/BasisLieHighestWeight/src/RootConversion.jl index bb8f6ac1f51f..fa8d54fa7ab4 100644 --- a/experimental/BasisLieHighestWeight/src/RootConversion.jl +++ b/experimental/BasisLieHighestWeight/src/RootConversion.jl @@ -3,172 +3,159 @@ using Oscar fromGap = Oscar.GAP.gap_to_julia -############################################ -# conversion weight representation # -############################################ - - -function w_to_eps(t, n, weight) - #println("w_to_eps: ", t, n, weight) - if t == "A" - return w_to_eps_A(n, weight) - elseif t in ["B", "C", "D", "E", "F", "G"] - #return round.(alpha_to_eps(t, n, w_to_alpha(t, n, weight))) # round not necessary - return alpha_to_eps(t, n, w_to_alpha(t, n, weight)) +function w_to_eps(type::String, rank::Int, weight::Vector{Int})::Vector{Int} + if type == "A" + return w_to_eps_A(rank, weight) + elseif type in ["B", "C", "D", "E", "F", "G"] + return alpha_to_eps(type, rank, w_to_alpha(type, rank, weight)) else println("This type of lie algebra is not supported.") end end -function eps_to_w(t, n, weight) - #println("eps_to_w: ", t, n, weight) - if t == "A" - return eps_to_w_A(n, weight) - elseif t in ["B", "C", "D", "E", "F", "G"] - return round.(alpha_to_w(t, n, eps_to_alpha(t, n, weight))) - #return alpha_to_w(t, n, eps_to_alpha(t, n, weight)) +function eps_to_w(type::String, rank::Int, weight::Vector{Int})::Vector{Int} + if type == "A" + return eps_to_w_A(rank, weight) + elseif type in ["B", "C", "D", "E", "F", "G"] + return round.(alpha_to_w(type, rank, eps_to_alpha(type, rank, weight))) else println("This type of lie algebra is not supported.") end end -function alpha_to_eps(t, n, weight) - if t in ["B", "C", "D"] - return alpha_to_eps_BCD(t, n, weight) - elseif t == "E" && n in [6, 7, 8] - return alpha_to_eps_E(n, weight) - elseif t == "F" && n == 4 +function alpha_to_eps(type::String, rank::Int, weight::Vector{Int})::Vector{Int} + if type in ["B", "C", "D"] + return alpha_to_eps_BCD(type, rank, weight) + elseif type == "E" && rank in [6, 7, 8] + return alpha_to_eps_E(rank, weight) + elseif type == "F" && rank == 4 return alpha_to_eps_F(weight) - elseif t == "G" && n == 2 + elseif type == "G" && rank == 2 return alpha_to_eps_G(weight) else println("This rank of lie algebra is not supported.") end end -function eps_to_alpha(t, n, weight) - if t in ["B", "C", "D"] - return eps_to_alpha_BCD(t, n, weight) - elseif t == "E" && n in [6, 7, 8] - return eps_to_alpha_E(n, weight) - elseif t == "F" && n == 4 +function eps_to_alpha(type::String, rank::Int, weight::Vector{Int})::Vector{Int} + if type in ["B", "C", "D"] + return eps_to_alpha_BCD(type, rank, weight) + elseif type == "E" && rank in [6, 7, 8] + return eps_to_alpha_E(rank, weight) + elseif type == "F" && rank == 4 return eps_to_alpha_F(weight) - elseif t == "G" && n == 2 + elseif type == "G" && rank == 2 return eps_to_alpha_G(weight) else println("This rank of lie algebra is not supported.") end end -function w_to_alpha(t, n, weight) - C = get_CartanMatrix(t, n) - #return round.([i for i in C*weights]) - #println("w_to_alpha: ", [i for i in C*weight]) +function w_to_alpha(type, rank, weight::Vector{Int})::Vector{Int} + C = get_CartanMatrix(type, rank) return [i for i in C*weight] end -function alpha_to_w(t, n, weight) - C_inv = get_inverse_CartanMatrix(t, n) - #return round.([i for i in C_inv*weights]) - #println("alpha_to_w: ", [i for i in C_inv*weight]) +function alpha_to_w(type::String, rank::Int, weight::Vector{Int})::Vector{Int} + C_inv = get_inverse_CartanMatrix(type, rank) return [i for i in C_inv*weight] end -function get_CartanMatrix(t, n) - L = GAP.Globals.SimpleLieAlgebra(GAP.Obj(t), n, GAP.Globals.Rationals) +function get_CartanMatrix(type::String, rank::Int) + L = GAP.Globals.SimpleLieAlgebra(GAP.Obj(type), rank, GAP.Globals.Rationals) R = GAP.Globals.RootSystem(L) C_list = fromGap(GAP.Globals.CartanMatrix(R)) - C = zeros(n,n) - for i in 1:n - for j in 1:n + C = zeros(rank, rank) + for i in 1:rank + for j in 1:rank C[i,j] = C_list[i][j] end end return C end -function get_inverse_CartanMatrix(t, n) - return inv(get_CartanMatrix(t, n)) +function get_inverse_CartanMatrix(type::String, rank::Int) + return inv(get_CartanMatrix(type, rank)) end -function alpha_to_eps_BCD(t, n, weight) +function alpha_to_eps_BCD(type::String, rank::Int, weight::Vector{Int})::Vector{Int} """ for B-D """ - eps = [0.0 for i=1:n] - for i in 1:(n-1) + eps = [0.0 for i in 1:rank] + for i in 1:(rank-1) eps[i] += weight[i] eps[i+1] -= weight[i] end - if t == "B" - eps[n] += weight[n] - elseif t == "C" - eps[n] += 2*weight[n] - elseif t == "D" - eps[n-1] += weight[n] - eps[n] += weight[n] + if type == "B" + eps[rank] += weight[rank] + elseif type == "C" + eps[rank] += 2*weight[rank] + elseif type == "D" + eps[rank - 1] += weight[rank] + eps[rank] += weight[rank] end return eps end -function eps_to_alpha_BCD(t, n, weight) +function eps_to_alpha_BCD(type::String, rank::Int, weight::Vector{Int})::Vector{Int} """ for B-D """ - alpha = [0.0 for i=1:n] - for i in 1:(n-2) + alpha = [0.0 for i in 1:rank] + for i in 1:(rank-2) alpha[i] = weight[i] weight[i+1] += weight[i] end - if t == "B" - alpha[n-1] = weight[n-1] - alpha[n] += weight[n-1] + weight[n] - elseif t == "C" - alpha[n-1] = weight[n-1] - alpha[n] += 0.5*weight[n-1] + 0.5*weight[n] # requires eps to be always even - elseif t == "D" - alpha[n-1] += (weight[n-1] - weight[n])/2 - alpha[n] += (weight[n-1] + weight[n])/2 + if type == "B" + alpha[rank - 1] = weight[rank - 1] + alpha[rank] += weight[rank-1] + weight[rank] + elseif type == "C" + alpha[rank - 1] = weight[rank - 1] + alpha[rank] += 0.5*weight[rank - 1] + 0.5*weight[rank] # requires eps to be always even + elseif type == "D" + alpha[rank - 1] += (weight[rank - 1] - weight[rank])/2 + alpha[rank] += (weight[rank - 1] + weight[rank])/2 end return alpha end -function alpha_to_eps_E(n, weight) +function alpha_to_eps_E(rank::Int, weight::Vector{Int})::Vector{Int} """ for E """ - if n == 6 + if rank == 6 return alpha_to_eps_E6(weight) - elseif n == 7 + elseif rank == 7 return alpha_to_eps_E7(weight) - elseif n == 8 + elseif rank == 8 return alpha_to_eps_E8(weight) end end -function eps_to_alpha_E(n, weight) +function eps_to_alpha_E(rank::Int, weight) """ for E """ - if n == 6 + if rank == 6 return eps_to_alpha_E6(weight) - elseif n == 7 + elseif rank == 7 return eps_to_alpha_E7(weight) - elseif n == 8 + elseif rank == 8 return eps_to_alpha_E8(weight) end end -function alpha_to_eps_E6(weight) +function alpha_to_eps_E6(weight::Vector{Int})::Vector{Int} """ for E6, potentially wrong order or roots (1-2-3-5-6, 3-4) """ - eps = [0.0 for i=1:6] + eps = [0.0 for i in 1:6] for i in 1:4 eps[i] += weight[i] - eps[i+1] += - weight[i] + eps[i + 1] += - weight[i] end eps[4] += weight[5] eps[5] += weight[5] @@ -176,7 +163,6 @@ function alpha_to_eps_E6(weight) eps[i] += -0.5*weight[6] end eps[6] += 0.5*sqrt(3)*weight[6] - #println("alpha_to_eps_E6: ", eps) return eps end @@ -184,7 +170,7 @@ function eps_to_alpha_E6(weight) """ for E6 """ - alpha = [0.0 for i=1:6] + alpha = [0.0 for i in 1:6] for j in 1:3 for i in 1:j alpha[j] += weight[i] @@ -202,14 +188,14 @@ function eps_to_alpha_E6(weight) return alpha end -function alpha_to_eps_E7(weight) +function alpha_to_eps_E7(weight::Vector{Int})::Vector{Int} """ for E7, potentially wrong order of roots (1-2-3-4-6-7, 4-5) """ - eps = [0.0 for i=1:7] + eps = [0.0 for i in 1:7] for i in 1:5 eps[i] += weight[i] - eps[i+1] += - weight[i] + eps[i + 1] += - weight[i] end eps[5] += weight[6] eps[6] += weight[6] @@ -217,15 +203,14 @@ function alpha_to_eps_E7(weight) eps[i] += -0.5*weight[7] end eps[7] += 0.5*sqrt(2)*weight[7] - #println("alpha_to_eps_E7: ", eps) return eps end -function eps_to_alpha_E7(weight) +function eps_to_alpha_E7(weight::Vector{Int})::Vector{Int} """ for E7 """ - alpha = [0.0 for i=1:7] + alpha = [0.0 for i in 1:7] for j in 1:4 for i in 1:j alpha[j] += weight[i] @@ -239,15 +224,14 @@ function eps_to_alpha_E7(weight) alpha[5] += -0.5*weight[6] + sqrt(2)*weight[7] alpha[6] += 0.5*weight[6] + 3*(sqrt(2) / 2)*weight[7] alpha[7] = sqrt(2)*weight[7] - #println("eps_to_alpha_E6: ", alpha) return alpha end -function alpha_to_eps_E8(weight) +function alpha_to_eps_E8(weight::Vector{Int})::Vector{Int} """ for E8 """ - eps = [0.0 for i=1:8] + eps = [0.0 for i in 1:8] for i in 1:6 eps[i] += weight[i] eps[i+1] += - weight[i] @@ -260,11 +244,11 @@ function alpha_to_eps_E8(weight) return eps end -function eps_to_alpha_E8(weight) +function eps_to_alpha_E8(weight::Vector{Int})::Vector{Int} """ for E8 """ - alpha = [0.0 for i=1:8] + alpha = [0.0 for i in 1:8] for j in 1:5 for i in 1:j alpha[j] += weight[i] @@ -281,11 +265,11 @@ function eps_to_alpha_E8(weight) return alpha end -function alpha_to_eps_F(weight) # how does this work for G? +function alpha_to_eps_F(weight::Vector{Int})::Vector{Int} """ for F """ - eps = [0.0 for i=1:4] + eps = [0.0 for i in 1:4] eps[1] = weight[1] - 0.5*weight[4] eps[2] = - weight[1] + weight[2] - 0.5*weight[4] eps[3] = - weight[2] + weight[3] - 0.5*weight[4] @@ -293,11 +277,11 @@ function alpha_to_eps_F(weight) # how does this work for G? return eps end -function eps_to_alpha_F(weight) +function eps_to_alpha_F(weight::Vector{Int})::Vector{Int} """ for F """ - alpha = [0 for i=1:4] + alpha = [0 for i in 1:4] alpha[1] = weight[1] - weight[4] alpha[2] = weight[1] + weight[2] - 2*weight[4] alpha[3] = weight[1] + weight[2] + weight[3] - 3*weight[4] @@ -305,11 +289,11 @@ function eps_to_alpha_F(weight) return alpha end -function alpha_to_eps_G(weight) # how does this work for G? +function alpha_to_eps_G(weight::Vector{Int})::Vector{Int} """ for G_2 """ - eps = [0.0 for i=1:3] + eps = [0.0 for i in 1:3] eps[1] = weight[1] - weight[2] eps[2] = - weight[1] + 2*weight[2] eps[3] = - weight[2] @@ -317,12 +301,11 @@ function alpha_to_eps_G(weight) # how does this work for G? return eps end -function eps_to_alpha_G(weight) +function eps_to_alpha_G(weight::Vector{Int})::Vector{Int} """ for G_2 """ - alpha = [0.0 for i=1:2] - #choose_representant_eps(weight) + alpha = [0.0 for i in 1:2] if length(weight) >= 3 weight .-= weight[3] end @@ -331,15 +314,15 @@ function eps_to_alpha_G(weight) return alpha end -function w_to_eps_A(n, weight) +function w_to_eps_A(rank::Int, weight::Vector{Int})::Vector{Int} """ input: weight in w_i output: weight in eps_i inverse to eps_to_w # TODO (right now only for t=A) """ - res = [0 for i=1:(n+1)] - for i in 1:n + res = [0 for i in 1:(rank+1)] + for i in 1:rank for l in 1:i res[l] += weight[i] end @@ -348,31 +331,27 @@ function w_to_eps_A(n, weight) return res end -function choose_representant_eps(weight) +function choose_representant_eps(weight::Vector{Int}) # choose representant eps_1 + ... + eps_m = 0 if any(<(0), weight) # non negative weight .-= min(weight ...) end end -function eps_to_w_A(n, weight) +function eps_to_w_A(rank::Int, weight::Vector{Int})::Vector{Int} """ input: weight in eps_i output: weight in w_i inverse to w_to_eps - # TODO (right now only for t=A) """ m = length(weight) choose_representant_eps(weight) - if weight[n+1] != 0 # eps_n+1 = 0 - weight .-= weight[n+1] - weight[n+1] = 0 + if weight[rank + 1] != 0 # eps_n+1 = 0 + weight .-= weight[rank + 1] + weight[rank + 1] = 0 end - #if all(>(0), weight) # minimal - # weight .-= min(weight ...) - #end - res = [0 for i=1:n] - for i in n:-1:1 + res = [0 for i in 1:rank] + for i in rank:-1:1 res[i] = weight[i] for l in 1:i weight[l] -= weight[i] diff --git a/experimental/BasisLieHighestWeight/src/TensorModels.jl b/experimental/BasisLieHighestWeight/src/TensorModels.jl index 3665bf9466b8..9254ba40e191 100644 --- a/experimental/BasisLieHighestWeight/src/TensorModels.jl +++ b/experimental/BasisLieHighestWeight/src/TensorModels.jl @@ -1,11 +1,9 @@ -# ? - using Oscar -#using SparseArrays - -# TODO: make the first one a symmetric product, or reduce more generally -function kron(A, B) +function kron(A::SMat{ZZRingElem}, B::SMat{ZZRingElem})::SMat{ZZRingElem} + """ + Computes the Kronecker-product of A and B + """ res = sparse_matrix(ZZ, nrows(A)*nrows(B), ncols(A)*ncols(B)) for i in 1:nrows(B) for j in 1:nrows(A) @@ -19,14 +17,11 @@ function kron(A, B) setindex!(res, new_row, (j-1)*nrows(B)+i) end end - #println("ncols(res): ", ncols(res)) - #println("nrows(res): ", nrows(res)) - return res end # temprary fix sparse in Oscar does not work -function tensorProduct(A, B) +function tensorProduct(A::SMat{ZZRingElem}, B::SMat{ZZRingElem})::SMat{ZZRingElem} temp_mat = kron(A, spid(sz(B))) + kron(spid(sz(A)), B) res = sparse_matrix(ZZ, nrows(A)*nrows(B), ncols(A)*ncols(B)) for i in 1:nrows(temp_mat) @@ -36,32 +31,28 @@ function tensorProduct(A, B) end -spid(n) = identity_matrix(SMat, ZZ, n) -sz(A) = nrows(A) #size(A)[1] +spid(n::Int) = identity_matrix(SMat, ZZ, n)::SMat{ZZRingElem} +sz(A::SMat{ZZRingElem}) = nrows(A)::Int #size(A)[1] #tensorProduct(A, B) = kron(A, spid(sz(B))) + kron(spid(sz(A)), B) tensorProducts(As, Bs) = (AB->tensorProduct(AB[1], AB[2])).(zip(As, Bs)) tensorPower(A, n) = (n == 1) ? A : tensorProduct(tensorPower(A, n-1), A) tensorPowers(As, n) = (A->tensorPower(A, n)).(As) - -function tensorMatricesForOperators(L, hw, ops) +function tensorMatricesForOperators(lie_algebra::GAP.Obj, heighest_weight::Vector{Int}, + operators::GAP.Obj)::Vector{SMat{ZZRingElem}} """ Calculates the matrices g_i corresponding to the operator ops[i]. """ - #println("hw: ", hw) - mats = [] - - for i in 1:length(hw) - #println("hw[i]: ", hw[i]) - if hw[i] <= 0 + matrices_of_operators = [] + for i in 1:length(heighest_weight) + if heighest_weight[i] <= 0 continue end - wi = Int.(1:length(hw) .== i) # i-th fundamental weight - _mats = matricesForOperators(L, wi, ops) - _mats = tensorPowers(_mats, hw[i]) - mats = mats == [] ? _mats : tensorProducts(mats, _mats) - #println(spdiagm(0 => [ZZ(1) for _ in 1:5])agm) - #display(mats) + wi = Int.(1:length(heighest_weight) .== i) # i-th fundamental weight + _matrices_of_operators = matricesForOperators(lie_algebra, wi, operators) + _matrices_of_operators = tensorPowers(_matrices_of_operators, heighest_weight[i]) + matrices_of_operators = matrices_of_operators == [] ? _matrices_of_operators : + tensorProducts(matrices_of_operators, _matrices_of_operators) end - return mats -end \ No newline at end of file + return matrices_of_operators +end diff --git a/experimental/BasisLieHighestWeight/src/VectorSpaceBases.jl b/experimental/BasisLieHighestWeight/src/VectorSpaceBases.jl index 75288085f41b..ffad0770f944 100644 --- a/experimental/BasisLieHighestWeight/src/VectorSpaceBases.jl +++ b/experimental/BasisLieHighestWeight/src/VectorSpaceBases.jl @@ -1,64 +1,58 @@ -# manages the basisvectors and its linear independence +# manages the linear (in-)dependence of integer vectors +# this file is only of use to BasisLieHighestWeight for the basis vectors using Oscar -# SparseArrays -TVec = SRow{ZZRingElem} # values ZZ, indices Int (TVec is datatype of basisvectors basisLieHighestWeight) +TVec = SRow{ZZRingElem} # values ZZ, indices Int (TVec is datatype of basisvectors in basisLieHighestWeight) Short = UInt8 # for exponents of monomials; max. 255 struct VSBasis - A::Vector{TVec} # vector of basisvectors - pivot::Vector{Int} # vector of pivotelements, i.e. pivot[i] is first nonzero element of A[i] + basis_vectors::Vector{TVec} # vector of basisvectors + pivot::Vector{Int} # vector of pivotelements, i.e. pivot[i] is first nonzero element of basis_vectors[i] dim::Vector{Int} # dimension end - nullSpace() = VSBasis([], [], []) # empty Vektorraum +reduceCol(a, b, i::Int) = (b[i]*a - a[i]*b)::TVec # create zero entry in a -function normalize(v::TVec) +function normalize(v::TVec)::Tuple{TVec, Int64} """ divides vector by gcd of nonzero entries, returns vector and first nonzero index - used: addAndReduce! + used: add_and_reduce! """ if is_empty(v) return (v, 0) end - pivot = first(v)[1] # first nonzero element of vector - return divexact(v, gcd(map(y->y[2], union(v)))), pivot end - -reduceCol(a, b, i::Int) = b[i]*a - a[i]*b # create zero entry in a - - -function addAndReduce!(sp::VSBasis, v::TVec) +function add_and_reduce!(sp::VSBasis, v::TVec)::TVec """ - for each pivot of sp.A we make entry of v zero and return the result and insert it into sp + for each pivot of sp.basis_vectors we make entry of v zero and return the result and insert it into sp 0 => linear dependent - * => linear independent, new column element of sp.A since it increases basis - invariants: the row of a pivotelement in any column in A is 0 (except the pivotelement) - elements of A are integers, gcd of each column is 1 + * => linear independent, new column element of sp.basis_vectors since it increases basis + invariants: the row of a pivotelement in any column in basis_vectors is 0 (except the pivotelement) + elements of basis_vectors are integers, gcd of each column is 1 """ - #println("sp: ", sp) - #println("v: ", v) - A = sp.A + # initialize objects + basis_vectors = sp.basis_vectors pivot = sp.pivot + v, newPivot = normalize(v) - v, newPivot = normalize(v) - if newPivot == 0 # v zero vector - + # case v zero vector + if newPivot == 0 return v end - - for j in 1:length(A) + + # use pivots of basis basis_vectors to create zeros in v + for j in 1:length(basis_vectors) i = pivot[j] if i != newPivot continue end - v = reduceCol(v, A[j], i) + v = reduceCol(v, basis_vectors[j], i) v, newPivot = normalize(v) if newPivot == 0 #return 0 @@ -66,12 +60,14 @@ function addAndReduce!(sp::VSBasis, v::TVec) end end + # new pivot element of v pos = findfirst(pivot .> newPivot) if (pos === nothing) pos = length(pivot) + 1 end - insert!(A, pos, v) + # save result + insert!(basis_vectors, pos, v) insert!(pivot, pos, newPivot) return v end diff --git a/experimental/BasisLieHighestWeight/src/WeylPolytope.jl b/experimental/BasisLieHighestWeight/src/WeylPolytope.jl index 77c8e7ab923c..bac5bf1832f6 100644 --- a/experimental/BasisLieHighestWeight/src/WeylPolytope.jl +++ b/experimental/BasisLieHighestWeight/src/WeylPolytope.jl @@ -5,51 +5,40 @@ include("./RootConversion.jl") fromGap = Oscar.GAP.gap_to_julia -######################### -# weyl-polytope # -######################### - -function weylpolytope(t::String, n::Int, hw::Vector{Int}) +function weylpolytope(type::String, rank::Int, lie_algebra::GAP.Obj, + heighest_weight::Vector{Int})::Polymake.BigObjectAllocated """ - returns weyl-polytope in homogeneous coordinates, i.e. convex hull of orbit of weyl-group of type t,n on highest weight vector hw + returns weyl-polytope in homogeneous coordinates, i.e. convex hull of orbit of weyl-group of + type type and rank rank on highest weight vector heighest_weight """ - vertices = orbit_weylgroup(t, n, hw) - #println("vertices: ", vertices) - println(vertices) - vertices_hom = [ones(Int64, size(vertices)[1]) vertices]# homogeneous coordinates - println(vertices_hom) - #println("vertices_hom: ", vertices_hom) - #weylpoly = convex_hull(vertices) # normalized to first coordinate 1? See documentation in PolyMake + vertices = orbit_weylgroup(type, rank, lie_algebra, heighest_weight) + vertices = transpose(hcat(vertices ...)) + vertices = [w for w in eachrow(vertices)] + vertices = transpose(hcat(vertices ...)) + vertices_hom = [ones(Int64, size(vertices)[1]) vertices] # in homogeneous coordinates weylpoly = polytope.Polytope(POINTS=vertices_hom) - #println("weylpoly: ", weylpoly) - #println("contains?:", contains(weylpoly, [0, 0])) return weylpoly end -function orbit_weylgroup(t::String, n::Int, hw) +function orbit_weylgroup(type::String, rank::Int, lie_algebra::GAP.Obj, weight_vector::Vector{Int}) """ - operates weyl-group of type t,n on highest weight vector hw and returns list of vector - input in terms of w_i, output in eps_i (fix!!) + operates weyl-group of type type and rank rank on vector weight_vector and returns list of vectors in orbit + input and output weights in terms of w_i """ - # also possible with polymake orbit_polytope(Vector input_point, Group g), root_system(String type) to save the equations, constant summand missing # initialization - L, CH = lieAlgebra(t, n) - W = GAP.Globals.WeylGroup(GAP.Globals.RootSystem(L)) - orb = GAP.Globals.WeylOrbitIterator(W, GAP.Obj(hw)) + weyl_group = GAP.Globals.WeylGroup(GAP.Globals.RootSystem(lie_algebra)) + orbit_iterator = GAP.Globals.WeylOrbitIterator(weyl_group, GAP.Obj(weight_vector)) vertices = [] - # operate with the weylgroup on hw - GAP.Globals.IsDoneIterator(orb) - while !(GAP.Globals.IsDoneIterator(orb)) - w = GAP.Globals.NextIterator(orb) + # operate with the weylgroup on weight_vector + GAP.Globals.IsDoneIterator(orbit_iterator) + while !(GAP.Globals.IsDoneIterator(orbit_iterator)) + w = GAP.Globals.NextIterator(orbit_iterator) push!(vertices, fromGap(w)) end - # return result - vertices = transpose(hcat(vertices ...)) - vertices = [w_to_eps(t, n, w) for w in eachrow(vertices)] - vertices = transpose(hcat(vertices ...)) - #println("wts_eps ", [w_to_eps(t, n, w) for w in eachrow(vertices)]) + # return + vertices = convert(Vector{Vector{Int}}, vertices) return vertices end @@ -64,61 +53,59 @@ function get_points_polytope(polytope) end -############################################# -# compute monomials for weightspace # -############################################# - function convert_lattice_points_to_monomials(ZZx, lattice_points_weightspace) - return [finish(push_term!(MPolyBuildCtx(ZZx), ZZ(1), convert(Vector{Int}, convert(Vector{Int64}, lattice_point)))) for lattice_point in lattice_points_weightspace] + return [finish(push_term!(MPolyBuildCtx(ZZx), ZZ(1), convert(Vector{Int}, convert(Vector{Int64}, lattice_point)))) + for lattice_point in lattice_points_weightspace] end -function get_lattice_points_of_weightspace(wts, weight, t) +function get_lattice_points_of_weightspace(weights, weight, type) """ - calculates all lattice points in a given weightspace for lie algebras of type t + calculates all lattice points in a given weightspace for lie algebras of type type input: - wts: the operator weights in eps_i + weights: the operator weights in eps_i weight: lambda - mu output: all lattice points with weight weight """ - if t in ["A", "G"] - return get_lattice_points_of_weightspace_A_G_n(wts, weight) + if type in ["A", "G"] + return get_lattice_points_of_weightspace_A_G_n(weights, weight) else - return get_lattice_points_of_weightspace_Xn(wts, weight) + return get_lattice_points_of_weightspace_Xn(weights, weight) end end -function get_lattice_points_of_weightspace_A_G_n(wts, weight) +function get_lattice_points_of_weightspace_A_G_n(weights, weight) """ calculates all monomials in a given weightspace for lie algebras that have type A or G input: - wts: the operator weights in eps_i + weights: the operator weights in eps_i weight: lambda - mu output: all monomials with weight weight works by calculating all integer solutions to the following linear program: [ 1 | | ] [ x ] - [ 1 wts[1] ... wts[k] ] * [ | ] = weight + [ 1 weights[1]... weights[k]] * [ | ] = weight [... | | ] [ res ] [ 1 | | ] [ | ] where res[i] >= 0 for all i example: - wts = [[1, 0, 2], [-1, 1, 1], [0, -1, 0]] (i.e. a_1 = eps_1 - eps_2, a_2 = eps_2 - eps_3, a_12 = eps_1 - eps_3) + weights = [[1, 0, 2], [-1, 1, 1], [0, -1, 0]] (i.e. a_1 = eps_1 - eps_2, a_2 = eps_2 - eps_3, a_12 = eps_1 - eps_3) weight = [2, 1, 0] - -> poly = polytope.Polytope(INEQUALITIES=[0 0 1 0 0; 0 0 0 1 0; 0 0 0 0 1], EQUATIONS=[-2 1 1 0 2; -1 1 -1 1 1; 0 1 0 -1 0]) + -> poly = polytope.Polytope(INEQUALITIES=[0 0 1 0 0; 0 0 0 1 0; 0 0 0 0 1], + EQUATIONS=[-2 1 1 0 2; -1 1 -1 1 1; 0 1 0 -1 0]) => returns [[1 0 0], [1 1 0]] """ - # build linear (in-)equations - wts = [reshape(w, 1, :) for w in wts] - n = length(wts) + # build linear (in-)equalities + weights = [reshape(w, 1, :) for w in weights] + n = length(weights) ineq = zeros(Int64, n, n+2) for i in 1:n ineq[i, 2+i] = 1 end equ = cat([-i for i in vec(weight)], [1 for i=1:length(weight)], dims = (2,2)) - equ = cat(equ, [transpose(w) for w in wts] ..., dims = (2,2)) + equ = cat(equ, [transpose(w) for w in weights] ..., dims = (2,2)) # find integer solutions of linear (in-)equation as lattice points of polytope poly = polytope.Polytope(INEQUALITIES=ineq, EQUATIONS=equ) @@ -130,38 +117,42 @@ function get_lattice_points_of_weightspace_A_G_n(wts, weight) end -function get_lattice_points_of_weightspace_Xn(wts, weight) +function get_lattice_points_of_weightspace_Xn(weights, weight) """ calculates all lattice points in a given weightspace for lie algebras that don't have type A input: - wts: the operator weights in eps_i + weights: the operator weights in eps_i weight: lambda - mu output: all lattice points with weight weight works by calculating all integer solutions to the following linear program: - [ | | ] [ x ] - [wts[1] ... wts[k] ] * [ | ] = weight - [ | | ] [ res ] - [ | | ] [ | ] + [ | | ] [ x ] + [weights[1]...weights[k]] * [ | ] = weight + [ | | ] [ res ] + [ | | ] [ | ] where res[i] >= 0 for all i example: - wts = [[1, 0, 2], [-1, 1, 1], [0, -1, 0]] (i.e. a_1 = eps_1 - eps_2, a_2 = eps_2 - eps_3, a_12 = eps_1 - eps_3) + weights = [[1, 0, 2], [-1, 1, 1], [0, -1, 0]] (i.e. a_1 = eps_1 - eps_2, a_2 = eps_2 - eps_3, a_12 = eps_1 - eps_3) weight = [2, 1, 0] -> poly = polytope.Polytope(INEQUALITIES=[0 1 0 0; 0 0 1 0; 0 0 0 1], EQUATIONS=[-2 1 0 2; -1 -1 1 1; 0 0 -1 0]) => returns """ - wts = [reshape(w, 1, :) for w in wts] - n = length(wts) + # build linear (in-)equalities + weights = [reshape(w, 1, :) for w in weights] + n = length(weights) ineq = zeros(Int64, n, n+1) for i in 1:n ineq[i, 1+i] = 1 end - #equ = cat([-i for i in vec(weight)], [1 for i=1:length(weight)], dims = (2,2)) equ = [-i for i in vec(weight)] - equ = cat(equ, [transpose(w) for w in wts] ..., dims = (2,2)) + equ = cat(equ, [transpose(w) for w in weights] ..., dims = (2,2)) + + # find integer solutions of linear (in-)equation as lattice points of polytope poly = polytope.Polytope(INEQUALITIES=ineq, EQUATIONS=equ) + + # convert lattice-points to Oscar monomials lattice_points_weightspace = lattice_points(Polyhedron(poly)) return lattice_points_weightspace end diff --git a/experimental/BasisLieHighestWeight/test/runtests.jl b/experimental/BasisLieHighestWeight/test/runtests.jl index 0a10ea2dc689..d8cf23f20775 100644 --- a/experimental/BasisLieHighestWeight/test/runtests.jl +++ b/experimental/BasisLieHighestWeight/test/runtests.jl @@ -9,42 +9,40 @@ forGap = Oscar.GAP.julia_to_gap fromGap = Oscar.GAP.gap_to_julia """ -We are testing our code in multiple ways. First, we calculated two small examples per hand and compare those. Then we check basic properties of the result. -For example we know the size of our monomial basis. These properties get partially used in the algorithm and could therefore be true for false results. We -have another basic algorithm that solves the problem without the recursion, weightspaces and saving of computations. The third test compares the results we -can compute with the weaker version. +We are testing our code in multiple ways. First, we calculated two small examples per hand and compare those. Then we +check basic properties of the result. For example we know the size of our monomial basis. These properties get partially +used in the algorithm and could therefore be true for false results. We have another basic algorithm that solves the +problem without the recursion, weightspaces and saving of computations. The third test compares the results we can +compute with the weaker version. """ function compare_algorithms(dynkin::Char, n::Int64, lambda::Vector{Int64}) - #print("compare_algorithms", dynkin, n, lambda) # old algorithm mons_old = MBOld.basisLieHighestWeight(string(dynkin), n, lambda) # basic algorithm # new algorithm - mons_new = BasisLieHighestWeight.basisLieHighestWeight2(string(dynkin), n, lambda) # algorithm that needs to be tested + mons_new = BasisLieHighestWeight.basisLieHighestWeight(string(dynkin), n, lambda) L = G.SimpleLieAlgebra(forGap(string(dynkin)), n, G.Rationals) gapDim = G.DimensionOfHighestWeightModule(L, forGap(lambda)) # dimension # comparison # convert set of monomials over different ring objects to string representation to compare for equality - @test issetequal(string.(mons_old), string.(mons_new)) # compare if result of basic and more sophisticated algorithm match + @test issetequal(string.(mons_old), string.(mons_new)) # compare if result of old and new algorithm match @test gapDim == length(mons_new) # check if dimension is correct end function check_dimension(dynkin::Char, n::Int64, lambda::Vector{Int64}, monomial_order::String) - w = BasisLieHighestWeight.basisLieHighestWeight2(string(dynkin), n, lambda, monomial_order=monomial_order) # algorithm that needs to be tested + w = BasisLieHighestWeight.basisLieHighestWeight(string(dynkin), n, lambda, monomial_order=monomial_order) L = G.SimpleLieAlgebra(forGap(string(dynkin)), n, G.Rationals) gapDim = G.DimensionOfHighestWeightModule(L, forGap(lambda)) # dimension @test gapDim == length(w) # check if dimension is correct end - @testset "Test basisLieHighestWeight" begin - # TODO: add test for basis (not just dimension) @testset "Known examples" begin - mons = BasisLieHighestWeight.basisLieHighestWeight2("A", 2, [1,0]) + mons = BasisLieHighestWeight.basisLieHighestWeight("A", 2, [1,0]) @test issetequal(string.(mons), Set(["1", "x3", "x1"])) - mons = BasisLieHighestWeight.basisLieHighestWeight2("A", 2, [1,0], ops=[1,2,1]) + mons = BasisLieHighestWeight.basisLieHighestWeight("A", 2, [1,0], operators=[1,2,1]) @test issetequal(string.(mons), Set(["1", "x2*x3", "x3"])) end @testset "Compare with simple algorithm and check dimension" begin @@ -72,14 +70,16 @@ end end @testset "Check dimension" begin @testset "Monomial order $monomial_order" for monomial_order in ("Lex", "RevLex", "GRevLex") - #@testset "Operators $ops" for ops in ("regular", "longest-word") + # the functionality longest-word was temporarily removed because it required coxeter groups from + # https://github.com/jmichel7/Gapjm.jl + #@testset "Operators $ops" for ops in ("regular", "longest-word") check_dimension('A', 3, [1,1,1], monomial_order) - # #check_dimension('B', 3, [2,1,0], monomial_order, ops) - # #check_dimension('C', 3, [1,1,1], monomial_order, ops) - # #check_dimension('D', 4, [3,0,1,1], monomial_order, ops) - # #check_dimension('F', 4, [2,0,1,0], monomial_order, ops) - # #check_dimension('G', 2, [1,0], monomial_order, ops) - # #check_dimension('G', 2, [2,2], monomial_order, ops) + #check_dimension('B', 3, [2,1,0], monomial_order, ops) + #check_dimension('C', 3, [1,1,1], monomial_order, ops) + #check_dimension('D', 4, [3,0,1,1], monomial_order, ops) + #check_dimension('F', 4, [2,0,1,0], monomial_order, ops) + #check_dimension('G', 2, [1,0], monomial_order, ops) + #check_dimension('G', 2, [2,2], monomial_order, ops) #end end end From b6507694c494dc23e338313562ff53838175dd1f Mon Sep 17 00:00:00 2001 From: BenWilop Date: Mon, 10 Apr 2023 22:27:48 +0200 Subject: [PATCH 15/19] a few small changes to improve readibility --- .../src/BasisLieHighestWeight.jl | 208 +++++++++--------- .../BasisLieHighestWeight/src/LieAlgebras.jl | 4 +- .../src/MonomialOrder.jl | 32 +-- .../BasisLieHighestWeight/src/NewMonomial.jl | 58 ++--- .../BasisLieHighestWeight/src/TensorModels.jl | 10 +- .../BasisLieHighestWeight/src/WeylPolytope.jl | 8 +- 6 files changed, 157 insertions(+), 163 deletions(-) diff --git a/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl b/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl index 02098bffa1d7..73d06e1aa7ae 100644 --- a/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl +++ b/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl @@ -11,14 +11,14 @@ include("./NewMonomial.jl") fromGap = Oscar.GAP.gap_to_julia @doc Markdown.doc""" - basisLieHighestWeight(type::String, rank::Int, heighest_weight::Vector{Int}; + basisLieHighestWeight(type::String, rank::Int, highest_weight::Vector{Int}; operators::Union{String, Vector{Int}} = "regular", monomial_order::Union{String, Function} = "GRevLex", cache_size::Int = 0, parallel::Bool = false, return_no_minkowski::Bool = false, return_operators::Bool = false) Computes a monomial basis for the highest weight module with highest weight -``heighest_weight`` (in terms of the fundamental weights), for a simple Lie algebra of type +``highest_weight`` (in terms of the fundamental weights), for a simple Lie algebra of type ``type`` and rank ``rank``. # Parameters @@ -42,7 +42,7 @@ Set{ZZMPolyRingElem} with 3 elements: x3 ``` """ -function basisLieHighestWeight(type::String, rank::Int, heighest_weight::Vector{Int}; +function basisLieHighestWeight(type::String, rank::Int, highest_weight::Vector{Int}; operators::Union{String, Vector{Int}} = "regular", monomial_order::Union{String, Function} = "GRevLex", cache_size::Int = 0, parallel::Bool = false, return_no_minkowski::Bool = false, @@ -61,13 +61,13 @@ function basisLieHighestWeight(type::String, rank::Int, heighest_weight::Vector{ monomial_order_lt = get_monomial_order_lt(monomial_order, ZZx, x) # less than function to sort monomials by order # save computations from recursions - calc_heighest_weight = Dict{Vector{Int}, Set{ZZMPolyRingElem}}([0 for i in 1:rank] => Set([ZZx(1)])) + calc_highest_weight = Dict{Vector{Int}, Set{ZZMPolyRingElem}}([0 for i in 1:rank] => Set([ZZx(1)])) # we save all highest weights, for which the Minkowski-sum did not suffice to gain all monomials no_minkowski = Set{Vector{Int}}() - # start recursion over heighest_weight - monomial_basis = compute_monomials(type, rank, lie_algebra, ZZx, x, heighest_weight, operators, weights, - weights_eps, monomial_order_lt, calc_heighest_weight, cache_size, parallel, no_minkowski) + # start recursion over highest_weight + monomial_basis = compute_monomials(type, rank, lie_algebra, ZZx, x, highest_weight, operators, weights, + weights_eps, monomial_order_lt, calc_highest_weight, cache_size, parallel, no_minkowski) # output if return_no_minkowski && return_operators @@ -131,78 +131,78 @@ function get_operators(type::String, rank::Int, operators::Union{String, Vector{ end function compute_monomials(type::String, rank::Int, lie_algebra::GAP.Obj, ZZx::ZZMPolyRing, x::Vector{ZZMPolyRingElem}, - heighest_weight::Vector{Int}, operators::GAP.Obj, weights::Vector{Vector{Int64}}, + highest_weight::Vector{Int}, operators::GAP.Obj, weights::Vector{Vector{Int64}}, weights_eps::Vector{Vector{Int64}}, monomial_order_lt::Function, - calc_heighest_weight::Dict{Vector{Int64}, Set{ZZMPolyRingElem}}, cache_size::Int, + calc_highest_weight::Dict{Vector{Int64}, Set{ZZMPolyRingElem}}, cache_size::Int, parallel::Bool, no_minkowski::Set{Vector{Int}})::Set{ZZMPolyRingElem} """ - This function calculates the monomial basis M_{heighest_weight} recursively. The recursion saves all computed - results in calc_heighest_weight and we first check, if we already encountered this highest weight in a prior step. + This function calculates the monomial basis M_{highest_weight} recursively. The recursion saves all computed + results in calc_highest_weight and we first check, if we already encountered this highest weight in a prior step. If this is not the case, we need to perform computations. The recursion works by using the Minkowski-sum. - If M_{heighest_weight} is the desired set of monomials (identified by the exponents as lattice points), it is know - that for lambda_1 + lambda_2 = heighest_weight we have M_{lambda_1} + M_{lambda_2} subseteq M_{heighest_weight}. - The complexity grows exponentially in the size of heighest_weight. Therefore, it is very helpful to obtain a part of - M_{heighest_weight} by going through all partitions of heighest_weight and using the Minkowski-property. The base - cases of the recursion are the fundamental weights heighest_weight = [0, ..., 1, ..., 0]. In this case, or if the + If M_{highest_weight} is the desired set of monomials (identified by the exponents as lattice points), it is know + that for lambda_1 + lambda_2 = highest_weight we have M_{lambda_1} + M_{lambda_2} subseteq M_{highest_weight}. + The complexity grows exponentially in the size of highest_weight. Therefore, it is very helpful to obtain a part of + M_{highest_weight} by going through all partitions of highest_weight and using the Minkowski-property. The base + cases of the recursion are the fundamental weights highest_weight = [0, ..., 1, ..., 0]. In this case, or if the Minkowski-property did not find enough monomials, we need to perform the computations "by hand". """ # simple cases - # we already computed the heighest_weight result in a prior recursion step - if haskey(calc_heighest_weight, heighest_weight) - return calc_heighest_weight[heighest_weight] - elseif heighest_weight == [0 for i=1:rank] # we mathematically know the solution + # we already computed the highest_weight result in a prior recursion step + if haskey(calc_highest_weight, highest_weight) + return calc_highest_weight[highest_weight] + elseif highest_weight == [0 for i=1:rank] # we mathematically know the solution return Set(ZZx(1)) end # calculation required - # number of monomials that we need to find, i.e. |M_{heighest_weight}|. - # if heighest_weight is a fundamental weightype, ranko partition into smaller summands is possible. This is the + # number of monomials that we need to find, i.e. |M_{highest_weight}|. + # if highest_weight is a fundamental weightype, ranko partition into smaller summands is possible. This is the # basecase of the recursion. - gapDim = GAP.Globals.DimensionOfHighestWeightModule(lie_algebra, GAP.Obj(heighest_weight)) # fundamental weights - if is_fundamental(heighest_weight) || sum(abs.(heighest_weight)) == 0 - push!(no_minkowski, heighest_weight) - set_mon = add_by_hand(type, rank, lie_algebra, ZZx, x, heighest_weight, operators, weights, weights_eps, + gapDim = GAP.Globals.DimensionOfHighestWeightModule(lie_algebra, GAP.Obj(highest_weight)) # fundamental weights + if is_fundamental(highest_weight) || sum(abs.(highest_weight)) == 0 + push!(no_minkowski, highest_weight) + set_mon = add_by_hand(type, rank, lie_algebra, ZZx, x, highest_weight, operators, weights, weights_eps, monomial_order_lt, gapDim, Set{ZZMPolyRingElem}(), cache_size, parallel) - push!(calc_heighest_weight, heighest_weight => set_mon) + push!(calc_highest_weight, highest_weight => set_mon) return set_mon else # use Minkowski-Sum for recursion set_mon = Set{ZZMPolyRingElem}() i = 0 - sub_weights = compute_sub_weights(heighest_weight) + sub_weights = compute_sub_weights(highest_weight) l = length(sub_weights) - # go through all partitions lambda_1 + lambda_2 = heighest_weight until we have enough monomials or used all + # go through all partitions lambda_1 + lambda_2 = highest_weight until we have enough monomials or used all # partitions while length(set_mon) < gapDim && i < l i += 1 lambda_1 = sub_weights[i] - lambda_2 = heighest_weight .- lambda_1 + lambda_2 = highest_weight .- lambda_1 mon_lambda_1 = compute_monomials(type, rank, lie_algebra, ZZx, x, lambda_1, operators, weights, weights_eps, - monomial_order_lt, calc_heighest_weight, cache_size, parallel, + monomial_order_lt, calc_highest_weight, cache_size, parallel, no_minkowski) mon_lambda_2 = compute_monomials(type, rank, lie_algebra, ZZx, x, lambda_2, operators, weights, weights_eps, - monomial_order_lt, calc_heighest_weight, cache_size, parallel, + monomial_order_lt, calc_highest_weight, cache_size, parallel, no_minkowski) - # Minkowski-sum: M_{lambda_1} + M_{lambda_2} subseteq M_{heighest_weight}, if monomials get identified with + # Minkowski-sum: M_{lambda_1} + M_{lambda_2} subseteq M_{highest_weight}, if monomials get identified with # points in ZZ^n mon_sum = Set([p*q for p in mon_lambda_1 for q in mon_lambda_2]) union!(set_mon, mon_sum) end # check if we found enough monomials if length(set_mon) < gapDim - push!(no_minkowski, heighest_weight) - set_mon = add_by_hand(type, rank, lie_algebra, ZZx, x, heighest_weight, operators, weights, weights_eps, + push!(no_minkowski, highest_weight) + set_mon = add_by_hand(type, rank, lie_algebra, ZZx, x, highest_weight, operators, weights, weights_eps, monomial_order_lt, gapDim, set_mon, cache_size, parallel) end - push!(calc_heighest_weight, heighest_weight => set_mon) + push!(calc_highest_weight, highest_weight => set_mon) return set_mon end end @doc Markdown.doc""" - is_fundamental(heighest_weight::Vector{Int})::Bool + is_fundamental(highest_weight::Vector{Int})::Bool - returns true if ``heighest_weight`` is fundamental, i.e. [0, ..., 1, ..., 0] + returns true if ``highest_weight`` is fundamental, i.e. [0, ..., 1, ..., 0] # Examples ```jldoctest @@ -213,9 +213,9 @@ julia> BasisLieHighestWeight.is_fundamental([0, 1, 1]) false ``` """ -function is_fundamental(heighest_weight::Vector{Int})::Bool +function is_fundamental(highest_weight::Vector{Int})::Bool one = false - for i in heighest_weight + for i in highest_weight if i > 0 if one || i > 1 return false @@ -227,62 +227,57 @@ function is_fundamental(heighest_weight::Vector{Int})::Bool return false end -function order_sub_weights(heighest_weight::Vector{Int}, sub_weights::Vector{Any})::Vector{Vector{Int}} +function compute_sub_weights(highest_weight::Vector{Int})::Vector{Vector{Int}} """ - sort weights incrasing by their 2-norm - """ - sort!(sub_weights, by=x->sum((x).^2)) -end - -function compute_sub_weights(heighest_weight::Vector{Int})::Vector{Vector{Int}} - """ - returns list of weights w != 0 with 0 <= w <= heighest_weight elementwise + returns list of weights w != 0 with 0 <= w <= highest_weight elementwise """ sub_weights = [] - foreach(Iterators.product((0:x for x in heighest_weight)...)) do i + foreach(Iterators.product((0:x for x in highest_weight)...)) do i push!(sub_weights, [i...]) end popfirst!(sub_weights) # [0, ..., 0] - pop!(sub_weights) # heighest_weight - order_sub_weights(heighest_weight, sub_weights) + pop!(sub_weights) # highest_weight + sort!(sub_weights, by=x->sum((x).^2)) return sub_weights end -function add_known_monomials!(weightspace::Vector{Any}, set_mon_in_weightspace::Dict{Vector{Int64}, +function add_known_monomials!(weight::Vector{Int}, set_mon_in_weightspace::Dict{Vector{Int64}, Set{ZZMPolyRingElem}}, number_of_operators::Int, weights::Vector{Vector{Int64}}, matrices_of_operators::Vector{SMat{ZZRingElem}}, calc_monomials::Dict{ZZMPolyRingElem, - Tuple{TVec, Vector{Int}}}, + Tuple{TVec, Vector{Int}}}, x::Vector{ZZMPolyRingElem}, space::Dict{Vector{Int64}, Oscar.BasisLieHighestWeight.VSBasis}, e::Vector{Vector{Int}}, - cache_size::Int) + v0::SRow{ZZRingElem}, cache_size::Int) """ By using the Minkowski-sum, we know that all monomials in set_mon_in_weightspace are in our basis. Since we want to extend the weightspacse with missing monomials, we go need to calculate and add the vector of each monomial to our basis. """ - weight = weightspace[1] for mon in set_mon_in_weightspace[weight] - #vec, wt = calc_new_mon!(mon, number_of_operators, weights, matrices_of_operators, calc_monomials, space, e, - # cache_size) - d = sz(matrices_of_operators[1]) - v0 = sparse_row(ZZ, [(1,1)]) # starting vector v - vec = calc_vec(v0, mon, matrices_of_operators) - wt = calc_weight(mon, weights) - #println("vec:" , vec) - #println("wt: ", wt) - if !haskey(space, wt) - space[wt] = nullSpace() + # calculate the vector vec associated with mon + if cache_size == 0 + d = sz(matrices_of_operators[1]) + vec = calc_vec(v0, mon, matrices_of_operators) + else + vec = calc_new_mon!(x , mon, weights, matrices_of_operators, number_of_operators, calc_monomials, space, e, + cache_size) end - add_and_reduce!(space[wt], vec) + + # check if vec extends the basis + if !haskey(space, weight) + space[weight] = nullSpace() + end + add_and_reduce!(space[weight], vec) end end function add_new_monomials!(type::String, rank::Int, ZZx::ZZMPolyRing, x::Vector{ZZMPolyRingElem}, - matrices_of_operators::Vector{SMat{ZZRingElem}}, weights::Vector{Vector{Int}}, - monomial_order_lt::Function, weightspace::Vector{Any}, weights_eps::Vector{Vector{Int}}, + matrices_of_operators::Vector{SMat{ZZRingElem}}, number_of_operators::Int, + weights::Vector{Vector{Int}}, monomial_order_lt::Function, weight::Vector{Int}, + dim_weightspace::Int, weights_eps::Vector{Vector{Int}}, set_mon_in_weightspace::Dict{Vector{Int64}, Set{ZZMPolyRingElem}}, calc_monomials::Dict{ZZMPolyRingElem, Tuple{TVec, Vector{Int}}}, space::Dict{Vector{Int64}, - Oscar.BasisLieHighestWeight.VSBasis}, e::Vector{Vector{Int}}, cache_size::Int, - set_mon::Set{ZZMPolyRingElem}) + Oscar.BasisLieHighestWeight.VSBasis}, e::Vector{Vector{Int}}, v0::SRow{ZZRingElem}, + cache_size::Int, set_mon::Set{ZZMPolyRingElem}) """ If a weightspace is missing monomials, we need to calculate them by trial and error. We would like to go through all monomials in the order monomial_order_lt and calculate the corresponding vector. If it extends the basis, we add it @@ -290,8 +285,6 @@ function add_new_monomials!(type::String, rank::Int, ZZx::ZZMPolyRing, x::Vector Therefore, we only inspect the monomials that lie both in the weyl-polytope and the weightspace. Since the weyl- polytope is bounded these are finitely many, we can sort them and then go trough them, until we found enough. """ - weight = weightspace[1] - dim_weightspace = weightspace[2] # get monomials from weyl-polytope that are in the weightspace poss_mon_in_weightspace = convert_lattice_points_to_monomials(ZZx, @@ -313,12 +306,17 @@ function add_new_monomials!(type::String, rank::Int, ZZx::ZZMPolyRing, x::Vector continue end - # calculate the vector and check if it extends the basis - #vec, _ = calc_new_mon!(mon, m, weights, matrices_of_operators, calc_monomials, space, e, cache_size) - d = sz(matrices_of_operators[1]) - v0 = sparse_row(ZZ, [(1,1)]) # starting vector v - vec = calc_vec(v0, mon, matrices_of_operators) + # calculate the vector vec associated with mon + if cache_size == 0 + d = sz(matrices_of_operators[1]) + vec = calc_vec(v0, mon, matrices_of_operators) + else + vec = calc_new_mon!(x , mon, weights, matrices_of_operators, number_of_operators, calc_monomials, space, e, + cache_size) + end #println("vec:" , vec) + + # check if vec extends the basis if !haskey(space, weight) space[weight] = nullSpace() end @@ -335,16 +333,17 @@ end function add_by_hand(type::String, rank::Int, lie_algebra::GAP.Obj, ZZx::ZZMPolyRing, x::Vector{ZZMPolyRingElem}, - heighest_weight::Vector{Int}, operators::GAP.Obj, weights::Vector{Vector{Int64}}, + highest_weight::Vector{Int}, operators::GAP.Obj, weights::Vector{Vector{Int64}}, weights_eps::Vector{Vector{Int64}}, monomial_order_lt::Function, gapDim::Int, set_mon::Set{ZZMPolyRingElem}, cache_size::Int, parallel::Bool)::Set{ZZMPolyRingElem} """ This function calculates the missing monomials by going through each non full weightspace and adding possible monomials manually by computing their corresponding vectors and checking if they enlargen the basis. """ + #println("add_by_hand: ", highest_weight) # initialization # matrices g_i for (g_1^a_1 * ... * g_k^a_k)*v - matrices_of_operators = tensorMatricesForOperators(lie_algebra, heighest_weight, operators) + matrices_of_operators = tensorMatricesForOperators(lie_algebra, highest_weight, operators) number_of_operators = length(matrices_of_operators) e = [1*(1:number_of_operators .== i) for i in 1:number_of_operators] # e_i space = Dict(0*weights[1] => nullSpace()) # span of basis vectors to keep track of the basis @@ -353,7 +352,7 @@ function add_by_hand(type::String, rank::Int, lie_algebra::GAP.Obj, ZZx::ZZMPoly calc_monomials = Dict{ZZMPolyRingElem, Tuple{TVec, Vector{Int}}}(ZZx(1) => (v0, 0 * weights[1])) push!(set_mon, ZZx(1)) # required monomials of each weightspace - weightspaces = get_dim_weightspace(type, rank, lie_algebra, heighest_weight) + weightspaces = get_dim_weightspace(type, rank, lie_algebra, highest_weight) # sort the monomials from the minkowski-sum by their weightspaces set_mon_in_weightspace = Dict{Vector{Int}, Set{ZZMPolyRingElem}}() @@ -366,51 +365,56 @@ function add_by_hand(type::String, rank::Int, lie_algebra::GAP.Obj, ZZx::ZZMPoly end # only inspect weightspaces with missing monomials - full_weightspaces = zeros(Bool, length(weightspaces)) - for i=1:length(weightspaces) - full_weightspaces[i] = (length(set_mon_in_weightspace[weightspaces[i][1]]) == weightspaces[i][2]) + weights_with_full_weightspace = Set{Vector{Int}}() + for (weight, dim_weightspace) in weightspaces + #full_weightspaces[i] = (length(set_mon_in_weightspace[weightspaces[i][1]]) == weightspaces[i][2]) + if (length(set_mon_in_weightspace[weight]) == dim_weightspace) + push!(weights_with_full_weightspace, weight) + end end - deleteat!(weightspaces, full_weightspaces) - weightsapces = full_weightspaces + delete!(weightspaces, weights_with_full_weightspace) # use parallel computations if parallel=true. The weightspaces could be calculated completely indepent. This is not # implemented, since I used the package Distributed.jl for this, which is not in the Oscar dependencies. But I plan - # to reimplement this. insert known monomials into basis - for weightspace in weightspaces - add_known_monomials!(weightspace, set_mon_in_weightspace, number_of_operators, weights, matrices_of_operators, - calc_monomials, space, e, cache_size) + # to reimplement this. + # insert known monomials into basis + for (weight, _) in weightspaces + add_known_monomials!(weight, set_mon_in_weightspace, number_of_operators, weights, matrices_of_operators, + calc_monomials, x, space, e, v0, cache_size) end # calculate new monomials - for weightspace in weightspaces - add_new_monomials!(type, rank, ZZx, x, matrices_of_operators, weights, monomial_order_lt, weightspace, - weights_eps, set_mon_in_weightspace, calc_monomials, space, e, cache_size, set_mon) + for (weight, dim_weightspace) in weightspaces + add_new_monomials!(type, rank, ZZx, x, matrices_of_operators, number_of_operators, weights, monomial_order_lt, + weight, dim_weightspace, weights_eps, set_mon_in_weightspace, calc_monomials, space, e, v0, + cache_size, set_mon) end return set_mon end -function get_dim_weightspace(type::String, rank::Int, lie_algebra::GAP.Obj, heighest_weight::Vector{Int})::Vector{Any} +function get_dim_weightspace(type::String, rank::Int, lie_algebra::GAP.Obj, + highest_weight::Vector{Int})::Dict{Vector{Int}, Int} """ - calculates matrix, first row weights, second row dimension of corresponding weightspace - GAP computes the dimension for all positive weights. The dimension is constant on orbits of the weylgroup, - and we can therefore calculate the dimension of each weightspace. + Calculates dictionary with weights as keys and dimension of corresponding weightspace as value. GAP computes the + dimension for all positive weights. The dimension is constant on orbits of the weylgroup, and we can therefore + calculate the dimension of each weightspace. """ # calculate dimension for dominant weights with GAP root_system = GAP.Globals.RootSystem(lie_algebra) dominant_weights, dominant_weights_dim = fromGap(GAP.Globals.DominantCharacter(root_system, - GAP.Obj(heighest_weight))) + GAP.Obj(highest_weight))) dominant_weights = convert(Vector{Vector{Int}}, dominant_weights) - dim_weightspace = [] + weightspaces = Dict{Vector{Int}, Int}() # calculate dimension for the rest by checking which positive weights lies in the orbit. for i in 1:length(dominant_weights) orbit_weights = orbit_weylgroup(type, rank, lie_algebra, dominant_weights[i]) - dim = dominant_weights_dim[i] + dim_weightspace = dominant_weights_dim[i] for weight in orbit_weights - append!(dim_weightspace, [[heighest_weight - weight, dim]]) + weightspaces[highest_weight - weight] = dim_weightspace end end - return dim_weightspace + return weightspaces end end diff --git a/experimental/BasisLieHighestWeight/src/LieAlgebras.jl b/experimental/BasisLieHighestWeight/src/LieAlgebras.jl index 57aa9bf87517..173903a2138e 100644 --- a/experimental/BasisLieHighestWeight/src/LieAlgebras.jl +++ b/experimental/BasisLieHighestWeight/src/LieAlgebras.jl @@ -22,12 +22,12 @@ function multiply_scalar(A::SMat{T}, d) where T return A end -function matricesForOperators(lie_algebra::GAP.Obj, heighest_weight::Vector{Int}, +function matricesForOperators(lie_algebra::GAP.Obj, highest_weight::Vector{Int}, ops::GAP.Obj)::Vector{SMat{ZZRingElem}} """ used to create tensorMatricesForOperators """ - M = Oscar.GAP.Globals.HighestWeightModule(lie_algebra, Oscar.GAP.julia_to_gap(heighest_weight)) + M = Oscar.GAP.Globals.HighestWeightModule(lie_algebra, Oscar.GAP.julia_to_gap(highest_weight)) matrices_of_operators = Oscar.GAP.Globals.List(ops, o -> Oscar.GAP.Globals.MatrixOfAction(GAP.Globals.Basis(M), o)) matrices_of_operators = gapReshape.( Oscar.GAP.gap_to_julia(matrices_of_operators)) denominators = map(y->denominator(y[2]), union(union(matrices_of_operators...)...)) diff --git a/experimental/BasisLieHighestWeight/src/MonomialOrder.jl b/experimental/BasisLieHighestWeight/src/MonomialOrder.jl index 617764e72387..1395ec72ab29 100644 --- a/experimental/BasisLieHighestWeight/src/MonomialOrder.jl +++ b/experimental/BasisLieHighestWeight/src/MonomialOrder.jl @@ -1,20 +1,20 @@ # manages methods for different orders of monomials function get_monomial_order_lt(monomial_order::Union{String, Function}, ZZx::ZZMPolyRing, - x::Vector{ZZMPolyRingElem})::Function -""" -Returns the desired monomial_order function -""" -#if isa(monomial_order, Function) -# return monomial_order -if monomial_order == "GRevLex" -choosen_monomial_order = degrevlex(x) -elseif monomial_order == "RevLex" -choosen_monomial_order = revlex(x) -elseif monomial_order == "Lex" -choosen_monomial_order = lex(x) -else -println("no suitable order picked") -end -return (mon1, mon2) -> (cmp(choosen_monomial_order, mon1, mon2) == -1) + x::Vector{ZZMPolyRingElem})::Function + """ + Returns the desired monomial_order function + """ + #if isa(monomial_order, Function) + # return monomial_order == + if monomial_order == "GRevLex" + choosen_monomial_order = degrevlex(x) + elseif monomial_order == "RevLex" + choosen_monomial_order = revlex(x) + elseif monomial_order == "Lex" + choosen_monomial_order = lex(x) + else + println("no suitable order picked") + end + return (mon1, mon2) -> (cmp(choosen_monomial_order, mon1, mon2) == -1) end diff --git a/experimental/BasisLieHighestWeight/src/NewMonomial.jl b/experimental/BasisLieHighestWeight/src/NewMonomial.jl index f0e8e17f7be8..d13c4937188e 100644 --- a/experimental/BasisLieHighestWeight/src/NewMonomial.jl +++ b/experimental/BasisLieHighestWeight/src/NewMonomial.jl @@ -19,7 +19,8 @@ function calc_weight(mon::ZZMPolyRingElem, weights::Vector{Vector{Int}})::Vector return weight end -function calc_vec(v0::SRow{ZZRingElem}, mon::ZZMPolyRingElem, mats)::SRow{ZZRingElem} +function calc_vec(v0::SRow{ZZRingElem}, mon::ZZMPolyRingElem, + matrices_of_operators::Vector{SMat{ZZRingElem}})::SRow{ZZRingElem} """ calculates vector associated with monomial mon """ @@ -27,85 +28,74 @@ function calc_vec(v0::SRow{ZZRingElem}, mon::ZZMPolyRingElem, mats)::SRow{ZZRing degree_mon = degrees(mon) for i in length(degree_mon):-1:1 for j in 1:degree_mon[i] - vec = mul(vec, transpose(mats[i])) + vec = mul(vec, transpose(matrices_of_operators[i])) end end return vec end -function highest_calc_sub_monomial(mon::ZZMPolyRingElem, - calc_monomials::Dict{ZZMPolyRingElem, Tuple{TVec, Vector{Int}}})::ZZMPolyRingElem +function highest_calc_sub_monomial(x::Vector{ZZMPolyRingElem}, mon::ZZMPolyRingElem, + calc_monomials::Dict{ZZMPolyRingElem, Tuple{TVec, Vector{Int}}}, + number_of_operators::Int)::ZZMPolyRingElem """ returns the key in calc_monomials that can be extended by the least amount of left-operations to mon """ sub_mon = copy(mon) - m = length(mon) - for i in 1:m - while sub_mon[i] > 0 + for i in 1:number_of_operators + while is_divisible_by(sub_mon, x[i]) if haskey(calc_monomials, sub_mon) return sub_mon else - sub_mon[i] -= 1 + sub_mon /= x[i] end end end return sub_mon end -function calc_new_mon!(mon::ZZMPolyRingElem, number_of_operators::Int, weights::Vector{Int}, - matrices_of_operators::Vector{SMat{ZZRingElem}}, +function calc_new_mon!(x::Vector{ZZMPolyRingElem}, mon::ZZMPolyRingElem, weights::Vector{Vector{Int}}, + matrices_of_operators::Vector{SMat{ZZRingElem}}, number_of_operators::Int, calc_monomials::Dict{ZZMPolyRingElem, Tuple{TVec, Vector{Int}}}, space::Dict{Vector{Int64}, Oscar.BasisLieHighestWeight.VSBasis}, e::Vector{Vector{Int}}, - cache_size::Int)::Tuple{SRow{ZZRingElem}, Vector{Int}} + cache_size::Int)::SRow{ZZRingElem} # calculate vector of mon by extending a previous calculated vector to a # monom that differs only by left-multiplication, save results in calc_monomials - sub_mon = highest_calc_sub_monomial(mon, calc_monomials) + sub_mon = highest_calc_sub_monomial(x, mon, calc_monomials, number_of_operators) #println("sub_mon: ", sub_mon) sub_mon_cur = copy(sub_mon) (vec, weight) = calc_monomials[sub_mon] for i in number_of_operators:-1:1 - for k in sub_mon[i]:(mon[i]-1) - sub_mon_cur += e[i] + for k in degrees(sub_mon)[i]:(degrees(mon)[i]-1) + sub_mon_cur *= x[i] weight += weights[i] if !haskey(space, weight) space[weight] = nullSpace() end - #if isempty(vec.nzind) # v already 0 - # needs_to_be_saved = false - #else - # vec = mats[i] * vec - #end - #vec = add_and_reduce!(space[weight], vec) - #println(sub_mon_cur) - #if needs_to_be_saved - # calc_monomials[sub_mon_cur] = (vec, weight) - #end - #mul!(A, vec) - vec = matrices_of_operators[i] * vec + + vec = mul(vec, transpose(matrices_of_operators[i])) if length(calc_monomials) < cache_size calc_monomials[sub_mon_cur] = (vec, weight) end # check if the extended monomial can be deleted from calculated_monomials, i.e. the other possible - # extensions are already contained + # extensions by left multiplication with some x[i] are already contained can_be_deleted = true k = number_of_operators for l in 1:number_of_operators - if (sub_mon_cur - e[i])[l] != 0 + if degrees(sub_mon_cur - x[i])[l] != 0 k = l end end for l in 1:k - can_be_deleted = can_be_deleted && haskey(calc_monomials, sub_mon_cur-e[i]+e[l]) + can_be_deleted = can_be_deleted && haskey(calc_monomials, sub_mon_cur - x[i] + x[l]) end - if can_be_deleted && sub_mon_cur != e[i] - delete!(calc_monomials, sub_mon_cur-e[i]) + if can_be_deleted && sub_mon_cur != x[i] + delete!(calc_monomials, sub_mon_cur - x[i]) end end end - # calc_monomials[sub_mon_cur] = (vec, weight) this position is for graded_reverse_lexicographic enough instead of - # the one above - return vec, weight + #println(length(calc_monomials)) + return vec end diff --git a/experimental/BasisLieHighestWeight/src/TensorModels.jl b/experimental/BasisLieHighestWeight/src/TensorModels.jl index 9254ba40e191..0b56cc2635f9 100644 --- a/experimental/BasisLieHighestWeight/src/TensorModels.jl +++ b/experimental/BasisLieHighestWeight/src/TensorModels.jl @@ -38,19 +38,19 @@ tensorProducts(As, Bs) = (AB->tensorProduct(AB[1], AB[2])).(zip(As, Bs)) tensorPower(A, n) = (n == 1) ? A : tensorProduct(tensorPower(A, n-1), A) tensorPowers(As, n) = (A->tensorPower(A, n)).(As) -function tensorMatricesForOperators(lie_algebra::GAP.Obj, heighest_weight::Vector{Int}, +function tensorMatricesForOperators(lie_algebra::GAP.Obj, highest_weight::Vector{Int}, operators::GAP.Obj)::Vector{SMat{ZZRingElem}} """ Calculates the matrices g_i corresponding to the operator ops[i]. """ matrices_of_operators = [] - for i in 1:length(heighest_weight) - if heighest_weight[i] <= 0 + for i in 1:length(highest_weight) + if highest_weight[i] <= 0 continue end - wi = Int.(1:length(heighest_weight) .== i) # i-th fundamental weight + wi = Int.(1:length(highest_weight) .== i) # i-th fundamental weight _matrices_of_operators = matricesForOperators(lie_algebra, wi, operators) - _matrices_of_operators = tensorPowers(_matrices_of_operators, heighest_weight[i]) + _matrices_of_operators = tensorPowers(_matrices_of_operators, highest_weight[i]) matrices_of_operators = matrices_of_operators == [] ? _matrices_of_operators : tensorProducts(matrices_of_operators, _matrices_of_operators) end diff --git a/experimental/BasisLieHighestWeight/src/WeylPolytope.jl b/experimental/BasisLieHighestWeight/src/WeylPolytope.jl index bac5bf1832f6..d830702b0228 100644 --- a/experimental/BasisLieHighestWeight/src/WeylPolytope.jl +++ b/experimental/BasisLieHighestWeight/src/WeylPolytope.jl @@ -6,12 +6,12 @@ include("./RootConversion.jl") fromGap = Oscar.GAP.gap_to_julia function weylpolytope(type::String, rank::Int, lie_algebra::GAP.Obj, - heighest_weight::Vector{Int})::Polymake.BigObjectAllocated + highest_weight::Vector{Int})::Polymake.BigObjectAllocated """ returns weyl-polytope in homogeneous coordinates, i.e. convex hull of orbit of weyl-group of - type type and rank rank on highest weight vector heighest_weight + type type and rank rank on highest weight vector highest_weight """ - vertices = orbit_weylgroup(type, rank, lie_algebra, heighest_weight) + vertices = orbit_weylgroup(type, rank, lie_algebra, highest_weight) vertices = transpose(hcat(vertices ...)) vertices = [w for w in eachrow(vertices)] vertices = transpose(hcat(vertices ...)) @@ -60,7 +60,7 @@ end function get_lattice_points_of_weightspace(weights, weight, type) """ - calculates all lattice points in a given weightspace for lie algebras of type type + calculates all lattice points in a given weightspace for a lie algebra of type type input: weights: the operator weights in eps_i weight: lambda - mu From 16e78976e832aa666420e139e7a6269db14bfb84 Mon Sep 17 00:00:00 2001 From: BenWilop Date: Wed, 12 Apr 2023 22:16:41 +0200 Subject: [PATCH 16/19] few more small changes to types / names and typos --- .../src/BasisLieHighestWeight.jl | 115 +++++++++++++----- .../BasisLieHighestWeight/src/LieAlgebras.jl | 6 +- .../src/MonomialOrder.jl | 6 +- .../BasisLieHighestWeight/src/NewMonomial.jl | 12 +- .../src/VectorSpaceBases.jl | 11 +- .../BasisLieHighestWeight/test/MBOld.jl | 5 +- .../BasisLieHighestWeight/test/runtests.jl | 16 +-- 7 files changed, 113 insertions(+), 58 deletions(-) diff --git a/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl b/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl index 73d06e1aa7ae..babfb0260ef1 100644 --- a/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl +++ b/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl @@ -1,5 +1,5 @@ module BasisLieHighestWeight -export basisLieHighestWeight +export basis_lie_highest_weight export is_fundamental using Polymake @@ -24,9 +24,11 @@ Computes a monomial basis for the highest weight module with highest weight # Parameters - `type`: type of liealgebra we want to investigate, one of "A", "B", "C", "D", "E", "F", "G" - `rank`: rank of liealgebra -- `operators`: currently not implemented, because we used https://github.com/jmichel7/Gapjm.jl to work with coxeter - groups and get left descending elements -- `monomial_order`: highest weight +- `highest_weight`: highest-weight +- `operators`: list of operators, either "regular" or integer array. The functionality of choosing a random longest word + is currently not implemented, because we used https://github.com/jmichel7/Gapjm.jl to work with coxeter + groups need a method to obtain all non left descending elements to extend a word +- `monomial_order`: monomial order in which our basis gets defined with regards to our operators - `cache_size`: number of computed monomials we want to cache, default is 0 - `parallel`: currently not implemented, because we used Distributed.jl, but if true parts of the algorithms can be parallelized @@ -35,28 +37,82 @@ Computes a monomial basis for the highest weight module with highest weight # Examples ```jldoctest -julia> BasisLieHighestWeight.basisLieHighestWeight("A", 2, [1,0]) +julia> BasisLieHighestWeight.basis_lie_highest_weight("A", 2, [1, 1], return_no_minkowski = true, return_operators = true) +(Set(ZZMPolyRingElem[x1*x2, x2, 1, x1*x3, x3^2, x1, x3, x2*x3]), Set([[1, 0], [0, 1]]), GAP: [ v.1, v.2, v.3 ]) + + +julia> BasisLieHighestWeight.basis_lie_highest_weight("A", 3, [2, 2, 3], monomial_order = "Lex") +Set{ZZMPolyRingElem} with 1260 elements: + x3*x5^2*x6^2 + x2*x3*x5^2*x6 + x4^2*x5^2*x6 + x1^2*x3^3*x5 + x2*x3*x4*x5^3*x6^2 + x1*x3*x4*x5^3*x6^2 + x1^2*x3*x4*x6 + x1*x3*x4^3 + x4^2*x5^3*x6^4 + x1*x2*x3*x5^2 + x3^2*x4^4*x5^2*x6 + x2^2*x3*x6^2 + x1*x2^2*x3^2*x5 + x1*x3*x4*x5^2 + x1^2*x2*x6 + x1*x3^2*x4*x5*x6^3 + x1^2*x2*x4*x5^2*x6^2 + x4^4*x5 + x1^2*x2*x3^2*x6 + x1*x3^2*x5^2 + x2*x3*x4*x5^3 + ⋮ + +julia> BasisLieHighestWeight.basis_lie_highest_weight("A", 2, [1, 0], operators = [1,2,1]) Set{ZZMPolyRingElem} with 3 elements: 1 - x1 x3 + x2*x3 + +julia> BasisLieHighestWeight.basis_lie_highest_weight("C", 3, [1, 1, 1], monomial_order = "Lex") +Set{ZZMPolyRingElem} with 512 elements: + x1*x5*x6*x8 + x6^4 + x3*x4^2*x8 + x3*x4*x6*x7 + x8^3 + x3*x6^2 + x2*x3 + x5*x6^2*x9 + x6*x8^2*x9 + x1*x6*x7 + x5*x6*x9^2 + x6^2*x7^2*x8 + x5*x7*x8 + x4*x6^2*x7*x8^2 + x4^2*x5*x7 + x1*x5^2*x6 + x1*x6*x8 + x3*x4*x5 + x2*x4*x6^2*x7 + x4*x6*x7 + x1*x4*x7*x8^2 + ⋮ ``` """ -function basisLieHighestWeight(type::String, rank::Int, highest_weight::Vector{Int}; +function basis_lie_highest_weight(type::String, rank::Int, highest_weight::Vector{Int}; operators::Union{String, Vector{Int}} = "regular", monomial_order::Union{String, Function} = "GRevLex", cache_size::Int = 0, parallel::Bool = false, return_no_minkowski::Bool = false, return_operators::Bool = false) - # The function precomputes objects that are independent of the highest weight and can be used in all recursion + # The function precomputes objects that are independent of the highest weight and that can be used in all recursion # steps. Then it starts the recursion and returns the result. # initialization of objects that can be precomputed - lie_algebra, chevalley_basis = lieAlgebra(type, rank) # lie_algebra of type, rank and its chevalley_basis + lie_algebra, chevalley_basis = create_lie_lgebra(type, rank) # lie_algebra of type, rank and its chevalley_basis # operators that are represented by our monomials. x_i is connected to operators[i] operators = get_operators(type, rank, operators, lie_algebra, chevalley_basis) - weights = weightsForOperators(lie_algebra, chevalley_basis[3], operators) # weights of the operators + weights = weights_for_operators(lie_algebra, chevalley_basis[3], operators) # weights of the operators weights = (weight->Int.(weight)).(weights) - weights_eps = [w_to_eps(type, rank, w) for w in weights] + weights_eps = [w_to_eps(type, rank, w) for w in weights] # other root system ZZx, x = PolynomialRing(ZZ, length(operators)) # for our monomials monomial_order_lt = get_monomial_order_lt(monomial_order, ZZx, x) # less than function to sort monomials by order @@ -96,7 +152,7 @@ function get_operators(type::String, rank::Int, operators::Union{String, Vector{ """ handles user input for operators "regular" for all operators - "longest-word" for random longest-word in Weyl-group + "longest-word" for random longest-word in Weyl-group (currently not implemented) operators::Vector{Int} for explicit longest-word """ # create standard operators @@ -150,19 +206,19 @@ function compute_monomials(type::String, rank::Int, lie_algebra::GAP.Obj, ZZx::Z # we already computed the highest_weight result in a prior recursion step if haskey(calc_highest_weight, highest_weight) return calc_highest_weight[highest_weight] - elseif highest_weight == [0 for i=1:rank] # we mathematically know the solution + elseif highest_weight == [0 for i in 1:rank] # we mathematically know the solution return Set(ZZx(1)) end # calculation required - # number of monomials that we need to find, i.e. |M_{highest_weight}|. - # if highest_weight is a fundamental weightype, ranko partition into smaller summands is possible. This is the - # basecase of the recursion. - gapDim = GAP.Globals.DimensionOfHighestWeightModule(lie_algebra, GAP.Obj(highest_weight)) # fundamental weights + # gap_dim is number of monomials that we need to find, i.e. |M_{highest_weight}|. + # if highest_weight is a fundamental weight, partition into smaller summands is possible. This is the basecase of + # the recursion. + gap_dim = GAP.Globals.DimensionOfHighestWeightModule(lie_algebra, GAP.Obj(highest_weight)) # fundamental weights if is_fundamental(highest_weight) || sum(abs.(highest_weight)) == 0 push!(no_minkowski, highest_weight) set_mon = add_by_hand(type, rank, lie_algebra, ZZx, x, highest_weight, operators, weights, weights_eps, - monomial_order_lt, gapDim, Set{ZZMPolyRingElem}(), cache_size, parallel) + monomial_order_lt, gap_dim, Set{ZZMPolyRingElem}(), cache_size, parallel) push!(calc_highest_weight, highest_weight => set_mon) return set_mon else @@ -173,7 +229,7 @@ function compute_monomials(type::String, rank::Int, lie_algebra::GAP.Obj, ZZx::Z l = length(sub_weights) # go through all partitions lambda_1 + lambda_2 = highest_weight until we have enough monomials or used all # partitions - while length(set_mon) < gapDim && i < l + while length(set_mon) < gap_dim && i < l i += 1 lambda_1 = sub_weights[i] lambda_2 = highest_weight .- lambda_1 @@ -183,16 +239,16 @@ function compute_monomials(type::String, rank::Int, lie_algebra::GAP.Obj, ZZx::Z mon_lambda_2 = compute_monomials(type, rank, lie_algebra, ZZx, x, lambda_2, operators, weights, weights_eps, monomial_order_lt, calc_highest_weight, cache_size, parallel, no_minkowski) - # Minkowski-sum: M_{lambda_1} + M_{lambda_2} subseteq M_{highest_weight}, if monomials get identified with + # Minkowski-sum: M_{lambda_1} + M_{lambda_2} \subseteq M_{highest_weight}, if monomials get identified with # points in ZZ^n mon_sum = Set([p*q for p in mon_lambda_1 for q in mon_lambda_2]) union!(set_mon, mon_sum) end # check if we found enough monomials - if length(set_mon) < gapDim + if length(set_mon) < gap_dim push!(no_minkowski, highest_weight) set_mon = add_by_hand(type, rank, lie_algebra, ZZx, x, highest_weight, operators, weights, weights_eps, - monomial_order_lt, gapDim, set_mon, cache_size, parallel) + monomial_order_lt, gap_dim, set_mon, cache_size, parallel) end push!(calc_highest_weight, highest_weight => set_mon) return set_mon @@ -249,7 +305,7 @@ function add_known_monomials!(weight::Vector{Int}, set_mon_in_weightspace::Dict{ v0::SRow{ZZRingElem}, cache_size::Int) """ By using the Minkowski-sum, we know that all monomials in set_mon_in_weightspace are in our basis. Since we want to - extend the weightspacse with missing monomials, we go need to calculate and add the vector of each monomial to our + extend the weightspace with missing monomials, we need to calculate and add the vector of each monomial to our basis. """ for mon in set_mon_in_weightspace[weight] @@ -283,10 +339,10 @@ function add_new_monomials!(type::String, rank::Int, ZZx::ZZMPolyRing, x::Vector monomials in the order monomial_order_lt and calculate the corresponding vector. If it extends the basis, we add it to the result and else we try the next one. We know, that all monomials that work lay in the weyl-polytope. Therefore, we only inspect the monomials that lie both in the weyl-polytope and the weightspace. Since the weyl- - polytope is bounded these are finitely many, we can sort them and then go trough them, until we found enough. + polytope is bounded these are finitely many and we can sort them and then go trough them, until we found enough. """ - # get monomials from weyl-polytope that are in the weightspace + # get monomials from weyl-polytope that are in the weightspace, sorted by monomial_order_lt poss_mon_in_weightspace = convert_lattice_points_to_monomials(ZZx, get_lattice_points_of_weightspace(weights_eps, w_to_eps(type, rank, weight), type)) poss_mon_in_weightspace = sort(poss_mon_in_weightspace, lt=monomial_order_lt) @@ -334,7 +390,7 @@ end function add_by_hand(type::String, rank::Int, lie_algebra::GAP.Obj, ZZx::ZZMPolyRing, x::Vector{ZZMPolyRingElem}, highest_weight::Vector{Int}, operators::GAP.Obj, weights::Vector{Vector{Int64}}, - weights_eps::Vector{Vector{Int64}}, monomial_order_lt::Function, gapDim::Int, + weights_eps::Vector{Vector{Int64}}, monomial_order_lt::Function, gap_dim::Int, set_mon::Set{ZZMPolyRingElem}, cache_size::Int, parallel::Bool)::Set{ZZMPolyRingElem} """ This function calculates the missing monomials by going through each non full weightspace and adding possible @@ -367,16 +423,15 @@ function add_by_hand(type::String, rank::Int, lie_algebra::GAP.Obj, ZZx::ZZMPoly # only inspect weightspaces with missing monomials weights_with_full_weightspace = Set{Vector{Int}}() for (weight, dim_weightspace) in weightspaces - #full_weightspaces[i] = (length(set_mon_in_weightspace[weightspaces[i][1]]) == weightspaces[i][2]) if (length(set_mon_in_weightspace[weight]) == dim_weightspace) push!(weights_with_full_weightspace, weight) end end delete!(weightspaces, weights_with_full_weightspace) - # use parallel computations if parallel=true. The weightspaces could be calculated completely indepent. This is not - # implemented, since I used the package Distributed.jl for this, which is not in the Oscar dependencies. But I plan - # to reimplement this. + # use parallel computations if parallel = true. The weightspaces could be calculated completely indepent (except for + # the caching). This is not implemented, since I used the package Distributed.jl for this, which is not in the + # Oscar dependencies. But I plan to reimplement this. # insert known monomials into basis for (weight, _) in weightspaces add_known_monomials!(weight, set_mon_in_weightspace, number_of_operators, weights, matrices_of_operators, diff --git a/experimental/BasisLieHighestWeight/src/LieAlgebras.jl b/experimental/BasisLieHighestWeight/src/LieAlgebras.jl index 173903a2138e..d5255631a525 100644 --- a/experimental/BasisLieHighestWeight/src/LieAlgebras.jl +++ b/experimental/BasisLieHighestWeight/src/LieAlgebras.jl @@ -3,9 +3,9 @@ using Oscar fromGap = Oscar.GAP.gap_to_julia -function lieAlgebra(type::String, rank::Int)::Tuple{GAP.Obj, GAP.Obj} +function create_lie_lgebra(type::String, rank::Int)::Tuple{GAP.Obj, GAP.Obj} """ - Creates the Lie-algebra as a GAP object that gets used for a lot other computations with GAP + Creates the Lie-algebra as a GAP object that gets used for a lot of other computations with GAP """ lie_algebra = GAP.Globals.SimpleLieAlgebra(GAP.Obj(type), rank, GAP.Globals.Rationals) return lie_algebra, GAP.Globals.ChevalleyBasis(lie_algebra) @@ -37,7 +37,7 @@ function matricesForOperators(lie_algebra::GAP.Obj, highest_weight::Vector{Int}, end -function weightsForOperators(lie_algebra::GAP.Obj, cartan::GAP.Obj, operators::GAP.Obj)::Vector{Vector{Int}} +function weights_for_operators(lie_algebra::GAP.Obj, cartan::GAP.Obj, operators::GAP.Obj)::Vector{Vector{Int}} """ Calculates the weight wts[i] for each operator ops[i] """ diff --git a/experimental/BasisLieHighestWeight/src/MonomialOrder.jl b/experimental/BasisLieHighestWeight/src/MonomialOrder.jl index 1395ec72ab29..5185fd8f3ebf 100644 --- a/experimental/BasisLieHighestWeight/src/MonomialOrder.jl +++ b/experimental/BasisLieHighestWeight/src/MonomialOrder.jl @@ -1,12 +1,10 @@ -# manages methods for different orders of monomials - function get_monomial_order_lt(monomial_order::Union{String, Function}, ZZx::ZZMPolyRing, x::Vector{ZZMPolyRingElem})::Function """ - Returns the desired monomial_order function + Returns the desired monomial_order function less than """ #if isa(monomial_order, Function) - # return monomial_order == + # choosen_monomial_order = monomial_order if monomial_order == "GRevLex" choosen_monomial_order = degrevlex(x) elseif monomial_order == "RevLex" diff --git a/experimental/BasisLieHighestWeight/src/NewMonomial.jl b/experimental/BasisLieHighestWeight/src/NewMonomial.jl index d13c4937188e..cba90354ce9f 100644 --- a/experimental/BasisLieHighestWeight/src/NewMonomial.jl +++ b/experimental/BasisLieHighestWeight/src/NewMonomial.jl @@ -14,21 +14,21 @@ function calc_weight(mon::ZZMPolyRingElem, weights::Vector{Vector{Int}})::Vector degree_mon = degrees(mon) weight = [0 for i in 1:length(weights[1])] for i in 1:length(degree_mon) - weight .+= degree_mon[i] * weights[i] + weight .+= degree_mon[i] * weights[i] end return weight end function calc_vec(v0::SRow{ZZRingElem}, mon::ZZMPolyRingElem, matrices_of_operators::Vector{SMat{ZZRingElem}})::SRow{ZZRingElem} - """ - calculates vector associated with monomial mon - """ + """ + calculates vector associated with monomial mon + """ vec = v0 degree_mon = degrees(mon) for i in length(degree_mon):-1:1 for j in 1:degree_mon[i] - vec = mul(vec, transpose(matrices_of_operators[i])) + vec = mul(vec, transpose(matrices_of_operators[i])) # currently there is no sparse matrix * vector mult end end return vec @@ -73,7 +73,7 @@ function calc_new_mon!(x::Vector{ZZMPolyRingElem}, mon::ZZMPolyRingElem, weights space[weight] = nullSpace() end - vec = mul(vec, transpose(matrices_of_operators[i])) + vec = mul(vec, transpose(matrices_of_operators[i])) # currently there is no sparse matrix * vector mult if length(calc_monomials) < cache_size calc_monomials[sub_mon_cur] = (vec, weight) end diff --git a/experimental/BasisLieHighestWeight/src/VectorSpaceBases.jl b/experimental/BasisLieHighestWeight/src/VectorSpaceBases.jl index ffad0770f944..f4cf0694a3a5 100644 --- a/experimental/BasisLieHighestWeight/src/VectorSpaceBases.jl +++ b/experimental/BasisLieHighestWeight/src/VectorSpaceBases.jl @@ -1,20 +1,19 @@ # manages the linear (in-)dependence of integer vectors -# this file is only of use to BasisLieHighestWeight for the basis vectors +# this file is only of use to basis_lie_highest_weight for the basis vectors using Oscar -TVec = SRow{ZZRingElem} # values ZZ, indices Int (TVec is datatype of basisvectors in basisLieHighestWeight) +TVec = SRow{ZZRingElem} # TVec is datatype of basisvectors in basisLieHighestWeight Short = UInt8 # for exponents of monomials; max. 255 struct VSBasis basis_vectors::Vector{TVec} # vector of basisvectors pivot::Vector{Int} # vector of pivotelements, i.e. pivot[i] is first nonzero element of basis_vectors[i] - dim::Vector{Int} # dimension end -nullSpace() = VSBasis([], [], []) # empty Vektorraum +nullSpace() = VSBasis([], []) # empty Vektorraum -reduceCol(a, b, i::Int) = (b[i]*a - a[i]*b)::TVec # create zero entry in a +reduce_col(a::TVec, b::TVec, i::Int) = (b[i]*a - a[i]*b)::TVec # create zero entry in a function normalize(v::TVec)::Tuple{TVec, Int64} """ @@ -52,7 +51,7 @@ function add_and_reduce!(sp::VSBasis, v::TVec)::TVec if i != newPivot continue end - v = reduceCol(v, basis_vectors[j], i) + v = reduce_col(v, basis_vectors[j], i) v, newPivot = normalize(v) if newPivot == 0 #return 0 diff --git a/experimental/BasisLieHighestWeight/test/MBOld.jl b/experimental/BasisLieHighestWeight/test/MBOld.jl index 061396036875..687aa79ef7cf 100644 --- a/experimental/BasisLieHighestWeight/test/MBOld.jl +++ b/experimental/BasisLieHighestWeight/test/MBOld.jl @@ -1,4 +1,7 @@ - + # This file is an old version of the algorithm that can compute (not all cases) of + # BasisLieHighestWeight.basis_lie_highest_weight and is used in runtests.jl to check that the newer algorithm matches + # There is code doubling, but I am not sure how the src part is going to change when its integrated with the other + # lie algebra work. module MBOld diff --git a/experimental/BasisLieHighestWeight/test/runtests.jl b/experimental/BasisLieHighestWeight/test/runtests.jl index d8cf23f20775..2c1b167a535e 100644 --- a/experimental/BasisLieHighestWeight/test/runtests.jl +++ b/experimental/BasisLieHighestWeight/test/runtests.jl @@ -21,28 +21,28 @@ function compare_algorithms(dynkin::Char, n::Int64, lambda::Vector{Int64}) mons_old = MBOld.basisLieHighestWeight(string(dynkin), n, lambda) # basic algorithm # new algorithm - mons_new = BasisLieHighestWeight.basisLieHighestWeight(string(dynkin), n, lambda) + mons_new = BasisLieHighestWeight.basis_lie_highest_weight(string(dynkin), n, lambda) L = G.SimpleLieAlgebra(forGap(string(dynkin)), n, G.Rationals) - gapDim = G.DimensionOfHighestWeightModule(L, forGap(lambda)) # dimension + gap_dim = G.DimensionOfHighestWeightModule(L, forGap(lambda)) # dimension # comparison # convert set of monomials over different ring objects to string representation to compare for equality @test issetequal(string.(mons_old), string.(mons_new)) # compare if result of old and new algorithm match - @test gapDim == length(mons_new) # check if dimension is correct + @test gap_dim == length(mons_new) # check if dimension is correct end function check_dimension(dynkin::Char, n::Int64, lambda::Vector{Int64}, monomial_order::String) - w = BasisLieHighestWeight.basisLieHighestWeight(string(dynkin), n, lambda, monomial_order=monomial_order) + w = BasisLieHighestWeight.basis_lie_highest_weight(string(dynkin), n, lambda, monomial_order=monomial_order) L = G.SimpleLieAlgebra(forGap(string(dynkin)), n, G.Rationals) - gapDim = G.DimensionOfHighestWeightModule(L, forGap(lambda)) # dimension - @test gapDim == length(w) # check if dimension is correct + gap_dim = G.DimensionOfHighestWeightModule(L, forGap(lambda)) # dimension + @test gap_dim == length(w) # check if dimension is correct end @testset "Test basisLieHighestWeight" begin @testset "Known examples" begin - mons = BasisLieHighestWeight.basisLieHighestWeight("A", 2, [1,0]) + mons = BasisLieHighestWeight.basis_lie_highest_weight("A", 2, [1,0]) @test issetequal(string.(mons), Set(["1", "x3", "x1"])) - mons = BasisLieHighestWeight.basisLieHighestWeight("A", 2, [1,0], operators=[1,2,1]) + mons = BasisLieHighestWeight.basis_lie_highest_weight("A", 2, [1,0], operators=[1,2,1]) @test issetequal(string.(mons), Set(["1", "x2*x3", "x3"])) end @testset "Compare with simple algorithm and check dimension" begin From 49b6ddc7a2d907b820d7141b6ed37a264aad601b Mon Sep 17 00:00:00 2001 From: BenWilop Date: Wed, 12 Apr 2023 23:06:27 +0200 Subject: [PATCH 17/19] pseudocode for basis_lie_highest_weight --- .../src/BasisLieHighestWeight.jl | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl b/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl index babfb0260ef1..230a269ac8b1 100644 --- a/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl +++ b/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl @@ -103,6 +103,39 @@ function basis_lie_highest_weight(type::String, rank::Int, highest_weight::Vecto monomial_order::Union{String, Function} = "GRevLex", cache_size::Int = 0, parallel::Bool = false, return_no_minkowski::Bool = false, return_operators::Bool = false) + """ + Pseudocode: + + basis_lie_highest_weight(highest_weight) + return compute_monomials(highest_weight) + + compute_monomials(highest_weight) + if highest_weight was already computed + return old results + if highest_weight = [0, ..., 0] or [0, ..., 1, ..., 0] + return add_by_hand(highest_weight, {}) + else + set_mon = {} + go through all partitions lambda_1 + lambda_2 = highest_weight + add compute_monomials(lambda_1) (+) compute_monomials(lambda_1) to set_mon + if set_mon too small + add_by_hand(highest_weight, set_mon) + return set_mon + + add_by_hand(highest_weight, set_mon) + add_known_monomials(set_mon) + go through all weightspaces that are not full + add_new_monomials(weightspace, set_mon) + return set_mon + + add_known_monomials(set_mon) + add all monomials from set_mon to basis + + add_new_monomials(weightspace, set_mon) + calculate monomials with weight in weightspace + go through them one by one in monomial_order until basis is full + return set_mon + """ # The function precomputes objects that are independent of the highest weight and that can be used in all recursion # steps. Then it starts the recursion and returns the result. From 02918d3b4d0cb59a848a9b90b570b4858af4e403 Mon Sep 17 00:00:00 2001 From: BenWilop Date: Sat, 15 Apr 2023 22:52:26 +0200 Subject: [PATCH 18/19] changed RootCOnversion type A to make it consistent with the other functions --- .../src/RootConversion.jl | 93 ++++++++++--------- 1 file changed, 49 insertions(+), 44 deletions(-) diff --git a/experimental/BasisLieHighestWeight/src/RootConversion.jl b/experimental/BasisLieHighestWeight/src/RootConversion.jl index fa8d54fa7ab4..6e1191b2d89f 100644 --- a/experimental/BasisLieHighestWeight/src/RootConversion.jl +++ b/experimental/BasisLieHighestWeight/src/RootConversion.jl @@ -4,27 +4,34 @@ using Oscar fromGap = Oscar.GAP.gap_to_julia function w_to_eps(type::String, rank::Int, weight::Vector{Int})::Vector{Int} - if type == "A" - return w_to_eps_A(rank, weight) - elseif type in ["B", "C", "D", "E", "F", "G"] + """ + converts weight in rootsystem w_i to eps_i + """ + if type in ["A", "B", "C", "D", "E", "F", "G"] return alpha_to_eps(type, rank, w_to_alpha(type, rank, weight)) else - println("This type of lie algebra is not supported.") + println("Type needs to be one of A-D") end end function eps_to_w(type::String, rank::Int, weight::Vector{Int})::Vector{Int} - if type == "A" - return eps_to_w_A(rank, weight) - elseif type in ["B", "C", "D", "E", "F", "G"] + """ + converts weight in rootsystem eps_i to w_i + """ + if type in ["A", "B", "C", "D", "E", "F", "G"] return round.(alpha_to_w(type, rank, eps_to_alpha(type, rank, weight))) else - println("This type of lie algebra is not supported.") + println("Type needs to be one of A-D") end end function alpha_to_eps(type::String, rank::Int, weight::Vector{Int})::Vector{Int} - if type in ["B", "C", "D"] + """ + converts weight in rootsystem alpha_i to eps_i + """ + if type == "A" + return alpha_to_eps_A(rank, weight) + elseif type in ["B", "C", "D"] return alpha_to_eps_BCD(type, rank, weight) elseif type == "E" && rank in [6, 7, 8] return alpha_to_eps_E(rank, weight) @@ -38,7 +45,12 @@ function alpha_to_eps(type::String, rank::Int, weight::Vector{Int})::Vector{Int} end function eps_to_alpha(type::String, rank::Int, weight::Vector{Int})::Vector{Int} - if type in ["B", "C", "D"] + """ + converts weight in rootsystem eps_i to alpha_i + """ + if type == "A" + return eps_to_alpha_A(rank, weight) + elseif type in ["B", "C", "D"] return eps_to_alpha_BCD(type, rank, weight) elseif type == "E" && rank in [6, 7, 8] return eps_to_alpha_E(rank, weight) @@ -78,8 +90,6 @@ function get_inverse_CartanMatrix(type::String, rank::Int) return inv(get_CartanMatrix(type, rank)) end - - function alpha_to_eps_BCD(type::String, rank::Int, weight::Vector{Int})::Vector{Int} """ for B-D @@ -314,23 +324,6 @@ function eps_to_alpha_G(weight::Vector{Int})::Vector{Int} return alpha end -function w_to_eps_A(rank::Int, weight::Vector{Int})::Vector{Int} - """ - input: weight in w_i - output: weight in eps_i - inverse to eps_to_w - # TODO (right now only for t=A) - """ - res = [0 for i in 1:(rank+1)] - for i in 1:rank - for l in 1:i - res[l] += weight[i] - end - end - choose_representant_eps(res) - return res -end - function choose_representant_eps(weight::Vector{Int}) # choose representant eps_1 + ... + eps_m = 0 if any(<(0), weight) # non negative @@ -338,24 +331,36 @@ function choose_representant_eps(weight::Vector{Int}) end end -function eps_to_w_A(rank::Int, weight::Vector{Int})::Vector{Int} +function alpha_to_eps_A(rank::Int, weight::Vector{Int})::Vector{Int} + """ + for A + """ + eps = [0 for i in 1:(rank + 1)] + for i in 1:rank + eps[i] += weight[i] + eps[i + 1] -= weight[i] + end + choose_representant_eps(eps) + return eps +end + +function eps_to_alpha_A(rank::Int, weight::Vector{Int})::Vector{Int} """ - input: weight in eps_i - output: weight in w_i - inverse to w_to_eps + for A """ - m = length(weight) - choose_representant_eps(weight) - if weight[rank + 1] != 0 # eps_n+1 = 0 - weight .-= weight[rank + 1] - weight[rank + 1] = 0 + if length(weight) == rank + append!(weight, 0) end - res = [0 for i in 1:rank] - for i in rank:-1:1 - res[i] = weight[i] - for l in 1:i - weight[l] -= weight[i] + alpha = [0.0 for i in 1:(rank + 1)] + for i in 1:(rank + 1) + for j in 1:i + alpha[i] += weight[j] end end - return res + m = alpha[rank + 1] / (rank + 1) + for i in 1:rank + alpha[i] -= i*m + end + pop!(alpha) + return alpha end From 20ab80e9a00c719347f0ec40b1e29bbd9150b049 Mon Sep 17 00:00:00 2001 From: Ben Wilop Date: Sun, 23 Apr 2023 21:39:51 +0200 Subject: [PATCH 19/19] removed Markdown --- .../src/BasisLieHighestWeight.jl | 6 ++---- experimental/BasisLieHighestWeight/test/MBOld.jl | 13 ++++--------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl b/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl index 230a269ac8b1..40669c734a1f 100644 --- a/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl +++ b/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl @@ -3,14 +3,12 @@ export basis_lie_highest_weight export is_fundamental using Polymake -# using Distributed -using Markdown include("./NewMonomial.jl") fromGap = Oscar.GAP.gap_to_julia -@doc Markdown.doc""" +@doc """ basisLieHighestWeight(type::String, rank::Int, highest_weight::Vector{Int}; operators::Union{String, Vector{Int}} = "regular", monomial_order::Union{String, Function} = "GRevLex", cache_size::Int = 0, @@ -288,7 +286,7 @@ function compute_monomials(type::String, rank::Int, lie_algebra::GAP.Obj, ZZx::Z end end -@doc Markdown.doc""" +@doc """ is_fundamental(highest_weight::Vector{Int})::Bool returns true if ``highest_weight`` is fundamental, i.e. [0, ..., 1, ..., 0] diff --git a/experimental/BasisLieHighestWeight/test/MBOld.jl b/experimental/BasisLieHighestWeight/test/MBOld.jl index 687aa79ef7cf..b990e3d39127 100644 --- a/experimental/BasisLieHighestWeight/test/MBOld.jl +++ b/experimental/BasisLieHighestWeight/test/MBOld.jl @@ -1,7 +1,8 @@ # This file is an old version of the algorithm that can compute (not all cases) of - # BasisLieHighestWeight.basis_lie_highest_weight and is used in runtests.jl to check that the newer algorithm matches + # BasisLieHighestWeight.basis_lie_highest_weight and is used only in runtests.jl to check that the newer algorithm matches # There is code doubling, but I am not sure how the src part is going to change when its integrated with the other - # lie algebra work. + # lie algebra work and would prefer to change this file after doing the integration to make sure that everything stays + # correct. module MBOld @@ -193,11 +194,6 @@ function tensorMatricesForOperators(L, hw, ops) return mats end -#### monomial basis - - -# TODO: Demazure modules - """ basisLieHighestWeight(t::String, n::Int, hw::Vector{Int}; parallel::Bool = true) :: Tuple{Vector{Vector{Short}},Vector{TVec}} @@ -219,7 +215,6 @@ function basisLieHighestWeight(t::String, n::Int, hw::Vector{Int}; roots = []) # wts = weightsForOperators(L, CH[3], ops) wts = (v->Int.(v)).(wts) - #--- mats speichert die Matrizen g_i für (g_1^a_1 * ... * g_k^a_k)*v0 ab. mats = tensorMatricesForOperators(L, hw, ops) hwv = sparse_row(ZZ, [(1,1)]) @@ -303,4 +298,4 @@ function compute(v0, mats, wts::Vector{Vector{Int}}) return monomials end -end # module +end