Skip to content

Commit

Permalink
[FTheoryTools] Compute all vertical and well-quantized G4-flux ambien…
Browse files Browse the repository at this point in the history
…t space candidates
  • Loading branch information
HereAround committed Nov 19, 2024
1 parent 23273f4 commit 271681c
Show file tree
Hide file tree
Showing 7 changed files with 404 additions and 0 deletions.
4 changes: 4 additions & 0 deletions experimental/FTheoryTools/docs/src/g4.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,7 @@ Please note that this method may take a long time to execute for involved geomet
```@docs
well_quantized_ambient_space_models_of_g4_fluxes(m::AbstractFTheoryModel; check::Bool = true)
```
Similarly, we have a method for all vertical and well-quantized ambient space $G_4$-flux candidates:
```@docs
well_quantized_and_vertical_ambient_space_models_of_g4_fluxes(m::AbstractFTheoryModel; check::Bool = true)
```
64 changes: 64 additions & 0 deletions experimental/FTheoryTools/src/G4Fluxes/auxiliary.jl
Original file line number Diff line number Diff line change
Expand Up @@ -225,3 +225,67 @@ function _ambient_space_divisor_pairs_to_be_considered(m::AbstractFTheoryModel):
return list_of_elements

end


# The following is an internal function, that is being used to identify all well-quantized and
# vertical G4-flux ambient candidates. For this, we look for pairs of (pushforwards of) base divisors,
# s.t. their common zero locus does not intersect the CY hypersurface trivially.
# This method makes a pre-selection of such base divisor pairs. "Pre" means that we execute a sufficient,
# but not necessary, check to tell if a pair of base divisors restricts trivially.

function _ambient_space_base_divisor_pairs_to_be_considered(m::AbstractFTheoryModel)::Vector{Tuple{Int64, Int64}}

if has_attribute(m, :_ambient_space_base_divisor_pairs_to_be_considered)
return get_attribute(m, :_ambient_space_base_divisor_pairs_to_be_considered)
end

gS = gens(cox_ring(ambient_space(m)))
mnf = Oscar._minimal_nonfaces(ambient_space(m))
ignored_sets = Set([Tuple(sort(Vector{Int}(Polymake.row(mnf, i)))) for i in 1:Polymake.nrows(mnf)])

list_of_elements = Vector{Tuple{Int64, Int64}}()
for k in 1:n_rays(base_space(m))
for l in k:n_rays(base_space(m))

# V(x_k, x_l) = emptyset?
(k,l) in ignored_sets && continue

# Simplify the hypersurface polynomial by setting relevant variables to zero.
# If all coefficients of this new polynomial add to sum, then we keep this generator.
new_p_hyper = divrem(hypersurface_equation(m), gS[k])[2]
if k != l
new_p_hyper = divrem(new_p_hyper, gS[l])[2]
end
if sum(coefficients(new_p_hyper)) == 0
push!(list_of_elements, (k,l))
continue
end

# Determine remaining variables, after scaling "away" others.
remaining_vars_list = Set(1:length(gS))
for my_exps in ignored_sets
len_my_exps = length(my_exps)
inter_len = count(idx -> idx in [k,l], my_exps)
if (len_my_exps == 2 && inter_len == 1) || (len_my_exps == 3 && inter_len == 2)
delete!(remaining_vars_list, my_exps[findfirst(idx -> !(idx in [k,l]), my_exps)])
end
end
remaining_vars_list = collect(remaining_vars_list)

# If one monomial of `new_p_hyper` has unset positions (a.k.a. new_p_hyper is not constant upon
# scaling the remaining variables), then keep this generator.
for exps in exponents(new_p_hyper)
if any(x -> x != 0, exps[remaining_vars_list])
push!(list_of_elements, (k,l))
break
end
end

end
end

# Remember this result as attribute and return the findings.
set_attribute!(m, :_ambient_space_base_divisor_pairs_to_be_considered, list_of_elements)
return list_of_elements

end
272 changes: 272 additions & 0 deletions experimental/FTheoryTools/src/G4Fluxes/special_attributes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -293,3 +293,275 @@ function well_quantized_ambient_space_models_of_g4_fluxes(m::AbstractFTheoryMode
return res

end


@doc raw"""
well_quantized_and_vertical_ambient_space_models_of_g4_fluxes(m::AbstractFTheoryModel; check::Bool = true)::Tuple{QQMatrix, QQMatrix}
Given an F-theory model $m$ defined as hypersurface in a simplicial and
complete toric base, this method computes a basis of all well-quantized
and vertical ambient space $G_4$-fluxes. The result of this operation is a
tuple of two matrices. The columns of the first matrix specify those (rational)
combinations of ambient space $G_4$-fluxes, of which one may only take
$\mathbb{Z}$-linear combinations without violating flux quantization. The columns
of the second matrix specify those (rational) combinations of ambient space
$G_4$-fluxes, for which any rational linear combination satisfies the flux
quantization condition.
It can be computationally very demanding to check if a toric variety
$X$ is complete (and simplicial). The optional argument `check` can be set
to `false` to skip these tests.
# Examples
```jldoctest; setup = :(Oscar.LazyArtifacts.ensure_artifact_installed("QSMDB", Oscar.LazyArtifacts.find_artifacts_toml(Oscar.oscardir)))
julia> B3 = projective_space(NormalToricVariety, 3)
Normal toric variety
julia> Kbar = anticanonical_divisor_class(B3)
Divisor class on a normal toric variety
julia> t = literature_model(arxiv_id = "1109.3454", equation = "3.1", base_space = B3, defining_classes = Dict("w"=>Kbar))
Construction over concrete base may lead to singularity enhancement. Consider computing singular_loci. However, this may take time!
Global Tate model over a concrete base -- SU(5)xU(1) restricted Tate model based on arXiv paper 1109.3454 Eq. (3.1)
julia> res = well_quantized_and_vertical_ambient_space_models_of_g4_fluxes(t, check = false);
julia> res[1]
2 by 0 empty matrix
julia> res[2]
2 by 0 empty matrix
```
"""
function well_quantized_and_vertical_ambient_space_models_of_g4_fluxes(m::AbstractFTheoryModel; check::Bool = true)::Tuple{QQMatrix, QQMatrix}

# (1) Entry checks
@req base_space(m) isa NormalToricVariety "Computation of well-quantized G4-fluxes only supported for toric base and ambient spaces"
@req dim(ambient_space(m)) == 5 "Computation of well-quantized G4-fluxes only supported for 5-dimensional toric ambient spaces"
if check
@req is_complete(ambient_space(m)) "Computation of well-quantized G4-fluxes only supported for complete toric ambient spaces"
@req is_simplicial(ambient_space(m)) "Computation of well-quantized G4-fluxes only supported for simplicial toric ambient space"
end
if has_attribute(m, :well_quantized_and_vertical_ambient_space_models_of_g4_fluxes)
return get_attribute(m, :well_quantized_and_vertical_ambient_space_models_of_g4_fluxes)
end


# (2) Compute data, that is frequently used by the sophisticated intersection product below
S = cox_ring(ambient_space(m))
gS = gens(cox_ring(ambient_space(m)))
linear_relations = matrix(QQ, matrix(ZZ, rays(ambient_space(m))))
scalings = [c.coeff for c in S.d]
mnf = Oscar._minimal_nonfaces(ambient_space(m))
sr_ideal_pos = [Vector{Int}(Polymake.row(mnf, i)) for i in 1:Polymake.nrows(mnf)]
data = (
S = S,
gS = gS,
linear_relations = linear_relations,
scalings = scalings,
sr_ideal_pos = sr_ideal_pos
)


# (3) Are intersection numbers known?
inter_dict = Dict{NTuple{4, Int64}, QQFieldElem}()
s_inter_dict = Dict{String, QQFieldElem}()
if has_attribute(m, :inter_dict)
inter_dict = get_attribute(m, :inter_dict)
end
if has_attribute(m, :s_inter_dict)
s_inter_dict = get_attribute(m, :s_inter_dict)
end


# (4) Obtain critical information - this may take significant time!
ambient_space_flux_candidates_basis = ambient_space_models_of_g4_fluxes(m, check = check)
list_of_base_divisor_pairs_to_be_considered = Oscar._ambient_space_base_divisor_pairs_to_be_considered(m)
list_of_divisor_pairs_to_be_considered = Oscar._ambient_space_divisor_pairs_to_be_considered(m)


# (5) Work out the relevant intersection numbers to tell if a flux is vertical
vertical_constraint_matrix = Vector{Vector{QQFieldElem}}()
if arxiv_doi(m) == "10.48550/arXiv.1511.03209"

# Use special intersection theory for special F-theory model. This technology could be extended beyond this one use-case in the future.
for i in 1:length(ambient_space_flux_candidates_basis)

condition = Vector{ZZRingElem}()
idxs = findall(x -> x != 0, collect(exponents(polynomial(ambient_space_flux_candidates_basis[i]).f))[1])
if length(idxs) == 1
idxs = [idxs[1], idxs[1]]
end

# Compute against pairs of base divisors
for j in 1:length(list_of_base_divisor_pairs_to_be_considered)

my_tuple = Tuple(sort([idxs..., list_of_base_divisor_pairs_to_be_considered[j]...]))
push!(condition, sophisticated_intersection_product(ambient_space(m), my_tuple, hypersurface_equation(m), inter_dict, s_inter_dict, data))

end

# Compute against zero section and base divisor
pos_zero_section = findfirst(x -> x == "z", string.(gS))
for j in 1:n_rays(base_space(m))

my_tuple = Tuple(sort([idxs..., [j, pos_zero_section]...]))
push!(condition, sophisticated_intersection_product(ambient_space(m), my_tuple, hypersurface_equation(m), inter_dict, s_inter_dict, data))

end

push!(vertical_constraint_matrix, condition)

end

else

# Cover all other case with generic, but potentially painfully slow methodology.
tds = torusinvariant_prime_divisors(ambient_space(m))
cds = [cohomology_class(tds[i]) for i in 1:length(tds)]
pt_class = cohomology_class(anticanonical_divisor_class(ambient_space(m)))
for i in 1:length(ambient_space_flux_candidates_basis)

condition = Vector{QQFieldElem}()

idxs = findall(x -> x != 0, collect(exponents(polynomial(ambient_space_flux_candidates_basis[i]).f))[1])
if length(idxs) == 1
idxs = [idxs[1], idxs[1]]
end

# Compute against pairs of base divisors
for j in 1:length(list_of_divisor_pairs_to_be_considered)

my_tuple = Tuple(sort([idxs..., list_of_divisor_pairs_to_be_considered[j]...]))
if !haskey(inter_dict, my_tuple)
class = ambient_space_flux_candidates_basis[i] * cds[list_of_divisor_pairs_to_be_considered[j][1]] * cds[list_of_divisor_pairs_to_be_considered[j][2]] * pt_class
inter_dict[my_tuple] = integrate(class)
end
push!(condition, inter_dict[my_tuple])

end

# Compute against zero section and base divisor
zsc = zero_section_class(m)
pos_zero_section = findfirst(x -> x == string(polynomial(zsc).f), string.(gS))
@req pos_zero_section !== nothing && pos_zero_section >= 1 "Could not establish position of the zero section"
for j in 1:n_rays(base_space(m))
my_tuple = Tuple(sort([idxs..., [j, pos_zero_section]...]))
if !haskey(inter_dict, my_tuple)
class = ambient_space_flux_candidates_basis[i] * cds[j] * zsc * pt_class
inter_dict[my_tuple] = integrate(class)
end
push!(condition, inter_dict[my_tuple])

end

push!(vertical_constraint_matrix, condition)

end

end


# (6) Compute the vertical fluxes as the kernel of the vertical_constraint_matrix.
# (6) To later tell if those fluxes are properly quantized, we want to parametrize them with integer coefficient only.
denom = lcm(unique(vcat([denominator.(k) for k in vertical_constraint_matrix]...)))
if denom != 1
vertical_constraint_matrix = denom * vertical_constraint_matrix
end
C_vertical = transpose(matrix(ZZ, vertical_constraint_matrix))
vertical_fluxes = nullspace(C_vertical)[2]


# (7) Work out the relevant intersection numbers to tell if a flux is well quantized
quant_constraint_matrix = Vector{Vector{QQFieldElem}}()
if arxiv_doi(m) == "10.48550/arXiv.1511.03209"

# Use special intersection theory for special F-theory model. This technology could be extended beyond this one use-case in the future.
for i in 1:length(ambient_space_flux_candidates_basis)
condition = Vector{ZZRingElem}()
idxs = findall(x -> x != 0, collect(exponents(polynomial(ambient_space_flux_candidates_basis[i]).f))[1])
if length(idxs) == 1
idxs = [idxs[1], idxs[1]]
end

for j in 1:length(list_of_divisor_pairs_to_be_considered)

my_tuple = Tuple(sort([idxs..., list_of_divisor_pairs_to_be_considered[j]...]))
push!(condition, sophisticated_intersection_product(ambient_space(m), my_tuple, hypersurface_equation(m), inter_dict, s_inter_dict, data))

end
push!(quant_constraint_matrix, condition)
end

else

# Cover all other case with generic, but potentially painfully slow methodology.
tds = torusinvariant_prime_divisors(ambient_space(m))
cds = [cohomology_class(tds[i]) for i in 1:length(tds)]
pt_class = cohomology_class(anticanonical_divisor_class(ambient_space(m)))
for i in 1:length(ambient_space_flux_candidates_basis)

condition = Vector{QQFieldElem}()

idxs = findall(x -> x != 0, collect(exponents(polynomial(ambient_space_flux_candidates_basis[i]).f))[1])
if length(idxs) == 1
idxs = [idxs[1], idxs[1]]
end

for j in 1:length(list_of_divisor_pairs_to_be_considered)

my_tuple = Tuple(sort([idxs..., list_of_divisor_pairs_to_be_considered[j]...]))
if !haskey(inter_dict, my_tuple)
class = ambient_space_flux_candidates_basis[i] * cds[list_of_divisor_pairs_to_be_considered[j][1]] * cds[list_of_divisor_pairs_to_be_considered[j][2]] * pt_class
inter_dict[my_tuple] = integrate(class)
end
push!(condition, inter_dict[my_tuple])

end
push!(quant_constraint_matrix, condition)
end

end

# (8) Convert the quant_constraint_matrix to a ZZ matrix. If necessary, multiply it by a suitable integer.
denom = lcm(unique(vcat([denominator.(k) for k in quant_constraint_matrix]...)))
if denom != 1
quant_constraint_matrix = denom * quant_constraint_matrix
end
C = transpose(matrix(ZZ, quant_constraint_matrix))


# (9) Work out the well-quantized fluxes as linear combinations of the parametrization of the vertical fluxes
C2 = C * vertical_fluxes # This is a ZZ-matrix, since we parametrize vertical fluxes with integer coefficients!
S, T, U = snf_with_transform(C2)
r = rank(S)
@req all(k -> !is_zero(S[k,k]), 1:r) "Inconsistency in Smith normal form detected. Please inform the authors."
@req all(k -> is_zero(S[k,k]), r+1:min(nrows(S), ncols(S))) "Inconsistency in Smith normal form detected. Please inform the authors."
S_prime = zero_matrix(QQ, ncols(S), ncols(S))
for k in 1:min(nrows(S), ncols(S))
if k <= r
S_prime[k,k] = denom//S[k,k]
else
S_prime[k,k] = 1
end
end
solution_matrix = U * S_prime


# (10) Finally, we need to re-express those in terms of the original bases.
# (10) Rather, we have res now expressed in terms of the basis of vertical fluxes...
sol_mat = vertical_fluxes * solution_matrix
res = (sol_mat[:,1:r], sol_mat[:,r+1:ncols(solution_matrix)])


# (11) Remember computed data
set_attribute!(m, :well_quantized_and_vertical_ambient_space_models_of_g4_fluxes, res)
set_attribute!(m, :inter_dict, inter_dict)
set_attribute!(m, :s_inter_dict, s_inter_dict)


# (12) Finally, return the result
return res

end
21 changes: 21 additions & 0 deletions experimental/FTheoryTools/src/Serialization/hypersurface_models.jl
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ function save_object(s::SerializerState, h::HypersurfaceModel)
attrs_dict[:_ambient_space_divisor_pairs_to_be_considered] = _ambient_space_divisor_pairs_to_be_considered(h)
end

# Do we know which pairs of ambient space base divisors intersect non-trivially with the hypersurface?
if has_attribute(h, :_ambient_space_base_divisor_pairs_to_be_considered)
attrs_dict[:_ambient_space_base_divisor_pairs_to_be_considered] = _ambient_space_base_divisor_pairs_to_be_considered(h)
end

# Do we know ambient space models for g4-fluxes?
if has_attribute(h, :ambient_space_models_of_g4_fluxes)
ambient_space_flux_candidates_basis = ambient_space_models_of_g4_fluxes(h)
Expand All @@ -103,6 +108,13 @@ function save_object(s::SerializerState, h::HypersurfaceModel)
attrs_dict[:well_quantized_rational] = res[2]
end

# Do we know the well-quantized and vertical G4-fluxes
if has_attribute(h, :well_quantized_and_vertical_ambient_space_models_of_g4_fluxes)
res = well_quantized_and_vertical_ambient_space_models_of_g4_fluxes(h, check = false)
attrs_dict[:well_quantized_and_vertical_integral] = res[1]
attrs_dict[:well_quantized_and_vertical_rational] = res[2]
end

# Save all of the above data...
!isempty(attrs_dict) && save_typed_object(s, attrs_dict, :__attrs)
end
Expand Down Expand Up @@ -170,6 +182,9 @@ function load_object(s::DeserializerState, ::Type{<:HypersurfaceModel}, params::
if haskey(attrs_data, :_ambient_space_divisor_pairs_to_be_considered)
set_attribute!(model, :_ambient_space_divisor_pairs_to_be_considered, attrs_data[:_ambient_space_divisor_pairs_to_be_considered])
end
if haskey(attrs_data, :_ambient_space_base_divisor_pairs_to_be_considered)
set_attribute!(model, :_ambient_space_base_divisor_pairs_to_be_considered, attrs_data[:_ambient_space_base_divisor_pairs_to_be_considered])
end

# Likewise, there are only so many ambient space G4-flux candidates. If those are known, set them.
# In the serialization, we remember only the integer tuples that tell us which toric divisors to consider,
Expand All @@ -189,5 +204,11 @@ function load_object(s::DeserializerState, ::Type{<:HypersurfaceModel}, params::
set_attribute!(model, :well_quantized_ambient_space_models_of_g4_fluxes, quant_tuple)
end

# Are the well-quantized and vertical G4-fluxes known?
if haskey(attrs_data, :well_quantized_and_vertical_integral) && haskey(attrs_data, :well_quantized_and_vertical_integral)
quant_tuple = (attrs_data[:well_quantized_and_vertical_integral], attrs_data[:well_quantized_and_vertical_integral])
set_attribute!(model, :well_quantized_and_vertical_ambient_space_models_of_g4_fluxes, quant_tuple)
end

return model
end
Loading

0 comments on commit 271681c

Please sign in to comment.