diff --git a/Project.toml b/Project.toml index 82d24c7..a5672da 100644 --- a/Project.toml +++ b/Project.toml @@ -12,6 +12,7 @@ Memoization = "6fafb56a-5788-4b4e-91ca-c0cea6611c73" Oscar = "f1435218-dba5-11e9-1e4d-f1a5fab5fc13" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" Singular = "bcd08a7b-43d2-5ff7-b6d4-c458787f915c" +StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] @@ -22,4 +23,5 @@ LinearAlgebraX = "0.2.10" Memoization = "0.2.2" Oscar = "1" Singular = "0.28" +StaticArrays = "1.9.17" julia = "1.10" diff --git a/src/Bundles.jl b/src/Bundles.jl index 967e4fb..155a069 100644 --- a/src/Bundles.jl +++ b/src/Bundles.jl @@ -292,7 +292,7 @@ function exterior_power(F::Bundle, k::Int) CH = chow_ring(F) _has_chern_data(F) && - setfield!(new, :chern_character, simplify!(CH(_chern_characters_wedge(F, k)[end]))) + setfield!(new, :chern_character, __simplify(CH(_chern_characters_wedge(F, k)[end]))) if isdefined(F, :teleman_weights) new_weights = Dict( hn_type => @@ -360,7 +360,9 @@ function symmetric_power(F::Bundle, k::Int) CH = chow_ring(F) _has_chern_data(F) && - setfield!(new, :chern_character, simplify!(CH(_chern_characters_symmetric(F, k)[end]))) + setfield!( + new, :chern_character, __simplify(CH(_chern_characters_symmetric(F, k)[end])) + ) if isdefined(F, :teleman_weights) new_weights = Dict( hn_type => @@ -372,20 +374,8 @@ function symmetric_power(F::Bundle, k::Int) return new end -function homogeneous_components(M::QuiverModuliSpace, x) - n = dimension(M) - CH = chow_ring(M) - return [ - sum( - t for t in Singular.terms(x) if __chow_ring_monomial_grading(M, t) == i; init=CH(0) - ) - for - i in 0:n - ] -end - function truncate(M::QuiverModuliSpace, x, n) - comps = homogeneous_components(M, x) + comps = __homogeneous_components(M, x) # TODO this may be slow, try building new polynomial # also can I use the incorrect but faster Singular.degree? return sum(comps[i + 1] for i in 0:n) @@ -416,7 +406,7 @@ function _chern_characters_wedge(F::Bundle, k) init=CH(0), ), n) - simplify!(wedges[j + 1]) + wedges[j + 1] = __simplify(wedges[j + 1]) end return wedges end @@ -447,7 +437,7 @@ function _chern_characters_symmetric(F::Bundle, k) init=CH(0), ), n) - simplify!(syms[j + 1]) + syms[j + 1] = __simplify(syms[j + 1]) end return syms end @@ -463,20 +453,20 @@ function adams(F::Bundle, k) n = dimension(M) x = chern_character(F) - return [k^i for i in 0:n]' * homogeneous_components(M, x) + return [k^i for i in 0:n]' * __homogeneous_components(M, x) end function _chern_classes_from_character(F::Bundle) CH = chow_ring(F) M = variety(F) n = dimension(M) - comps = homogeneous_components(M, chern_character(F)) + comps = __homogeneous_components(M, chern_character(F)) p = [(CH(-1))^i * CH(factorial(i)) * comps[i + 1] for i in 0:n] e = [CH(0) for _ in 1:(n + 1)] e[1] = CH(1) for i in 1:n e[i + 1] = CH(-1//i) * sum(p[j + 1] * e[i - j + 1] for j in 1:i) - simplify!(e[i + 1]) + e[i + 1] = __simplify(e[i + 1]) end return Dict(i => e[i + 1] for i in 0:n) end @@ -491,18 +481,11 @@ function _chern_character_from_classes(F::Bundle) for i in 1:(n - 1) p[i + 1] = -CH(i + 1) * e[i + 1] - sum(e[j] * p[i - j + 1] for j in 1:i) end - return simplify(sum(CH((-1)^i//factorial(i)) * p[i] for i in 1:n) + rank(F)) -end - -simplify(f::Singular.spoly{Singular.n_Q}) = div(f, f.parent(1)) - -function simplify!(f::Singular.spoly{Singular.n_Q}) - f = div(f, f.parent(1)) - return f + return __simplify(sum(CH((-1)^i//factorial(i)) * p[i] for i in 1:n) + rank(F)) end """ - line_bundle(M::QuiverModuliSpace, eta::AbstractVector{Int}) + line_bundle(M::QuiverModuliSpace, eta::AbstractVector{Int}; unsafe::Bool=false, teleman::Bool=true) Construct the descent of `L(eta)` on the quiver moduli space `M`. @@ -510,6 +493,10 @@ Construct the descent of `L(eta)` on the quiver moduli space `M`. - `M::QuiverModuliSpace`: a quiver moduli space. - `eta::AbstractVector{Int}`: a dimension vector. +- `unsafe::Bool`: Optional keyword argument to skip Chow ring computation checks. + Default is `false`. +- `teleman::Bool`: Optional keyword argument to compute + the Teleman weights of the line bundle. Default is `true`. # Output @@ -530,7 +517,7 @@ julia> chern_class(H) -x21 julia> teleman_weights(H) -Dict{HNType{2}, Vector{Int64}} with 7 entries: +Dict{HNType, Vector{Int64}} with 7 entries: [[2, 2], [0, 1]] => [-10] [[2, 1], [0, 2]] => [-20] [[1, 0], [1, 2], [0, 1]] => [-40] @@ -539,20 +526,32 @@ Dict{HNType{2}, Vector{Int64}} with 7 entries: [[1, 1], [1, 2]] => [-5] [[2, 0], [0, 3]] => [-30] ``` + +The 7-subspace quiver moduli space: +```jldoctest +julia> Q = subspace_quiver(7); d = push!(ones(Int, 7), 2); M = QuiverModuliSpace(Q, d); + +julia> K_dual = line_bundle(M, canonical_stability(Q, d); unsafe=true, teleman=false); K_dual.chern_class[1] +-2*x11 - 2*x21 - 2*x31 - 2*x41 - 2*x51 - 2*x61 + 7*x81 +``` """ -function line_bundle(M::QuiverModuliSpace, eta::AbstractVector{Int}) +function line_bundle( + M::QuiverModuliSpace, eta::AbstractVector{Int}; unsafe::Bool=false, teleman::Bool=true +) eta' * M.d != 0 && throw(ArgumentError("$(eta) is not a linearization.")) - new = Bundle(M, 1, chern_class_line_bundle(M, eta)) - return set_teleman_weights!(new, weights_line_bundle(M, eta)) + new = Bundle(M, 1, chern_class_line_bundle(M, eta; unsafe=unsafe)) + teleman && set_teleman_weights!(new, weights_line_bundle(M, eta)) + return new end """ - canonical_bundle(M::QuiverModuliSpace) + canonical_bundle(M::QuiverModuliSpace; teleman::Bool=true, verbose::Bool=false, unsafe::Bool=false) Compute the canonical bundle on the quiver moduli space `M`. -If ``d`` is ``theta``-coprime and amply stable, the canonical bundle -is described in [[Proposition 4.2, MR4352662](https://mathscinet.ams.org/mathscinet-getitem?mr=4352662)]. +If the moduli problem is amply stable and does not admit properly semistable representations, +the canonical bundle is described in +[[Proposition 4.2, MR4352662](https://mathscinet.ams.org/mathscinet-getitem?mr=4352662)]. This function computes both the Chern character and the Teleman weights of the canonical bundle. @@ -560,6 +559,8 @@ of the canonical bundle. # Input - `M::QuiverModuliSpace`: a quiver moduli space. +- `teleman::Bool`: Optional keyword argument to compute the Teleman weights of the canonical bundle. Default is `true`. +- `unsafe::Bool`: Optional keyword argument to skip ample stability and properly semistable checks. Default is `false`. # Output @@ -583,7 +584,7 @@ julia> map(chern_class, omega) 6*x11 julia> map(teleman_weights, omega) -5-element Vector{Dict{HNType{2}, Vector{Int64}}}: +5-element Vector{Dict{HNType, Vector{Int64}}}: Dict([[1, 0], [0, 1]] => [4]) Dict([[1, 0], [0, 1]] => [6]) Dict([[1, 0], [0, 1]] => [8]) @@ -602,7 +603,7 @@ julia> chern_class(omega) 3*x21 julia> QuiverTools.teleman_weights(omega) -Dict{HNType{2}, Vector{Int64}} with 7 entries: +Dict{HNType, Vector{Int64}} with 7 entries: [[2, 2], [0, 1]] => [30] [[2, 1], [0, 2]] => [60] [[1, 0], [1, 2], [0, 1]] => [120] @@ -612,18 +613,26 @@ Dict{HNType{2}, Vector{Int64}} with 7 entries: [[2, 0], [0, 3]] => [90] ``` """ -function canonical_bundle(M::QuiverModuliSpace) - !(is_coprime(M) && is_amply_stable(M)) && - throw( - NotImplementedError( - "not coprime and amply stable, cannot compute the canonical bundle." - ), - ) - return line_bundle(M, -canonical_stability(M.Q, M.d)) +function canonical_bundle(M::QuiverModuliSpace; teleman::Bool=true, unsafe::Bool=false) + if !unsafe + has_properly_semistables(M.Q, M.d, M.theta, M.denom) && + throw( + ArgumentError( + "The quiver moduli problem has properly semistables, no description of the canonical bundle is available." + ), + ) + !is_amply_stable(M) && + throw( + ArgumentError( + "The quiver moduli problem is not amply stable, no description of the canonical bundle is available." + ), + ) + end + return line_bundle(M, -canonical_stability(M.Q, M.d); unsafe=unsafe, teleman=teleman) end """ - universal_bundle(M:::QuiverModuliSpace, i::Int) + universal_bundle(M:::QuiverModuliSpace, i::Int; teleman::Bool=true, unsafe::Bool=false) Compute the `i`-th universal bundle of `M`. @@ -638,6 +647,8 @@ by calling `chow_ring(M)` and it will use the default linearization. - `M::QuiverModuliSpace`: a quiver moduli space. - `i::Int`: the universal bundle on the `i`-th vertex of the quiver. +- `teleman::Bool`: Optional keyword argument to compute the Teleman weights of the universal bundle. Default is `true`. +- `unsafe::Bool`: Optional keyword argument to skip ample stability checks. Default is `false`. # Output @@ -660,7 +671,7 @@ julia> map(chern_class, [u1, u2]) x21 + 1 julia> map(teleman_weights, [u1, u2]) -2-element Vector{Dict{HNType{2}, Vector{Int64}}}: +2-element Vector{Dict{HNType, Vector{Int64}}}: Dict([[1, 0], [0, 1]] => [0]) Dict([[1, 0], [0, 1]] => [-2]) ``` @@ -682,7 +693,7 @@ julia> map(chern_character, [u1, u2]) julia> w = map(teleman_weights, [u1, u2]); julia> w[1] -Dict{HNType{2}, Vector{Int64}} with 7 entries: +Dict{HNType, Vector{Int64}} with 7 entries: [[2, 2], [0, 1]] => [5, 5] [[2, 1], [0, 2]] => [10, 10] [[1, 0], [1, 2], [0, 1]] => [25, 15] @@ -692,7 +703,7 @@ Dict{HNType{2}, Vector{Int64}} with 7 entries: [[2, 0], [0, 3]] => [15, 15] julia> w[2] -Dict{HNType{2}, Vector{Int64}} with 7 entries: +Dict{HNType, Vector{Int64}} with 7 entries: [[2, 2], [0, 1]] => [5, 5, 0] [[2, 1], [0, 2]] => [10, 5, 5] [[1, 0], [1, 2], [0, 1]] => [15, 15, 10] @@ -702,20 +713,21 @@ Dict{HNType{2}, Vector{Int64}} with 7 entries: [[2, 0], [0, 3]] => [10, 10, 10] ``` """ -function universal_bundle(M::QuiverModuliSpace, i::Int) - !is_coprime(M) && - throw( - ArgumentError("$(M.d) is not $(M.theta)-coprime, universal bundles do not exist.") - ) - cl = total_chern_class_universal(M, i) +function universal_bundle( + M::QuiverModuliSpace, i::Int; unsafe::Bool=false, teleman::Bool=true +) + gcd(M.d) > 1 && throw( + ArgumentError("gcd($(M.d)) = $(gcd(M.d)) > 1, the universal bundles do not exist.") + ) + cl = total_chern_class_universal(M, i; unsafe=unsafe) new = Bundle(M, M.d[i], cl) - weights = weights_universal_bundle(M, i) - return set_teleman_weights!(new, weights) + teleman && set_teleman_weights!(new, weights_universal_bundle(M, i)) + return new end """ - degree(F::Bundle) + degree(F::Bundle; unsafe::Bool=false) Compute the degree of the bundle `F`. If `rank(F)` is larger than ``1``, returns the degree of the determinant of `F`. @@ -723,6 +735,7 @@ If `rank(F)` is larger than ``1``, returns the degree of the determinant of `F`. # Input - `F::Bundle`: a bundle. +- `unsafe::Bool=false`: whether to skip ample stability checks. Default is `false`. # Output @@ -764,9 +777,39 @@ julia> chern_class(F) julia> degree(F) 56 ``` + +The 7-subspace quiver: +```jldoctest +julia> Q = subspace_quiver(7); d = push!(ones(Int, 7), 2); M = QuiverModuliSpace(Q, d); + +julia> K_dual = line_bundle(M, canonical_stability(Q, d); unsafe=true); + +julia> degree(K_dual; unsafe=true) +154 +``` """ -function degree(F::Bundle) +function degree(F::Bundle; unsafe::Bool=false) M = variety(F) - n = dimension(M) - return div(homogeneous_components(M, chern_class(det(F))^n)[n + 1], point_class(M)) + unsafe ? (n = 1 - euler_form(M.Q, M.d, M.d)) : (n = dimension(M)) + + if rank(F) == 1 + out = chern_class(F) + else + out = chern_class(det(F)) + end + + out = Singular.jet(out, n) + out = __simplify(out) + if n >= 2 + class_det = deepcopy(out) + for _ in 1:(n - 1) + # the multiplication here takes most of runtime + Oscar.mul!(out, out, class_det) + out = Singular.jet(out, n) + out = __simplify(out) + end + end + + pt = point_class(M; unsafe=unsafe) + return div(__homogeneous_components(M, out)[n + 1], pt) end diff --git a/src/Chow.jl b/src/Chow.jl index 624e973..36b1a86 100644 --- a/src/Chow.jl +++ b/src/Chow.jl @@ -17,6 +17,44 @@ function partial_order(Q::Quiver, f::AbstractVector{Int}, g::AbstractVector{Int} return true end +""" + __simplify(f) + +Force some Gröbner basis simplification of the polynomial `f` +by dividing it by 1. + +For internal use only. +""" +__simplify(f) = div(f, one(parent(f))) + +""" + __homogeneous_components(M::QuiverModuliSpace, x; unsafe::Bool=false) + +# Input + +- `M::QuiverModuliSpace`: a quiver moduli space. +- `x`: an element of the Chow ring of `M`. +- `unsafe::Bool=false`: whether to compute the dimension of `M` using + the faster Euler form instead of `dimension()`. Default is `false`. + +Decompose a Chow ring element `x` into its homogeneous components. + +For internal use only. +""" +function __homogeneous_components(M::QuiverModuliSpace, x; unsafe::Bool=false) + unsafe ? (n = 1 - euler_form(M.Q, M.d, M.d)) : (n = dimension(M)) + + CH = parent(x) + + return [ + sum( + t for t in Singular.terms(x) if __chow_ring_monomial_grading(M, t) == i; init=CH(0) + ) + for + i in 0:n + ] +end + """ symmetric_polynomial(degree::Int) @@ -110,12 +148,23 @@ function chow_ring( theta::AbstractVector{Int}=canonical_stability(Q, d); chi::AbstractVector{Int}=extended_gcd(d)[2], verbose::Bool=false, + unsafe::Bool=false, ) - # safety checks - if !is_coprime(d, theta) - throw(ArgumentError("d and theta are not coprime")) - elseif chi' * d != 1 - throw(ArgumentError("``chi`` is not a linearization")) + chi' * d != 1 && throw(ArgumentError("``chi`` is not a linearization")) + if !unsafe + has_properly_semistables(Q, d, theta) && + throw( + ArgumentError( + "The quiver moduli problem has properly semistable representations, no description of the Chow ring is available." + ), + ) + !is_amply_stable(Q, d, theta) && throw( + ArgumentError( + "The quiver moduli problem is not amply stable, no description of the Chow ring is available." + ), + ) + else + verbose && @warn "Unsafe computation." end # j varies first, then i @@ -128,14 +177,17 @@ function chow_ring( return vars[sum(d[1:(i - 1)]; init=0) + j] end + # build a base of R as an A-module. bounds = UnitRange{Int64}[0:(d[i] - nu) for i in 1:n_vertices(Q) for nu in 1:d[i]] - build_elem(lambda::NTuple) = prod( - prod( - xi(i, nu)^lambda[sum(d[1:(i - 1)]; init=0) + nu] - for nu in 1:d[i]; init=R(1) - ) - for i in support(d); init=R(1) - ) + function build_elem(lambda::NTuple) + out = R(1) + for i in support(d) + for nu in 1:d[i] + Oscar.mul!(out, out, xi(i, nu)^lambda[sum(d[1:(i - 1)]; init=0) + nu]) + end + end + return out + end base = map(build_elem, Iterators.product(bounds...)) verbose && @info "base has $(length(base)) elements" @@ -146,6 +198,7 @@ function chow_ring( # sign for the product of symmetric groups sign_product(w) = prod(sign(Oscar.perm(wi)) for wi in w; init=1) + # caching the indices of the variables after each permutation permuted_indices = Dict{Tuple,Vector{Int64}}( sigma => reduce( @@ -158,6 +211,7 @@ function chow_ring( ) permute_vector(e, sigma) = [e[k] for k in permuted_indices[sigma]] + # constructor of the permuted polynomial. This is much faster than f(permuted_vars[sigma]...) function permute(f::Singular.spoly{Singular.n_Q}, sigma::Tuple) context = Singular.MPolyBuildCtx(parent(f)) for (c, e) in zip(Singular.coefficients(f), Singular.exponent_vectors(f)) @@ -165,8 +219,6 @@ function chow_ring( end return Singular.finish(context) end - # Action of the symmetric group on R by permutation of the variables. - # permute(f, sigma) = f(permuted_vars[sigma]...) # The discriminant in the definition of the antisymmetrization. delta = prod( @@ -175,9 +227,14 @@ function chow_ring( ) function antisymmetrize(f::Singular.spoly{Singular.n_Q}) - out = sum( - sign_product(sigma) * permute(f, sigma) for sigma in W; init=R(0) - ) + out = R(0) + for sigma in W + if sign_product(sigma) == 1 + out += permute(f, sigma) + else # sign_product(sigma) == -1 # can be skipped since it is just a sign + out -= permute(f, sigma) + end + end return div(out, delta) end @@ -194,10 +251,10 @@ function chow_ring( # builds a new forbidden polynomial for the minimal forbidden dimension vector e. function new_forbidden(e::AbstractVector{Int}) - out = 1 + out = R(1) for (i, j) in Iterators.product(1:n_vertices(Q), 1:n_vertices(Q)) for r in 1:e[i], s in (e[j] + 1):d[j] - out *= (xi(j, s) - xi(i, r))^Q.adjacency[i, j] + Oscar.mul!(out, out, (xi(j, s) - xi(i, r))^Q.adjacency[i, j]) end end return out @@ -237,7 +294,6 @@ function chow_ring( a = antisymmetrize(forbidden_polynomials[i] * b) a != 0 && push!(anti, a) end - # unique!(anti) end verbose && @info "there are $(length(anti)) antisymmetrized forbidden polynomials" @@ -253,7 +309,7 @@ function chow_ring( end """ - chow_ring(M::QuiverModuliSpace; chi::Union{AbstractVector{Int},UndefInitializer}=undef) + chow_ring(M::QuiverModuliSpace; chi::Union{AbstractVector{Int},UndefInitializer}=undef, verbose::Bool=false, unsafe::Bool=false) Compute the Chow ring of the moduli space `M` for the given linearization `chi`. @@ -271,6 +327,7 @@ Compute the Chow ring of the moduli space `M` for the given linearization `chi`. function chow_ring( M::QuiverModuliSpace; chi::Union{AbstractVector{Int},UndefInitializer}=undef, verbose::Bool=false, + unsafe::Bool=false, ) if !isdefined(M.chow, :chi) if (chi isa UndefInitializer) @@ -278,7 +335,9 @@ function chow_ring( else setfield!(M.chow, :chi, chi) end - CH, R, inc = chow_ring(M.Q, M.d, M.theta; chi=M.chow.chi, verbose=verbose) + CH, R, inc = chow_ring( + M.Q, M.d, M.theta; chi=M.chow.chi, verbose=verbose, unsafe=unsafe + ) setfield!(M.chow, :ring, CH[1]) setfield!(M.chow, :_R, R) setfield!(M.chow, :_inclusion, inc) @@ -288,7 +347,7 @@ function chow_ring( if !(chi isa UndefInitializer) && M.chow.chi != chi # reinitializing all the fields setfield!(M.chow, :chi, chi) - CH, R, inc = chow_ring(M.Q, M.d, M.theta; chi=chi, verbose=verbose) + CH, R, inc = chow_ring(M.Q, M.d, M.theta; chi=chi, verbose=verbose, unsafe=unsafe) setfield!(M.chow, :ring, CH[1]) setfield!(M.chow, :_R, R) setfield!(M.chow, :_inclusion, inc) @@ -349,7 +408,7 @@ function extended_gcd(x) end """ - chern_class_line_bundle(M::QuiverModuliSpace, eta::AbstractVector{Int}) + chern_class_line_bundle(M::QuiverModuliSpace, eta::AbstractVector{Int}; unsafe::Bool=false) Compute the first Chern class of the line bundle `L(eta)`. @@ -359,6 +418,8 @@ This is given by ``L(eta) = \\bigoplus_{i \\in Q_0} \\det(U_i)^{-eta_i}``. - `M::QuiverModuliSpace`: a moduli space of representations of a quiver. - `eta::AbstractVector{Int]`: a choice of linearization for the trivial line bundle. +- `unsafe::Bool=false`: whether to skip the checks on ample stability and + existence of properly semistables. Default is `false`. # Output @@ -385,17 +446,20 @@ julia> chern_class_line_bundle(M, [9, -6]) """ function chern_class_line_bundle( M::QuiverModuliSpace, - eta::AbstractVector{Int}, + eta::AbstractVector{Int}; + unsafe::Bool=false, ) - A = chow_ring(M) - I = quotient_ideal(A) - Rvars = gens(base_ring(I)) + A = chow_ring(M; unsafe=unsafe) + R = base_ring(quotient_ideal(A)) + Rvars = gens(R) proj = __projection_to_quotient_ring(A) - chern_class = - -sum(eta[i] * Rvars[1 + sum(M.d[1:(i - 1)])] for i in support(M.d)) + chern_class = R(0) + for i in support(M.d) + Oscar.add!(chern_class, chern_class, eta[i] * Rvars[1 + sum(M.d[1:(i - 1)])]) + end - return A(div(proj(chern_class), A(1))) + return __simplify(proj(- chern_class)) end """ @@ -439,7 +503,7 @@ function chern_character_line_bundle( end """ - total_chern_class_universal(M::QuiverModuliSpace, i) + total_chern_class_universal(M::QuiverModuliSpace, i::Int; unsafe::Bool=false) Compute the total Chern class of the universal bundle `U_i`. @@ -467,21 +531,24 @@ x21 + x22 + x23 + 1 """ function total_chern_class_universal( M::QuiverModuliSpace, - i::Int, + i::Int; + unsafe::Bool=false, ) - CH = chow_ring(M) + CH = chow_ring(M; unsafe=unsafe) CHvars = gens(CH) return sum(CHvars[sum(M.d[1:(i - 1)]) + r] for r in 1:M.d[i]; init=CH(0)) + CH(1) end """ - point_class(M::QuiverModuliSpace) + point_class(M::QuiverModuliSpace; unsafe::Bool=false) Compute the point class of the moduli space `M`. # Input - `M::QuiverModuliSpace`: a moduli space of representations of a quiver. +- `unsafe::Bool=false`: whether to skip the checks on ample stability and + existence of properly semistables. Default is `false`. # Output @@ -508,30 +575,49 @@ julia> M = QuiverModuliSpace(Q, [2, 3]); julia> point_class(M) x23^2 ``` + +The 7-subspace quiver: +```jldoctest +julia> Q = subspace_quiver(7); d = push!(ones(Int, 7), 2); M = QuiverModuliSpace(Q, d); + +julia> point_class(M; unsafe=true) +1//10*x81^4 +``` """ function point_class( - M::QuiverModuliSpace + M::QuiverModuliSpace; + unsafe::Bool=false, ) if isdefined(M.chow, :point) && M.chow.point != undef return M.chow.point end - CH = chow_ring(M) - num = 1 - den = 1 - N = dimension(M) + CH = chow_ring(M; unsafe=unsafe) + num = CH(1) + unsafe ? (N = 1 - euler_form(M.Q, M.d, M.d)) : (N = dimension(M)) for i in 1:n_vertices(M.Q) - c = total_chern_class_universal(M, i) - num *= c^(M.d' * M.Q.adjacency[:, i]) - den *= c^M.d[i] + c = total_chern_class_universal(M, i; unsafe=unsafe) + for k in 1:(M.d' * M.Q.adjacency[:, i]) + Oscar.mul!(num, num, c) + num = __simplify(num) + num = Singular.jet(num, N) + end + end + # dividing at once is very slow, iteratively is much faster. + for i in 1:n_vertices(M.Q) + c = total_chern_class_universal(M, i; unsafe=unsafe) + for _ in 1:M.d[i] + num = Oscar.Singular.div(num, c) + end end - quot = div(num, den) - pt = sum( - term for term in Singular.terms(quot) if __chow_ring_monomial_grading(M, term) == N; - init=CH(0), - ) + pt = CH(0) + for term in Oscar.Singular.terms(num) + if __chow_ring_monomial_grading(M, term) == N + Oscar.add!(pt, pt, term) + end + end setfield!(M.chow, :point, pt) return M.chow.point end @@ -570,7 +656,8 @@ julia> todd_class(M) ``` """ function todd_class( - M::QuiverModuliSpace + M::QuiverModuliSpace; + unsafe::Bool=false, ) if isdefined(M.chow, :todd) && M.chow.todd != undef return M.chow.todd @@ -578,7 +665,7 @@ function todd_class( N = dimension(M) # consider these constructors: https://nemocas.github.io/AbstractAlgebra.jl/latest/mpolynomial/#Polynomial-functions - A = chow_ring(M) + A = chow_ring(M; unsafe=unsafe) R, inclusion = M.chow._R, M.chow._inclusion Rvars = gens(R) proj = __projection_to_quotient_ring(A) @@ -594,7 +681,7 @@ function todd_class( i, j = a for p in 1:M.d[i] for q in 1:M.d[j] - num *= todd_Q(xi(j, q) - xi(i, p), N) + Oscar.mul!(num, num, todd_Q(xi(j, q) - xi(i, p), N)) num = Singular.jet(num, N) end end @@ -603,7 +690,7 @@ function todd_class( for i in 1:n_vertices(M.Q) for p in 1:M.d[i] for q in 1:M.d[i] - den *= todd_Q(xi(i, q) - xi(i, p), N) + Oscar.mul!(den, den, todd_Q(xi(i, q) - xi(i, p), N)) den = Singular.jet(den, N) end end @@ -621,7 +708,7 @@ function todd_class( den /= constant_coefficient(den) quot = div(proj(num), proj(den)) - quot = div(quot, A(1)) + quot = __simplify(quot) setfield!(M.chow, :todd, A(quot)) return M.chow.todd end @@ -692,7 +779,7 @@ julia> integral(U1) """ function integral(M::QuiverModuliSpace, f) n = dimension(M) - integ = div(homogeneous_components(M, f * todd_class(M))[n + 1], point_class(M)) + integ = div(__homogeneous_components(M, f * todd_class(M))[n + 1], point_class(M)) return Singular.constant_coefficient(integ) end @@ -720,7 +807,10 @@ objects passed. Instead, it assumes that the Chow ring passed has variables ``x_{i, j}`` as in the Chow ring paper. """ function __chow_ring_monomial_grading(M::QuiverModuliSpace, f) - return __chow_degrees(M.d)' * collect(Singular.exponent_vectors(f))[1] + deg = __chow_degrees(M.d) + exp = first(Oscar.AbstractAlgebra.exponent_vectors(f)) + @assert size(deg) == size(exp) + return exp' * deg end """ diff --git a/src/Constructors.jl b/src/Constructors.jl index 74d1d44..5efe053 100644 --- a/src/Constructors.jl +++ b/src/Constructors.jl @@ -73,7 +73,7 @@ julia> loop_quiver(4) ``` """ function loop_quiver(m::Int) - return Quiver(Matrix{Int}(reshape([m], 1, 1)), string(m) * "-loop quiver") + return Quiver(reshape([m], 1, 1), string(m) * "-loop quiver") end """ @@ -243,13 +243,8 @@ The bipartite quiver with `m + n` vertices. # Examples ```jldoctest -julia> bipartite_quiver(2, 3).adjacency -5×5 Matrix{Int64}: - 0 0 1 1 1 - 0 0 1 1 1 - 0 0 0 0 0 - 0 0 0 0 0 - 0 0 0 0 0 +julia> print(bipartite_quiver(2, 3).adjacency) +[0 0 1 1 1; 0 0 1 1 1; 0 0 0 0 0; 0 0 0 0 0; 0 0 0 0 0] ``` """ function bipartite_quiver(m::Int, n::Int) @@ -292,7 +287,7 @@ opposite of 2-Kronecker quiver ``` """ opposite_quiver(Q::Quiver) = Quiver( - Matrix{Int}(transpose(Q.adjacency)), "opposite of " * Q.name + transpose(Q.adjacency), "opposite of " * Q.name ) """ @@ -315,7 +310,7 @@ double of 2-Kronecker quiver ``` """ double_quiver(Q::Quiver) = Quiver( - Q.adjacency + Matrix{Int}(transpose(Q.adjacency)), "double of " * Q.name + Q.adjacency + transpose(Q.adjacency), "double of " * Q.name ) """ diff --git a/src/Hodge.jl b/src/Hodge.jl index 264598c..b65989c 100644 --- a/src/Hodge.jl +++ b/src/Hodge.jl @@ -58,7 +58,11 @@ Cardinality of general linear group ``\\mathrm{GL}_n(\\mathbb{F}_v)``. if n == 0 return 1 else - return prod(q^n - q^i for i in 0:(n - 1)) + out = q^n - 1 + for i in 1:(n - 1) + out *= q^n - q^i + end + return out end end @@ -67,7 +71,7 @@ Cardinality of representation space ``\\mathrm{R}(Q,d), over \\mathbb{F}_q``. """ function CardinalRd(Q::Quiver, d::AbstractVector{Int}, q) return q^sum( - d[i] * d[j] * Q.adjacency[i, j] for i in 1:n_vertices(Q), j in 1:n_vertices(Q) + d[i] * d[j] * Q.adjacency[i, j] for i in 1:n_vertices(Q), j in 1:n_vertices(Q); init=0 ) end @@ -147,6 +151,19 @@ julia> theta = [3, -2]; julia> hodge_polynomial(Q, d, theta) x^6*y^6 + x^5*y^5 + 3*x^4*y^4 + 3*x^3*y^3 + 3*x^2*y^2 + x*y + 1 ``` + +Cases on a fake wall: +```jldoctest +julia> Q = Quiver([0 1 1 0; 0 0 1 0; 0 0 0 1; 0 0 0 0]); d = [3, 3, 4, 1]; + +julia> hodge_polynomial(Q, d) +x^3*y^3 + 3*x^2*y^2 + 3*x*y + 1 + +julia> Q = Quiver([0 1 0 1 0; 0 0 1 0 2; 0 0 0 1 0; 0 0 0 0 0; 0 0 0 0 0]); d = [1, 2, 1, 1, 1]; + +julia> hodge_polynomial(Q, d) +x^3*y^3 + 4*x^2*y^2 + 4*x*y + 1 + """ function hodge_polynomial( Q::Quiver, @@ -155,11 +172,12 @@ function hodge_polynomial( ) # safety checks - if theta' * d == 0 && !is_coprime(d) - throw(ArgumentError("d is not coprime")) - elseif !is_acyclic(Q) - throw(ArgumentError("Q is not acyclic.")) - end + !is_acyclic(Q) && throw(ArgumentError("Q is not acyclic.")) + has_properly_semistables(Q, d, theta) && throw( + ArgumentError( + "The quiver moduli problem has properly semistable representations, no description of the Hodge polynomial is known." + ), + ) R, q = polynomial_ring(Singular.QQ, ["q"]) F = fraction_field(R) @@ -327,6 +345,7 @@ function picard_rank(M::QuiverModuliSpace) return betti_numbers(M)[3] end +# TODO test the git_equivalence features """ index(M::QuiverModuliSpace) @@ -367,14 +386,17 @@ julia> index(M) ``` """ function index(M::QuiverModuliSpace) - !git_equivalent(M.Q, M.d, M.theta, canonical_stability(M.Q, M.d)) && - throw(ArgumentError("Only implemented for canonical stability.")) - if is_coprime(M.d, M.theta) && is_amply_stable(M) - return gcd(M.theta) - end - throw( - ArgumentError("Index computation requires ample stability and `theta`-coprimality.") + has_properly_semistables(M.Q, M.d, M.theta, M.denom) && throw( + ArgumentError( + "The quiver moduli problem has properly semistable representations, no description of the Mukai index is known." + ), + ) + !is_amply_stable(M) && throw( + ArgumentError( + "The quiver moduli problem is not amply stable, no description of the Mukai index is known." + ), ) + return gcd(canonical_stability(M.Q, M.d)) end """ diff --git a/src/Misc.jl b/src/Misc.jl index f291cf0..82b509f 100644 --- a/src/Misc.jl +++ b/src/Misc.jl @@ -7,9 +7,13 @@ Return the identity matrix of size `n`. """ -identity_matrix(n::Int) = map( - ind -> ind[1] == ind[2] ? 1 : 0, Iterators.product(1:n, 1:n) -) +@memoize function identity_matrix(n::Int) + out = zeros(Int, n, n) + for i in 1:n + out[i, i] = 1 + end + return coerce_matrix(out) +end """ diagonal(m::AbstractMatrix{Int}) @@ -151,15 +155,32 @@ function all_subdimension_vectors( d::AbstractVector{Int}; nonzero::Bool=false, strict::Bool=false, -) #TODO should this be memoized at all? - subdims = reshape( - collect.(collect(Iterators.product(map(di -> 0:di, d)...))), - prod(di + 1 for di in d; init=1), - ) - all(di == 0 for di in d) && (nonzero || strict) && return deleteat!(subdims, 1) - nonzero && deleteat!(subdims, 1) - strict && pop!(subdims) - return subdims +) + @assert length(d) > 0 "Input vector must have positive length." + if length(d) == 1 + if d[1] == 0 && (nonzero || strict) + return Vector{Int}[] + elseif d[1] == 0 && !(nonzero || strict) + return [[0]] + else + out = map(i -> [i], 0:d[1]) + nonzero && deleteat!(out, 1) + strict && pop!(out) + return out + end + else + subdims = all_subdimension_vectors(d[2:end]; nonzero=false, strict=false) + new_subdims = Vector{Vector{Int}}() + for subdim in subdims + for i in 0:d[1] + push!(new_subdims, vcat(i, subdim)) + end + end + all(di == 0 for di in d) && (nonzero || strict) && return deleteat!(new_subdims, 1) + nonzero && deleteat!(new_subdims, 1) + strict && pop!(new_subdims) + return new_subdims + end end """ @@ -228,4 +249,4 @@ true unit_vector(Q::Quiver, i::Int) = unit_vector(n_vertices(Q), i) coerce_vector(v) = v -coerce_matrix(m) = m +coerce_matrix(m) = SMatrix{size(m, 1),size(m, 1)}(m) diff --git a/src/Moduli.jl b/src/Moduli.jl index 6a73516..29f353f 100644 --- a/src/Moduli.jl +++ b/src/Moduli.jl @@ -258,7 +258,7 @@ Luna types for a 3-Kronecker quiver: julia> Q = kronecker_quiver(3); M = QuiverModuliSpace(Q, [3, 3]); julia> all_luna_types(M) -5-element Vector{LunaType{2}}: +5-element Vector{LunaType}: Dict([3, 3] => [1]) Dict([1, 1] => [1], [2, 2] => [1]) Dict([1, 1] => [3]) @@ -297,7 +297,7 @@ Keyword arguments: julia> Q = kronecker_quiver(3); M = QuiverModuliSpace(Q, [3, 3]); julia> all_luna_types(M) -5-element Vector{LunaType{2}}: +5-element Vector{LunaType}: Dict([3, 3] => [1]) Dict([1, 1] => [1], [2, 2] => [1]) Dict([1, 1] => [3]) @@ -307,11 +307,11 @@ julia> all_luna_types(M) julia> X = QuiverModuliSpace(Q, [2, 3]); julia> all_luna_types(X) -1-element Vector{LunaType{2}}: +1-element Vector{LunaType}: Dict([2, 3] => [1]) ``` """ -function all_luna_types( +@memoize Dict function all_luna_types( Q::Quiver, d::AbstractVector{Int}, theta::AbstractVector{Int}=canonical_stability(Q, d), @@ -328,14 +328,14 @@ function all_luna_types( filter!(e -> slope(e, theta, denom) == μ, same_slope) filter!(e -> has_stables(Q, e, theta, denom), same_slope) - luna_types = LunaType{n_vertices(Q)}[] + luna_types = LunaType[] for e in same_slope for luna_type in all_luna_types(Q, d - e, theta, denom; stable=true) if haskey(luna_type, e) for i in eachindex(luna_type[e]) push!(luna_types, __add_and_return(luna_type, e, i)) end - push!(luna_types, __add_and_return(luna_type, e)) + push!(luna_types, __add_and_return_noniso(luna_type, e)) else push!(luna_types, __add_and_return_new(luna_type, e)) end @@ -374,14 +374,14 @@ function __add_and_return(luna_type, e, i) end """ - __add_and_return(luna_type, e) + __add_and_return_noniso(luna_type, e) Returns a new Luna type obtained by adding a new copy of the subdimension vector `e` in the given Luna type. Internal use only. """ -function __add_and_return(luna_type, e) +function __add_and_return_noniso(luna_type, e) new_luna_type = deepcopy(luna_type) pushfirst!(new_luna_type[e], 1) return new_luna_type @@ -476,7 +476,7 @@ moduli space. julia> Q = kronecker_quiver(2); M = QuiverModuliSpace(Q, [2, 2], [1, -1]); julia> luna = all_luna_types(M) -2-element Vector{LunaType{2}}: +2-element Vector{LunaType}: Dict([1, 1] => [2]) Dict([1, 1] => [1, 1]) @@ -708,9 +708,7 @@ true function is_smooth(M::QuiverModuliSpace) if M.condition == "stable" return true - elseif is_coprime(M.d, M.theta) - return true - elseif semistable_equals_stable(M) + elseif !has_properly_semistables(M.Q, M.d, M.theta, M.denom) return true end @@ -771,13 +769,15 @@ true function is_projective(M::QuiverModuli) if is_acyclic(M.Q) M.condition == "semistable" && return true - M.condition == "stable" && return semistable_equals_stable(M) + M.condition == "stable" && return !has_properly_semistables(M.Q, M.d, M.theta, M.denom) end SSP = semisimple_moduli_space(M) M.condition == "semistable" && return dimension(SSP) in [0, -Inf] M.condition == "stable" && - return (dimension(SSP) in [1, -Inf] && semistable_equals_stable(M)) + return ( + dimension(SSP) in [1, -Inf] && !has_properly_semistables(M.Q, M.d, M.theta, M.denom) + ) end """ diff --git a/src/QuiverTools.jl b/src/QuiverTools.jl index 28f0dec..615ac02 100644 --- a/src/QuiverTools.jl +++ b/src/QuiverTools.jl @@ -7,6 +7,7 @@ using Memoization: Memoization using IterTools: IterTools using LinearAlgebraX: LinearAlgebraX using Combinatorics +using StaticArrays using Singular: Singular using Oscar: Oscar @@ -52,7 +53,8 @@ export kronecker_moduli, subspace_quiver_moduli # Stability export canonical_stability, is_coprime, slope export all_hn_types, - is_hn_type, has_semistables, has_stables, codimension_hn_stratum, is_amply_stable + is_hn_type, has_semistables, has_stables, has_properly_semistables, + codimension_hn_stratum, is_amply_stable export is_general_subdimension_vector, all_general_subdimension_vectors # Representation theory diff --git a/src/RepresentationTheory.jl b/src/RepresentationTheory.jl index 2f1fb7a..48bd9eb 100644 --- a/src/RepresentationTheory.jl +++ b/src/RepresentationTheory.jl @@ -65,6 +65,7 @@ true """ euler_form(Q::Quiver, x::AbstractVector{Int}, y::AbstractVector{Int}) = x' * euler_matrix(Q) * y +# TODO apparently 95% of the time here is spent retrieving the Euler matrix from the cache. ######################################################################################## # Canonical decomposition diff --git a/src/Stability.jl b/src/Stability.jl index a4cebdd..a7dfb05 100644 --- a/src/Stability.jl +++ b/src/Stability.jl @@ -167,10 +167,8 @@ function all_destabilizing_subdimension_vectors( all(di == 0 for di in d) && return Vector{Int}[] b = slope(d, theta, denom) - return filter( - e -> slope(e, theta, denom) > b, - all_subdimension_vectors(d; nonzero=true, strict=true), - ) + subs = all_subdimension_vectors(d; nonzero=true, strict=true) + return filter!(e -> slope(e, theta, denom) > b, subs) end """ @@ -717,8 +715,18 @@ function is_amply_stable( Q::Quiver, d::AbstractVector{Int}, theta::AbstractVector{Int}, - denom::Function=sum, ) - hn_types = all_hn_types(Q, d, theta, denom; unstable=true, ordered=false) + hn_types = all_hn_types(Q, d, theta; unstable=true, ordered=false) return all(stratum -> codimension_hn_stratum(Q, stratum) >= 2, hn_types) end + +""" + has_properly_semistables(Q::Quiver, d::Vector{Int}, theta::Vector{Int}, denom::Function=sum) + +""" +function has_properly_semistables( + Q::Quiver, d::AbstractVector{Int}, theta::AbstractVector{Int}, denom::Function=sum +) + is_coprime(d, theta) && return false + return !isempty(all_luna_types(Q, d, theta, denom; stable=false)) +end diff --git a/src/Teleman.jl b/src/Teleman.jl index 0828cdb..e0b7142 100644 --- a/src/Teleman.jl +++ b/src/Teleman.jl @@ -147,7 +147,7 @@ A dictionary with the weights of the 1-PS corresponding to each HN type. julia> Q = kronecker_quiver(3); julia> teleman_bounds(Q, [2, 3], [3, -2]) -Dict{HNType{2}, Int64} with 7 entries: +Dict{HNType, Int64} with 7 entries: [[2, 2], [0, 1]] => 20 [[2, 1], [0, 2]] => 50 [[1, 0], [1, 2], [0, 1]] => 100 @@ -253,9 +253,10 @@ function weights_universal_bundle( denom::Function=sum; chi::AbstractVector{Int}, ) - !is_coprime(d, theta) && - throw(ArgumentError("$(d) is not $(theta)-coprime, universal bundles do not exist.")) - + gcd(d) > 1 && + throw( + ArgumentError("gcd($(M.d)) = $(gcd(d)) > 1, the universal bundles do not exist.") + ) hn_types = all_hn_types(Q, d, theta, denom; unstable=true) return Dict( hn_type => weights_universal_bundle_on_stratum(hn_type, i, theta, denom; chi=chi) @@ -289,7 +290,7 @@ The weights of the universal bundles on our favourite 6-fold: julia> Q = kronecker_quiver(3); M = QuiverModuliSpace(Q, [2, 3]); julia> weights_universal_bundle(M, 1; chi=[2, -1]) -Dict{HNType{2}, Vector{Int64}} with 7 entries: +Dict{HNType, Vector{Int64}} with 7 entries: [[2, 2], [0, 1]] => [-5, -5] [[2, 1], [0, 2]] => [-10, -10] [[1, 0], [1, 2], [0, 1]] => [-15, -25] @@ -306,7 +307,7 @@ defaults to `extended_gcd(M.d)[2]` if not defined. julia> Q = kronecker_quiver(3); M = QuiverModuliSpace(Q, [2, 3]); julia> weights_universal_bundle(M, 1) -Dict{HNType{2}, Vector{Int64}} with 7 entries: +Dict{HNType, Vector{Int64}} with 7 entries: [[2, 2], [0, 1]] => [5, 5] [[2, 1], [0, 2]] => [10, 10] [[1, 0], [1, 2], [0, 1]] => [25, 15] @@ -318,7 +319,7 @@ Dict{HNType{2}, Vector{Int64}} with 7 entries: julia> QuiverTools.set_linearization!(M, [-4, 3]); julia> weights_universal_bundle(M, 1) -Dict{HNType{2}, Vector{Int64}} with 7 entries: +Dict{HNType, Vector{Int64}} with 7 entries: [[2, 2], [0, 1]] => [15, 15] [[2, 1], [0, 2]] => [30, 30] [[1, 0], [1, 2], [0, 1]] => [65, 55] @@ -409,8 +410,18 @@ function weights_canonical_bundle( theta::AbstractVector{Int}, denom::Function=sum, ) - !(is_coprime(d, theta) && is_amply_stable(Q, d, theta)) && - throw(ArgumentError("$(d) is not $(theta)-coprime and amply stable.")) + has_properly_semistables(Q, d, theta, denom) && + throw( + ArgumentError( + "The quiver moduli problem has properly semistables, no description of the canonical bundle is available." + ), + ) + !is_amply_stable(Q, d, theta) && + throw( + ArgumentError( + "The quiver moduli problem is not amply stable, no description of the canonical bundle is available." + ), + ) return weights_line_bundle(Q, d, -canonical_stability(Q, d), theta, denom) end @@ -435,7 +446,7 @@ The canonical bundle of our favourite 6-fold: julia> Q = kronecker_quiver(3); M = QuiverModuliSpace(Q, [2, 3]); julia> weights_canonical_bundle(M) -Dict{HNType{2}, Vector{Int64}} with 7 entries: +Dict{HNType, Vector{Int64}} with 7 entries: [[2, 2], [0, 1]] => [30] [[2, 1], [0, 2]] => [60] [[1, 0], [1, 2], [0, 1]] => [120] @@ -497,8 +508,10 @@ function all_weights_endomorphisms_universal_bundle( theta::AbstractVector{Int}, denom::Function=sum, ) - !is_coprime(d, theta) && - throw(ArgumentError("$(d) is not $(theta)-coprime, universal bundles do not exist.")) + gcd(d) > 1 && throw( + ArgumentError("gcd($(M.d)) = $(gcd(d)) > 1, the universal bundles do not exist.") + ) + hn_types = all_hn_types(Q, d, theta, denom; unstable=true) return Dict( hn_type => weights_endomorphism_universal_bundle_on_stratum(hn_type, theta, denom) for @@ -520,7 +533,7 @@ The weights of the endomorphisms of the universal bundles on our favourite 6-fol julia> Q = kronecker_quiver(3); M = QuiverModuliSpace(Q, [2, 3]); julia> all_weights_endomorphisms_universal_bundle(M) -Dict{HNType{2}, Vector{Int64}} with 7 entries: +Dict{HNType, Vector{Int64}} with 7 entries: [[2, 2], [0, 1]] => [0, 5, -5, 0] [[2, 1], [0, 2]] => [0, 5, -5, 0] [[1, 0], [1, 2], [0, 1]] => [0, 10, 15, -10, 0, 5, -15, -5, 0] @@ -647,13 +660,13 @@ end ##################################################################################### """ - set_teleman_weights!(F::Bundle, weights::Dict{<:HNType,Vector{Int}}) + set_teleman_weights!(F::Bundle, weights::Dict{HNType,Vector{Int}}) Set the Teleman weights of the bundle `F` to the given dictionary. This is used to construct Bundle objects and assign them Teleman weights. """ -function set_teleman_weights!(F::Bundle, weights::Dict{<:HNType,Vector{Int}}) +function set_teleman_weights!(F::Bundle, weights::Dict{HNType,Vector{Int}}) r = isdefined(F, :rank) ? F.rank : length(first(values(weights))) !all(length(v) == r for v in values(weights)) && throw(ArgumentError("Weights are not consistent with rank.")) diff --git a/src/Types.jl b/src/Types.jl index 7392587..0155259 100644 --- a/src/Types.jl +++ b/src/Types.jl @@ -5,7 +5,7 @@ """ # Summary -`struct Quiver` +`struct Quiver{T}` A quiver is represented by its adjacency ``n \\times n`` matrix ``adjacency = (a_{ij})``,\\ @@ -18,7 +18,7 @@ and ``a_{ij}`` is the number of arrows ``i \\to j``. `name :: String` """ -struct Quiver +struct Quiver{T} adjacency::AbstractMatrix{Int} name::String @@ -39,7 +39,9 @@ struct Quiver function Quiver(adjacency::AbstractMatrix{Int}, name::String="") size(adjacency, 1) != size(adjacency, 2) && throw(ArgumentError("adjacency matrix must be square")) - return new(adjacency, name) + adj = coerce_matrix(adjacency) + T = size(adjacency, 1) + return new{T}(adj, name) end """ @@ -289,20 +291,19 @@ end """ # Summary -`struct HNType{T}` +`struct HNType` A struct for a Harder-Narasimhan type. # Fields - `hn :: Vector{SVector{T,Int}}`\\ + `hn :: Vector{AbstractVector{Int}}`\\ """ -struct HNType{T} +struct HNType hn::Vector{Vector{Int}} function HNType(dstar::Vector{<:AbstractVector{Int}}) - T = length(dstar[1]) - return new{T}(coerce_vector.(dstar)) + return new(coerce_vector.(dstar)) end end @@ -369,7 +370,7 @@ function Bundle(parent::ChowRing, rank::Int, chern_class::Singular.spoly{Singula bundle = Bundle() setfield!(bundle, :parent, parent) setfield!(bundle, :rank, rank) - hom = homogeneous_components(parent.parent, chern_class) + hom = __homogeneous_components(parent.parent, chern_class) cl = Dict{Int,Singular.spoly{Singular.n_Q}}(i => hom[i + 1] for i in 0:n) setfield!(bundle, :chern_class, cl) return bundle @@ -416,7 +417,7 @@ function Bundle(M::QuiverModuliSpace, rank::Int, x::Singular.spoly{Singular.n_Q} bundle = Bundle() setfield!(bundle, :parent, M.chow) setfield!(bundle, :rank, rank) - hom = homogeneous_components(M, x) + hom = __homogeneous_components(M, x) cl = Dict{Int,Singular.spoly{Singular.n_Q}}(i => hom[i + 1] for i in 0:dimension(M)) setfield!(bundle, :chern_class, cl) return bundle @@ -434,7 +435,7 @@ function Bundle(M::QuiverModuliSpace, rank::Int, x::Vector{Singular.spoly{Singul bundle = Bundle() setfield!(bundle, :parent, M.chow) setfield!(bundle, :rank, rank) - hom = homogeneous_components(M, sum(x)) + hom = __homogeneous_components(M, sum(x)) cl = Dict{Int,Singular.spoly{Singular.n_Q}}(i => hom[i + 1] for i in 0:dimension(M)) setfield!(bundle, :chern_class, x) return bundle @@ -454,22 +455,22 @@ end """ # Summary -`struct LunaType{T}` +`struct LunaType` A struct to encode Luna types. # Fields - `data :: Dict{Vector{Int},Vector{Int}`\\ + `data :: Dict{AbstractVector{Int},AbstractVector{Int}}`\\ """ -struct LunaType{T} +struct LunaType data::Dict{Vector{Int},Vector{Int}} function LunaType(new_luna::Dict{<:AbstractVector{Int},Vector{Int}}) - T = length(collect(keys(new_luna))[1]) + # T = length(collect(keys(new_luna))[1]) - return new{T}(Dict(coerce_vector(tau) => new_luna[tau] for tau in keys(new_luna))) + return new(Dict(coerce_vector(tau) => new_luna[tau] for tau in keys(new_luna))) end end diff --git a/src/WallsAndChambers.jl b/src/WallsAndChambers.jl index 2cd1845..4dc3dfd 100644 --- a/src/WallsAndChambers.jl +++ b/src/WallsAndChambers.jl @@ -136,15 +136,17 @@ to not include the outer walls. ```jldoctests julia> Q = Quiver("1-2,2-3,3-4,1-3,1-4"); d = [1, 1, 1, 1]; -julia> map(rays, vgit_walls(Q, d; inner=false, top_dimension=false)) -7-element Vector{Oscar.SubObjectIterator{Oscar.RayVector{Nemo.QQFieldElem}}}: - [[0, 0, 1, -1], [0, 1, -1, 0]] - [[0, 0, 1, -1], [1, 0, -1, 0]] - [[0, 0, 1, -1], [1, -1, 0, 0]] - [[1, 0, 0, -1], [1, -1, 0, 0]] - [[1, 0, -1, 0]] - [[1, 0, 0, -1], [0, 1, -1, 0]] - [[1, -1, 0, 0], [0, 1, -1, 0]] +julia> walls = vgit_walls(Q, d; inner=false, top_dimension=false); + +julia> map(QuiverTools.Oscar.dim, walls) +7-element Vector{Int64}: + 2 + 2 + 2 + 2 + 1 + 2 + 2 ``` """ @memoize Dict function vgit_walls(Q, d; inner=false, top_dimension=true) diff --git a/test/Project.toml b/test/Project.toml new file mode 100644 index 0000000..b327ab0 --- /dev/null +++ b/test/Project.toml @@ -0,0 +1,5 @@ +[deps] +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +QuiverTools = "dc2e10be-62a3-4315-9c95-46bb97ac152d" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"