Quantum Schubert calculus

For homogeneous spaces, quantum Chevalley allows to compute ordinary small quantum Schubert structure constants from root data, without stable-map localization. Here we implemented the formula in order to reconstruct all ordinary quantum products.

julia> R = root_system(:A, 6);

julia> S = [2, 3, 4, 5, 6]; # Correspond to the variety P^6

julia> Q = quantum_schubert_context(R, S); # this stores only the data needed to the Quantum Chevalley

julia> length(Q.representatives)  # number of vertices
7

julia> Q.novikov_degrees # one component of at most degree 7
1-element Vector{Int64}:
 7

julia> Q.representatives # minimal length elements of the Weyl group of G/P
7-element Vector{WeylGroupElem}:
 id
 s1
 s2 * s1
 s3 * s2 * s1
 s4 * s3 * s2 * s1
 s5 * s4 * s3 * s2 * s1
 s6 * s5 * s4 * s3 * s2 * s1

julia> Q.codimensions # the codimention of each representatives
7-element Vector{Int64}:
 0
 1
 2
 3
 4
 5
 6

julia> Q.representatives[1]
id

julia> Q.representatives[2]
s1

Let us compute the quantum product id * s1. The expected result is s1

julia> quantum_schubert_product(Q, 1, 2)
Dict{Tuple{Int64, Tuple{Vararg{Int64}}}, QQFieldElem} with 1 entry:
  (2, (0,)) => 1

The result is a dictionary with entries of the form: (vertex, degree) => c. It means the following: The quantum product is the sum of the entries in the form: $c\cdot \sigma_{vertex}\cdot q^{degree}$, where $\sigma_{vertex}$ is the Schubert class given by the vertex. Thus $s_1 = 1 \sigma_{2} q^0$ as expected. Let us try to compute $s_1^9=\sigma_3 * \sigma_7=q=1\cdot\sigma_2\cdot q^1$:

julia> quantum_schubert_product(Q, 3, 7)
Dict{Tuple{Int64, Tuple{Vararg{Int64}}}, QQFieldElem} with 1 entry:
  (2, (1,)) => 1

julia> quantum_schubert_coefficient(Q, 1, 7, 2, 1)
1

We can compute the entire multiplication table of a Schubert class, and store them in a file for later use.

julia> v = 2;

julia> products = all_quantum_schubert_products(Q, v) # compute all products of v
7-element Vector{Dict{Tuple{Int64, Tuple{Vararg{Int64}}}, BigInt}}:
 Dict((2, (0,)) => 1)
 Dict((3, (0,)) => 1)
 Dict((4, (0,)) => 1)
 Dict((5, (0,)) => 1)
 Dict((6, (0,)) => 1)
 Dict((7, (0,)) => 1)
 Dict((1, (1,)) => 1)

julia> products = serialize_quantum_schubert_products("filename.jls", Q, 2); # compute the product and store in a file

We can have it in form of a matrix, use the following. Use at_q1=true to impose q=1.

julia> M = quantum_schubert_matrix(products;  at_q1=false)
[0   0   0   0   0   0   q1]
[1   0   0   0   0   0    0]
[0   1   0   0   0   0    0]
[0   0   1   0   0   0    0]
[0   0   0   1   0   0    0]
[0   0   0   0   1   0    0]
[0   0   0   0   0   1    0]

julia> M = quantum_schubert_matrix(products;  at_q1=true)
[0   0   0   0   0   0   1]
[1   0   0   0   0   0   0]
[0   1   0   0   0   0   0]
[0   0   1   0   0   0   0]
[0   0   0   1   0   0   0]
[0   0   0   0   1   0   0]
[0   0   0   0   0   1   0]

API

GKMtools.QuantumSchubertContext — Type

Root data and a lazy cache for ordinary small quantum Schubert calculus. Construct with quantum_schubert_context. Basis indices are vertex indices; Novikov coordinates correspond to omitted_roots. Mutable caches are not thread-safe. Auxiliary equivariant values use QQ or GF(p), selected by the constructor.

source
GKMtools.quantum_schubert_context — Function
quantum_schubert_context(G; p=nothing, max_cache_entries=200_000)
quantum_schubert_context(R::RootSystem, levi_indices; p=nothing, max_cache_entries=200_000)

Prepare sparse quantum Chevalley data and lazy associativity reconstruction. The graph overload preserves vertex numbering. The root-system overload enumerates minimal coset representatives without a GKM graph or the ambient Weyl group; its ordering is by length and word. levi_indices are the simple roots retained in the parabolic, as in generalized_gkm_flag.

Omit p for exact rational computation, or supply a prime to reconstruct directly over GF(p). The prime must exceed the basis size and admit a separating equivariant specialization; invalid choices throw ArgumentError. Each memo is bounded by max_cache_entries (zero disables memorization). This limits retained cache entries, not total RAM.

source
GKMtools.quantum_chevalley_product — Function
quantum_chevalley_product(Q, simple_root_index, u)

Ordinary quantum product of sigma_u with the divisor for an omitted simple root. Returns a dictionary (vertex, degree_tuple) => coefficient over Q.field (QQ or GF(p)).

julia> R = root_system(:C, 3);

julia> S = [3];

julia> Q = quantum_schubert_context(R, S);

julia> Q.representatives[3]
s2

julia> quantum_chevalley_product(Q, 1, 3)
Dict{Tuple{Int64, Tuple{Vararg{Int64}}}, QQFieldElem} with 2 entries:
  (5, (0, 0)) => 1
  (4, (0, 0)) => 1

julia> quantum_chevalley_product(Q, 2, 3)
Dict{Tuple{Int64, Tuple{Vararg{Int64}}}, QQFieldElem} with 2 entries:
  (4, (0, 0)) => 1
  (6, (0, 0)) => 1
source
GKMtools.quantum_schubert_coefficient — Function
quantum_schubert_coefficient(Q, u, v, w, degree=0)

Return the ordinary coefficient of q^degree sigma_w in sigma_u ⋆ sigma_v. Degrees are nonnegative tuples ordered by Q.omitted_roots; an integer is accepted for Picard rank one (zero for any rank).

julia> R = root_system(:C, 3);

julia> Q = quantum_schubert_context(R);

julia> quantum_schubert_coefficient(Q, 7, 6, 8, (1, 0, 0))
1

julia> quantum_schubert_coefficient(Q, 7, 6, 22, (0, 0, 0))
2

julia> quantum_schubert_product(Q, 7, 6)
Dict{Tuple{Int64, Tuple{Vararg{Int64}}}, QQFieldElem} with 4 entries:
  (22, (0, 0, 0)) => 2
  (8, (1, 0, 0))  => 1
  (24, (0, 0, 0)) => 1
  (9, (1, 0, 0))  => 1
source
GKMtools.quantum_schubert_product — Function
quantum_schubert_product(Q, u, v; max_degree=nothing)

Compute an ordinary quantum basis product as a sparse dictionary (output_vertex, degree_tuple) => coefficient over Q.field. By default all possible degrees are included. max_degree is an optional componentwise Novikov bound.

julia> R = root_system(:C, 3);

julia> S = [3];

julia> Q = quantum_schubert_context(R, S);

julia> quantum_schubert_product(Q, 5, 6)
Dict{Tuple{Int64, Tuple{Vararg{Int64}}}, QQFieldElem} with 3 entries:
  (13, (0, 0)) => 1
  (12, (0, 0)) => 1
  (14, (0, 0)) => 1

julia> quantum_schubert_product(Q, 6, 6)
Dict{Tuple{Int64, Tuple{Vararg{Int64}}}, QQFieldElem} with 3 entries:
  (13, (0, 0)) => 2
  (11, (0, 0)) => 2
  (1, (0, 1))  => 1
source
GKMtools.quantum_schubert_table — Function
quantum_schubert_table(Q; max_degree=nothing)

Compute every ordinary basis product. The dictionary stores pairs (u,v) with u <= v, each mapped to the sparse output of quantum_schubert_product. This can be large; individual products share the same lazy reconstruction cache.

julia> R = root_system(:A, 1);

julia> Q = quantum_schubert_context(R);

julia> quantum_schubert_table(Q)
Dict{Tuple{Int64, Int64}, Dict{Tuple{Int64, Tuple{Vararg{Int64}}}, QQFieldElem}} with 3 entries:
  (1, 2) => Dict((2, (0,))=>1)
  (1, 1) => Dict((1, (0,))=>1)
  (2, 2) => Dict((1, (1,))=>1)
source
GKMtools.serialize_quantum_schubert_products — Function
serialize_quantum_schubert_products(path, Q, u; show_bar=false)

Compute all ordinary quantum products sigma_u ⋆ sigma_v for fixed u, save them with Julia's Serialization.serialize, and return the saved vector.

The vector entry products[v] is a sparse dictionary (output_vertex, degree_tuple) => BigInt. Only this vector is stored: no graph, context, cache, representatives, or other metadata. Coefficients are native Julia integers, so loading does not require Oscar or GKMtools. Indices and degree coordinates retain the conventions of Q. For modular contexts, integers are residues in 0:Q.prime-1; the prime is not stored. Supply it when reconstructing a matrix from the saved vector.

Set show_bar=true to display progress over the second factor. All possible Novikov degrees are included. Computation finishes before the destination is opened; an existing file is overwritten.

Example

serialize_quantum_schubert_products("products-u3.jls", Q, 3)

using Serialization
products = deserialize("products-u3.jls")
products[2] # sigma_3 ⋆ sigma_2
source
GKMtools.quantum_schubert_matrix — Function
quantum_schubert_matrix(Q, u; at_q1=false)
quantum_schubert_matrix(products::AbstractVector; at_q1=false, p=nothing)

Return the matrix of quantum multiplication by sigma_u. Column v contains sigma_u ⋆ sigma_v: entry (w,v) is the sum of all coefficients c*q^d with output vertex w.

The first overload computes the complete product vector. The second accepts a vector loaded from serialize_quantum_schubert_products, without needing a context or graph. The matrix size is length(products). Supply p when loading modular residues: the result is over GF(p), or its Novikov polynomial ring. The context overload uses Q.prime automatically. The saved product vector contains no prime metadata.

By default the result is an Oscar matrix over QQ[q1,...,qr], with variables in the order of the degree tuples. Set at_q1=true to sum all Novikov degrees and return a matrix over QQ. An empty or entirely zero vector returns a zero matrix over the selected coefficient field, since no Novikov coordinates can be inferred.

Examples

julia> R = root_system(:C, 3);

julia> S = [1, 3];

julia> Q = quantum_schubert_context(R, S);

julia> Q.representatives[2]
s2

julia> M = quantum_schubert_matrix(Q, 2; at_q1=true)
[0   0   0   0   0   0   1   0   0   0   0   0]
[1   0   0   0   0   0   0   0   1   0   0   0]
[0   1   0   0   0   0   0   0   0   0   0   0]
[0   1   0   0   0   0   0   0   0   0   1   0]
[0   0   1   1   0   0   0   0   0   0   0   0]
[0   0   0   1   0   0   0   0   0   0   0   1]
[0   0   0   0   1   2   0   0   0   0   0   0]
[0   0   0   0   2   1   0   0   0   0   0   0]
[0   0   0   0   0   0   1   1   0   0   0   0]
[0   0   0   0   0   0   0   1   0   0   0   0]
[0   0   0   0   0   0   0   0   1   1   0   0]
[0   0   0   0   0   0   0   0   0   0   1   0]

julia> chi = characteristic_polynomial(M)
x^12 - 26*x^7 - 27*x^2

julia> eigenvalues_with_multiplicities(algebraic_closure(QQ), M)
11-element Vector{Tuple{QQBarFieldElem, Int64}}:
 ({a5: 1.93318}, 1)
 ({a1: 0}, 2)
 ({a1: -1.00000}, 1)
 ({a4: 0.809017 + 0.587785*im}, 1)
 ({a4: 0.809017 - 0.587785*im}, 1)
 ({a5: 0.597386 + 1.83857*im}, 1)
 ({a5: 0.597386 - 1.83857*im}, 1)
 ({a4: -0.309017 + 0.951057*im}, 1)
 ({a4: -0.309017 - 0.951057*im}, 1)
 ({a5: -1.56398 + 1.13630*im}, 1)
 ({a5: -1.56398 - 1.13630*im}, 1)
source

Products without serialization