Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/src/methods/quiver-moduli.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Black-box methods are provided to study some of their properties.
is_nonempty
dimension
is_smooth
codimension_singular_locus
is_projective
index
motive
Expand Down
1 change: 1 addition & 0 deletions docs/src/methods/quivers.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ indegree
outdegree
is_acyclic
is_connected
strongly_connected_components
is_sink
is_source
underlying_graph
Expand Down
31 changes: 31 additions & 0 deletions docs/src/methods/representation-theory.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,34 @@ canonical_decomposition
in_fundamental_domain
first_hochschild_cohomology
```

## Invariant theory of quiver representations

The affine quotient of the representation variety by the base change group
parametrizes semisimple representations of the quiver, and its ring of functions is
the ring of invariants, generated by traces along oriented cycles.

A quiver setting is *coregular* if this ring of invariants is a polynomial ring, or
equivalently if the affine quotient is smooth (in which case it is an affine space).
This is decided by the reduction algorithm of
[[Bocklandt](https://mathscinet.ams.org/mathscinet/relay-station?mr=1929191)],
which simplifies a quiver setting without changing its invariant theory and then
compares the result against a short list.

A stronger property is *cofreeness*: the coordinate ring of the representation
variety is a graded free module over the ring of invariants, which by a criterion of
Popov amounts to coregularity together with equidimensionality of the nullcone.
Cofree quiver settings are classified by
[[Bocklandt--Van de Weyer](https://doi.org/10.1016/j.jalgebra.2007.08.019)].

Beyond deciding smoothness of the affine quotient itself, these notions drive the
study of moduli spaces of quiver representations: étale-locally around a polystable
representation, a moduli space is the affine quotient of a *local quiver setting*, so
coregularity of local quiver settings decides smoothness of moduli spaces; see
[`is_smooth`](@ref) and [`codimension_singular_locus`](@ref).

```@docs
bocklandt_reduction
is_coregular
is_cofree
```
8 changes: 8 additions & 0 deletions src/Misc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@
# Misc
######

# Shared validator for public quiver-setting functions that accept `(Q, d)` directly.
function __check_dimension_vector(Q::Quiver, d::AbstractVector{Int})
length(d) == n_vertices(Q) ||
throw(ArgumentError("dimension vector must have length $(n_vertices(Q))"))
all(>=(0), d) || throw(ArgumentError("dimension vector must be non-negative"))
return nothing
end

"""
identity_matrix(n::Int)

Expand Down
127 changes: 117 additions & 10 deletions src/Moduli.jl
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,19 @@ function is_luna_type(M::QuiverModuli, tau)
return tau == Dict(M.d => [1])
end

# A nonzero Luna type has at least one nonzero dimension vector of the correct length,
# and every dimension vector has a nonempty list of positive multiplicities.
ks = collect(keys(tau))
isempty(ks) && return false
if !all(
e -> length(e) == n_vertices(M.Q) && all(>=(0), e) && any(>(0), e),
ks,
)
return false
end
if !all(e -> !isempty(tau[e]) && all(>(0), tau[e]), ks)
return false
end
# each key `e` contributes `sum(tau[e])` copies of `e` (one per multiplicity in its list)
if sum(sum(tau[e]) * e for e in ks) != M.d
return false
Expand All @@ -469,10 +481,12 @@ function is_luna_type(M::QuiverModuli, tau)
return false
end

if !all(has_semistables(M.Q, e, M.theta, M.denom) for e in ks)
if !all(has_stables(M.Q, e, M.theta, M.denom) for e in ks)
return false
end
return true
# A rigid stable representation is unique up to isomorphism, so its dimension
# vector cannot encode several distinct stable summands in one Luna type.
return all(e -> length(tau[e]) == 1 || euler_form(M.Q, e, e) <= 0, ks)
end

"""
Expand Down Expand Up @@ -513,6 +527,8 @@ julia> dimension_of_luna_stratum(M, Dict([0, 0] => [1]))
```
"""
function dimension_of_luna_stratum(M::QuiverModuli, tau)
is_luna_type(M, tau) ||
throw(DomainError(tau, "not a Luna type for the given moduli problem"))
# the formula below would give 1 for the zero dimension vector
sum(M.d) == 0 && return 0
return sum(length(tau[e]) * (1 - euler_form(M.Q, e, e)) for e in collect(keys(tau)))
Expand All @@ -530,11 +546,13 @@ Returns the local quiver and dimension vector for the given Luna type.

# Output

- a dictionary with the local quiver `Q` and dimension vector `d` for the given Luna type.
- a named tuple `(Q, d, summands)` containing the local quiver, its dimension vector,
and the dimension vectors of the stable summands, one for each vertex of the local
quiver, ordered compatibly with `d`.
"""
function local_quiver_setting(M::QuiverModuli, tau)
if !is_luna_type(M, tau)
throw(DomainError("Not a Luna type"))
throw(DomainError(tau, "not a Luna type for the given moduli problem"))
end

# one local vertex per distinct stable summand, i.e. per entry of each multiplicity list;
Expand All @@ -549,7 +567,14 @@ function local_quiver_setting(M::QuiverModuli, tau)
Qloc = Quiver(A)
dloc = [m for e in keys(tau) for m in tau[e]]

return Dict("Q" => Qloc, "d" => dloc)
return (Q=Qloc, d=dloc, summands=summands)
end

# whether the local quiver setting of the Luna type is coregular, i.e., whether the
# moduli space is smooth along the corresponding stratum
function __is_smooth_stratum(M::QuiverModuli, tau)
setting = local_quiver_setting(M, tau)
return is_coregular(setting.Q, setting.d)
end

"""
Expand Down Expand Up @@ -726,7 +751,7 @@ end
function _dimension(M::QuiverModuliSpace)
# the zero representation is semistable, but not stable, for d = 0
!is_connected(M.Q) &&
raise(ArgumentError("Q is not connected, M has disjoint connected components."))
throw(ArgumentError("Q is not connected, M has disjoint connected components."))

if all(M.d .== 0)
if M.condition == "semistable"
Expand All @@ -746,10 +771,10 @@ function _dimension(M::QuiverModuliSpace)
if M.condition == "stable"
return -Inf
elseif M.condition == "semistable"
if has_semistables(M.Q, M.d, M.theta)
if has_semistables(M.Q, M.d, M.theta, M.denom)
return maximum(
dimension_of_luna_stratum(M, tau) for
tau in all_luna_types(M.Q, M.d, M.theta)
tau in all_luna_types(M.Q, M.d, M.theta, M.denom)
)
end
end
Expand All @@ -762,6 +787,15 @@ end

Checks if the moduli space is smooth.

In the presence of properly semistable representations, the moduli space is
étale-locally isomorphic, around a polystable representation, to the affine quotient of
the corresponding local quiver setting near the zero representation, by
[[MR1972892](https://mathscinet.ams.org/mathscinet/relay-station?mr=1972892)].
Following the strategy of
[[Theorem 4.2, MR1929191](https://mathscinet.ams.org/mathscinet/relay-station?mr=1929191)],
the moduli space is thus smooth if and only if the local quiver setting of every Luna
type is coregular, which is checked using [`is_coregular`](@ref).

# Input

- `M::QuiverModuliSpace`: a moduli space of representations of a quiver.
Expand All @@ -776,6 +810,26 @@ Setups with `d` `theta`-coprime are smooth:
```jldoctest
julia> Q = kronecker_quiver(3); M = QuiverModuliSpace(Q, [2, 3]);

julia> is_smooth(M)
true
```

For the 3-Kronecker quiver and `d = (3, 3)` the moduli space is singular, whereas for
`d = (2, 2)` and `d = (2, 4)` one gets ``\\mathbb{P}^5``, despite the presence of
properly semistable representations:
```jldoctest
julia> M = QuiverModuliSpace(kronecker_quiver(3), [3, 3]);

julia> is_smooth(M)
false

julia> M = QuiverModuliSpace(kronecker_quiver(3), [2, 2]);

julia> is_smooth(M)
true

julia> M = QuiverModuliSpace(kronecker_quiver(3), [2, 4]);

julia> is_smooth(M)
true
```
Expand All @@ -787,15 +841,68 @@ function is_smooth(M::QuiverModuliSpace)
return true
end

throw(NotImplementedError("Not implemented for properly semistable cases."))
# smoothness at the polystable points of a Luna stratum is equivalent to
# coregularity of its local quiver setting, by combining the étale-local description
# of [MR1972892] with [Theorem 2.1, MR1929191]; this is the globalization of
# [Theorem 4.2, MR1929191] to arbitrary stability parameters
return all(tau -> __is_smooth_stratum(M, tau), all_luna_types(M))
end

"""
codimension_singular_locus(M::QuiverModuliSpace)

Computes the codimension of the singular locus of the moduli space.

The singular locus is a union of Luna strata: all points of the stratum of a Luna type
are singular if the corresponding local quiver setting is not coregular, and smooth
otherwise, as in [`is_smooth`](@ref). Unlike for moduli of vector bundles on a curve,
the singular locus can be strictly smaller than the locus of properly semistable
representations, whose codimension is bounded by that of the singular locus.

# Input

- `M::QuiverModuliSpace`: a moduli space of representations of a quiver.

# Output

- the codimension of the singular locus, or `Inf` if the moduli space is smooth.

# Examples

The Segre cubic threefold, with its ten singular points:
```jldoctest
julia> M = QuiverModuliSpace(subspace_quiver(6), [1, 1, 1, 1, 1, 1, 2]);

julia> codimension_singular_locus(M)
3
```

For the 3-Kronecker quiver and `d = (2, 2)` the properly semistable locus is non-empty
yet the moduli space is smooth, whilst for `d = (3, 3)` there are singularities:
```jldoctest
julia> codimension_singular_locus(QuiverModuliSpace(kronecker_quiver(3), [2, 2]))
Inf

julia> codimension_singular_locus(QuiverModuliSpace(kronecker_quiver(3), [3, 3]))
3
```
"""
function codimension_singular_locus(M::QuiverModuliSpace)
M.condition == "stable" && return Inf

# the stratum of a Luna type consists of singular points if and only if its local
# quiver setting is not coregular; the stable stratum is always smooth
singular = filter(tau -> !__is_smooth_stratum(M, tau), all_luna_types(M))
isempty(singular) && return Inf
return dimension(M) - maximum(dimension_of_luna_stratum(M, tau) for tau in singular)
end

"""
is_smooth(M::QuiverModuliStack)

Checks if the moduli stack is smooth.

This is always trus, as the quotient stack of a smooth variety is smooth.
This is always true, as the quotient stack of a smooth variety is smooth.

# Input

Expand Down
10 changes: 6 additions & 4 deletions src/QuiverTools.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export Quiver, HNType, LunaType, QuiverModuli, QuiverModuliSpace, QuiverModuliSt
# Quivers
export n_vertices,
n_arrows, arrows, indegree, outdegree, is_acyclic, is_connected, is_sink, is_source,
underlying_graph, first_hochschild_cohomology
strongly_connected_components, underlying_graph, first_hochschild_cohomology

# Constructors
export kronecker_quiver, loop_quiver, jordan_quiver, subspace_quiver, star_quiver,
Expand All @@ -60,11 +60,13 @@ export is_general_subdimension_vector, all_general_subdimension_vectors
# Representation theory
export euler_form, euler_matrix, is_root, is_schur_root, is_real_root, is_imaginary_root,
is_isotropic_root,
general_ext, general_hom, canonical_decomposition, in_fundamental_domain
general_ext, general_hom, canonical_decomposition, in_fundamental_domain,
bocklandt_reduction, is_coregular, is_cofree

# Moduli
export all_luna_types, is_luna_type, dimension_of_luna_stratum
export is_nonempty, codimension_unstable_locus, dimension, is_smooth,
export is_nonempty, codimension_unstable_locus, codimension_singular_locus, dimension,
is_smooth,
is_projective, is_strongly_amply_stable, semistable_equals_stable, semisimple_moduli_space

# Hodge
Expand Down Expand Up @@ -133,9 +135,9 @@ end

include("Types.jl")
include("Quivers.jl")
include("Misc.jl")
include("Stability.jl")
include("RepresentationTheory.jl")
include("Misc.jl")
include("Constructors.jl")
include("Moduli.jl")
include("Hodge.jl")
Expand Down
49 changes: 49 additions & 0 deletions src/Quivers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,55 @@ function is_connected(Q::Quiver)
return all(p -> p > 0, paths)
end

"""
strongly_connected_components(Q::Quiver)

Compute the strongly connected components of `Q`.

Two vertices belong to the same strongly connected component if and only if
they are connected by paths in both directions. The reachability relation is
computed as the reflexive-transitive closure of the adjacency relation, using
Warshall's Boolean transitive-closure algorithm
[[Warshall](https://doi.org/10.1145/321105.321107)]; its ``O(n^3)`` running time
is not an issue for the quivers we consider.

# Input

- `Q::Quiver`: a quiver.

# Output

- a list of the strongly connected components, each given as the list of its vertices.

# Examples

```jldoctest
julia> strongly_connected_components(cyclic_quiver(4)) # 1 → 4 needs a path of length 3
1-element Vector{Vector{Int64}}:
[1, 2, 3, 4]

julia> strongly_connected_components(kronecker_quiver(3))
2-element Vector{Vector{Int64}}:
[1]
[2]

julia> strongly_connected_components(Quiver("1-2,2-1,2-3"))
2-element Vector{Vector{Int64}}:
[1, 2]
[3]
```
"""
function strongly_connected_components(Q::Quiver)
n = n_vertices(Q)
# `reachable[i, j]` records existence of a path, not the number of paths.
reachable = [i == j || Q.adjacency[i, j] > 0 for i in 1:n, j in 1:n]
# After the kth outer Warshall pass, paths may use any intermediate vertex in 1:k.
for k in 1:n, i in 1:n, j in 1:n
reachable[i, j] |= reachable[i, k] && reachable[k, j]
end
Comment thread
giannipetrella marked this conversation as resolved.
return unique([findall(j -> reachable[i, j] && reachable[j, i], 1:n) for i in 1:n])
end

"""
indegree(Q::Quiver, j::Int)

Expand Down
Loading