From 563e44be507fd142fa16fb21b356ac4928a26263 Mon Sep 17 00:00:00 2001 From: Martin Bies Date: Sun, 19 Jan 2025 15:03:27 +0100 Subject: [PATCH 1/6] [FTheoryTools] Implement D3-tadpole constraint for family of G4-fluxes --- experimental/FTheoryTools/docs/src/g4.md | 1 + .../src/FamilyOfG4Fluxes/attributes.jl | 144 ++++++++++++++++++ experimental/FTheoryTools/src/exports.jl | 1 + 3 files changed, 146 insertions(+) diff --git a/experimental/FTheoryTools/docs/src/g4.md b/experimental/FTheoryTools/docs/src/g4.md index 2715d8000fd9..52ab935df586 100644 --- a/experimental/FTheoryTools/docs/src/g4.md +++ b/experimental/FTheoryTools/docs/src/g4.md @@ -108,6 +108,7 @@ Families of G4-fluxes currently support the following attributes: model(gf::FamilyOfG4Fluxes) matrix_integral(gf::FamilyOfG4Fluxes) matrix_rational(gf::FamilyOfG4Fluxes) +d3_tadpole_constraint(fgs::FamilyOfG4Fluxes; check::Bool = true) ``` ### Properties diff --git a/experimental/FTheoryTools/src/FamilyOfG4Fluxes/attributes.jl b/experimental/FTheoryTools/src/FamilyOfG4Fluxes/attributes.jl index 56d7836cf784..1a31e9563438 100644 --- a/experimental/FTheoryTools/src/FamilyOfG4Fluxes/attributes.jl +++ b/experimental/FTheoryTools/src/FamilyOfG4Fluxes/attributes.jl @@ -94,3 +94,147 @@ true ``` """ matrix_rational(gf::FamilyOfG4Fluxes) = gf.mat_rat + + +##################################################### +# 2 Compute the D3-tadpole constraint +##################################################### + +@doc raw""" + d3_tadpole_constraint(fgs::FamilyOfG4Fluxes; check::Bool = true) + +Return the d3-tapdole constraint of a family of G4-fluxes. Recall that for a given $G_4$-flux, this constraint +is $- \frac{1}{2} \cdot G_4^2 + \frac{1}{24} \cdot \chi(\widehat{Y}_4) \stackrel{!}{\geq} 0$. + +Note that the family of fluxes is specified by linear combination of cohomology classes, some with rational +and some with integral coefficients. In terms of these coefficients the d3-tadpole constraint is the demand +that a quadratic polynomial in the coefficients evaluates to a non-negative number. This method returns said +polynomial in the cofficients. In order to evaluate the D3-tadpole for a particular $G_4$-flux, one has to +evaluate this polynomial for the numeric coefficient values that correspond to the given $G_4$-flux. + +We use symbols $a_i$ to indicate integral coefficients and $r_i$ to indicate rational coefficients. + +```jldoctest; setup = :(Oscar.LazyArtifacts.ensure_artifact_installed("QSMDB", Oscar.LazyArtifacts.find_artifacts_toml(Oscar.oscardir))) +julia> qsm_model = literature_model(arxiv_id = "1903.00009", model_parameters = Dict("k" => 2021)) +Hypersurface model over a concrete base + +julia> fgs = special_flux_family(qsm_model, check = false) +A family of G4 fluxes: + - Elementary quantization checks: satisfied + - Verticality checks: failed + - Non-abelian gauge group: broken + +julia> d3_tadpole_constraint(fgs); +``` +""" +function d3_tadpole_constraint(fgs::FamilyOfG4Fluxes; check::Bool = true) + + # Is the result known? + if has_attribute(fgs, :d3_tadpole_constraint) + return get_attribute(fgs, :d3_tadpole_constraint)::QQMPolyRingElem + end + + # Entry checks + m = model(fgs) + @req base_space(m) isa NormalToricVariety "Computation of D3-tadpole constraint only supported for toric base and ambient spaces" + @req dim(ambient_space(m)) == 5 "Computation of D3-tadpole constraint only supported for 5-dimensional toric ambient spaces" + if check + @req is_complete(ambient_space(m)) "Computation of D3-tadpole constraint only supported for complete toric ambient spaces" + @req is_simplicial(ambient_space(m)) "Computation of D3-tadpole constraint only supported for simplicial toric ambient space" + end + + # Are intersection numbers known? + inter_dict = get_attribute!(m, :inter_dict) do + Dict{NTuple{4, Int64}, ZZRingElem}() + end::Dict{NTuple{4, Int64}, ZZRingElem} + s_inter_dict = get_attribute!(m, :s_inter_dict) do + Dict{String, ZZRingElem}() + end::Dict{String, ZZRingElem} + + # Compute data, that is frequently used by the sophisticated intersection product + if arxiv_doi(m) == "10.48550/arXiv.1511.03209" + 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 + ) + end + + # Find the number of integral and rational parameters + numb_int_parameters = ncols(matrix_integral(fgs)) + numb_rat_parameters = ncols(matrix_rational(fgs)) + + # Create a polynomial ring with parameters ai for the integral_parameters and ri for the rational parameters + gens_strings = vcat([["a$(k)" for k in 1:numb_int_parameters], ["r$(k)" for k in 1:numb_rat_parameters]]...) + amb_ring, gens = polynomial_ring(QQ, gens_strings) + + # Extract ambient space basis of G4-flux candidates used to express flux family in + basis = ambient_space_models_of_g4_fluxes(m, check = check) + basis_indices = get_attribute(m, :ambient_space_models_of_g4_fluxes_indices)::Vector{Tuple{Int64, Int64}} + + # Compute the cohomology class corresponding to the hypersurface equation + cy = polynomial(cohomology_class(toric_divisor_class(ambient_space(m), degree(hypersurface_equation(m))))) + + # Compute the tadpole constraint by iterating over all generators of the flux family + tadpole_constraint_polynomial = zero(amb_ring) + for k1 in 1:ngens(amb_ring) + for k2 in 1:ngens(amb_ring) + + # Extract generator k1 + if numb_int_parameters >= k1 + gen1 = matrix_integral(fgs)[:, k1] + else + gen1 = matrix_rational(fgs)[:, k1 - numb_int_parameters] + end + + # Extract generator k2 + if numb_int_parameters >= k2 + gen2 = matrix_integral(fgs)[:, k2] + else + gen2 = matrix_rational(fgs)[:, k2 - numb_int_parameters] + end + + # Compute the intersection number of generator k1 and generator k2 + inter_number = ZZ(0) + for l1 in 1:length(basis) + for l2 in 1:length(basis) + + gen1[l1] * gen2[l2] == 0 && continue + + my_tuple = Tuple(sort([basis_indices[l1]..., basis_indices[l2]...])) + + if arxiv_doi(m) == "10.48550/arXiv.1511.03209" + change = sophisticated_intersection_product(ambient_space(m), my_tuple, hypersurface_equation(m), inter_dict, s_inter_dict, data) + else + change = get!(inter_dict, my_tuple) do + return QQ(integrate(cohomology_class(ambient_space(m), polynomial(basis[l1]) * polynomial(basis[l2]) * cy); check = check)) + end + end + + inter_number += gen1[l1] * gen2[l2] * change + + end + end + + # Update the D3-tadpole constraint polynomial + tadpole_constraint_polynomial += inter_number * gens[k1] * gens[k2] + + end + end + + # Modify the tadpole constraint polynomial to reflect the actual constraint + tadpole_constraint_polynomial = -1//2 * tadpole_constraint_polynomial + 1//24 * euler_characteristic(m, check = check) + set_attribute!(fgs, :d3_tadpole_constraint, tadpole_constraint_polynomial) + + # Finally, return the result + return tadpole_constraint_polynomial::QQMPolyRingElem + +end diff --git a/experimental/FTheoryTools/src/exports.jl b/experimental/FTheoryTools/src/exports.jl index 70451523730b..4667738f691b 100644 --- a/experimental/FTheoryTools/src/exports.jl +++ b/experimental/FTheoryTools/src/exports.jl @@ -54,6 +54,7 @@ export degrees_of_kbar_restrictions_to_components_of_simplified_dual_graph export discriminant export display_all_literature_models export dual_graph +export d3_tadpole_constraint export estimated_number_of_triangulations export euler_characteristic export explicit_model_sections From 47cafdc076b62b150ea7987c4eb104e8c1e8fde3 Mon Sep 17 00:00:00 2001 From: Martin Bies Date: Sun, 19 Jan 2025 18:53:55 +0100 Subject: [PATCH 2/6] [FTheoryTools] Serialize D3-tadpole constraint for special families of G4 fluxes --- .../src/Serialization/hypersurface_models.jl | 18 ++++++++++++++++++ .../src/Serialization/tate_models.jl | 18 ++++++++++++++++++ .../src/Serialization/weierstrass_models.jl | 18 ++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/experimental/FTheoryTools/src/Serialization/hypersurface_models.jl b/experimental/FTheoryTools/src/Serialization/hypersurface_models.jl index 24582dbc4c31..70130807d935 100644 --- a/experimental/FTheoryTools/src/Serialization/hypersurface_models.jl +++ b/experimental/FTheoryTools/src/Serialization/hypersurface_models.jl @@ -97,6 +97,9 @@ function save_object(s::SerializerState, h::HypersurfaceModel) res = well_quantized_ambient_space_models_of_g4_fluxes(h, check = false) attrs_dict[:well_quantized_integral] = matrix_integral(res) attrs_dict[:well_quantized_rational] = matrix_rational(res) + if has_attribute(res, :d3_tadpole_constraint) + attrs_dict[:well_quantized_d3_tadpole] = d3_tadpole_constraint(res) + end end # Do we know the well-quantized and vertical G4-fluxes @@ -104,6 +107,9 @@ function save_object(s::SerializerState, h::HypersurfaceModel) res = well_quantized_and_vertical_ambient_space_models_of_g4_fluxes(h, check = false) attrs_dict[:well_quantized_and_vertical_integral] = matrix_integral(res) attrs_dict[:well_quantized_and_vertical_rational] = matrix_rational(res) + if has_attribute(res, :d3_tadpole_constraint) + attrs_dict[:well_quantized_and_vertical_d3_tadpole] = d3_tadpole_constraint(res) + end end # Do we know the well-quantized, vertical G4-fluxes that do not break the non-Abelian gauge group? @@ -111,6 +117,9 @@ function save_object(s::SerializerState, h::HypersurfaceModel) res = well_quantized_and_vertical_and_no_non_abelian_gauge_group_breaking_ambient_space_models_of_g4_fluxes(h, check = false) attrs_dict[:well_quantized_vertical_no_break_integral] = matrix_integral(res) attrs_dict[:well_quantized_vertical_no_break_rational] = matrix_rational(res) + if has_attribute(res, :d3_tadpole_constraint) + attrs_dict[:well_quantized_vertical_and_no_breaking_d3_tadpole] = d3_tadpole_constraint(res) + end end # Save all of the above data... @@ -204,6 +213,9 @@ function load_object(s::DeserializerState, ::Type{<:HypersurfaceModel}, params:: set_attribute!(fgs, :is_well_quantized, true) set_attribute!(fgs, :is_vertical, false) set_attribute!(fgs, :breaks_non_abelian_gauge_group, true) + if haskey(attrs_data, :well_quantized_d3_tadpole) + set_attribute!(fgs, :d3_tadpole_constraint, attrs_dict[:well_quantized_d3_tadpole]) + end set_attribute!(model, :well_quantized_ambient_space_models_of_g4_fluxes, fgs) end @@ -214,6 +226,9 @@ function load_object(s::DeserializerState, ::Type{<:HypersurfaceModel}, params:: set_attribute!(fgs, :is_well_quantized, true) set_attribute!(fgs, :is_vertical, true) set_attribute!(fgs, :breaks_non_abelian_gauge_group, true) + if haskey(attrs_data, :well_quantized_and_vertical_d3_tadpole) + set_attribute!(fgs, :d3_tadpole_constraint, attrs_dict[:well_quantized_and_vertical_d3_tadpole]) + end set_attribute!(model, :well_quantized_and_vertical_ambient_space_models_of_g4_fluxes, fgs) end @@ -224,6 +239,9 @@ function load_object(s::DeserializerState, ::Type{<:HypersurfaceModel}, params:: set_attribute!(fgs, :is_well_quantized, true) set_attribute!(fgs, :is_vertical, true) set_attribute!(fgs, :breaks_non_abelian_gauge_group, false) + if haskey(attrs_data, :well_quantized_vertical_and_no_breaking_d3_tadpole) + set_attribute!(fgs, :d3_tadpole_constraint, attrs_dict[:well_quantized_vertical_and_no_breaking_d3_tadpole]) + end set_attribute!(model, :well_quantized_and_vertical_and_no_non_abelian_gauge_group_breaking_ambient_space_models_of_g4_fluxes, fgs) end diff --git a/experimental/FTheoryTools/src/Serialization/tate_models.jl b/experimental/FTheoryTools/src/Serialization/tate_models.jl index 5c2b43cf08b1..a4e3e4c6e924 100644 --- a/experimental/FTheoryTools/src/Serialization/tate_models.jl +++ b/experimental/FTheoryTools/src/Serialization/tate_models.jl @@ -98,6 +98,9 @@ function save_object(s::SerializerState, gtm::GlobalTateModel) res = well_quantized_ambient_space_models_of_g4_fluxes(gtm, check = false) attrs_dict[:well_quantized_integral] = matrix_integral(res) attrs_dict[:well_quantized_rational] = matrix_rational(res) + if has_attribute(res, :d3_tadpole_constraint) + attrs_dict[:well_quantized_d3_tadpole] = d3_tadpole_constraint(res) + end end # Do we know the well-quantized and vertical G4-fluxes @@ -105,6 +108,9 @@ function save_object(s::SerializerState, gtm::GlobalTateModel) res = well_quantized_and_vertical_ambient_space_models_of_g4_fluxes(gtm, check = false) attrs_dict[:well_quantized_and_vertical_integral] = matrix_integral(res) attrs_dict[:well_quantized_and_vertical_rational] = matrix_rational(res) + if has_attribute(res, :d3_tadpole_constraint) + attrs_dict[:well_quantized_and_vertical_d3_tadpole] = d3_tadpole_constraint(res) + end end # Do we know the well-quantized, vertical G4-fluxes that do not break the non-Abelian gauge group? @@ -112,6 +118,9 @@ function save_object(s::SerializerState, gtm::GlobalTateModel) res = well_quantized_and_vertical_and_no_non_abelian_gauge_group_breaking_ambient_space_models_of_g4_fluxes(gtm, check = false) attrs_dict[:well_quantized_vertical_no_break_integral] = matrix_integral(res) attrs_dict[:well_quantized_vertical_no_break_rational] = matrix_rational(res) + if has_attribute(res, :d3_tadpole_constraint) + attrs_dict[:well_quantized_vertical_and_no_breaking_d3_tadpole] = d3_tadpole_constraint(res) + end end # Save all of the above data... @@ -205,6 +214,9 @@ function load_object(s::DeserializerState, ::Type{<: GlobalTateModel}, params::T set_attribute!(fgs, :is_well_quantized, true) set_attribute!(fgs, :is_vertical, false) set_attribute!(fgs, :breaks_non_abelian_gauge_group, true) + if haskey(attrs_data, :well_quantized_d3_tadpole) + set_attribute!(fgs, :d3_tadpole_constraint, attrs_dict[:well_quantized_d3_tadpole]) + end set_attribute!(model, :well_quantized_ambient_space_models_of_g4_fluxes, fgs) end @@ -215,6 +227,9 @@ function load_object(s::DeserializerState, ::Type{<: GlobalTateModel}, params::T set_attribute!(fgs, :is_well_quantized, true) set_attribute!(fgs, :is_vertical, true) set_attribute!(fgs, :breaks_non_abelian_gauge_group, true) + if haskey(attrs_data, :well_quantized_and_vertical_d3_tadpole) + set_attribute!(fgs, :d3_tadpole_constraint, attrs_dict[:well_quantized_and_vertical_d3_tadpole]) + end set_attribute!(model, :well_quantized_and_vertical_ambient_space_models_of_g4_fluxes, fgs) end @@ -225,6 +240,9 @@ function load_object(s::DeserializerState, ::Type{<: GlobalTateModel}, params::T set_attribute!(fgs, :is_well_quantized, true) set_attribute!(fgs, :is_vertical, true) set_attribute!(fgs, :breaks_non_abelian_gauge_group, false) + if haskey(attrs_data, :well_quantized_vertical_and_no_breaking_d3_tadpole) + set_attribute!(fgs, :d3_tadpole_constraint, attrs_dict[:well_quantized_vertical_and_no_breaking_d3_tadpole]) + end set_attribute!(model, :well_quantized_and_vertical_and_no_non_abelian_gauge_group_breaking_ambient_space_models_of_g4_fluxes, fgs) end diff --git a/experimental/FTheoryTools/src/Serialization/weierstrass_models.jl b/experimental/FTheoryTools/src/Serialization/weierstrass_models.jl index b1f31c0c43ed..e9e123e801bc 100644 --- a/experimental/FTheoryTools/src/Serialization/weierstrass_models.jl +++ b/experimental/FTheoryTools/src/Serialization/weierstrass_models.jl @@ -97,6 +97,9 @@ function save_object(s::SerializerState, w::WeierstrassModel) res = well_quantized_ambient_space_models_of_g4_fluxes(w, check = false) attrs_dict[:well_quantized_integral] = matrix_integral(res) attrs_dict[:well_quantized_rational] = matrix_rational(res) + if has_attribute(res, :d3_tadpole_constraint) + attrs_dict[:well_quantized_d3_tadpole] = d3_tadpole_constraint(res) + end end # Do we know the well-quantized and vertical G4-fluxes @@ -104,6 +107,9 @@ function save_object(s::SerializerState, w::WeierstrassModel) res = well_quantized_and_vertical_ambient_space_models_of_g4_fluxes(w, check = false) attrs_dict[:well_quantized_and_vertical_integral] = matrix_integral(res) attrs_dict[:well_quantized_and_vertical_rational] = matrix_rational(res) + if has_attribute(res, :d3_tadpole_constraint) + attrs_dict[:well_quantized_and_vertical_d3_tadpole] = d3_tadpole_constraint(res) + end end # Do we know the well-quantized, vertical G4-fluxes that do not break the non-Abelian gauge group? @@ -111,6 +117,9 @@ function save_object(s::SerializerState, w::WeierstrassModel) res = well_quantized_and_vertical_and_no_non_abelian_gauge_group_breaking_ambient_space_models_of_g4_fluxes(w, check = false) attrs_dict[:well_quantized_vertical_no_break_integral] = matrix_integral(res) attrs_dict[:well_quantized_vertical_no_break_rational] = matrix_rational(res) + if has_attribute(res, :d3_tadpole_constraint) + attrs_dict[:well_quantized_vertical_and_no_breaking_d3_tadpole] = d3_tadpole_constraint(res) + end end # Save all of the above data... @@ -204,6 +213,9 @@ function load_object(s::DeserializerState, ::Type{<: WeierstrassModel}, params:: set_attribute!(fgs, :is_well_quantized, true) set_attribute!(fgs, :is_vertical, false) set_attribute!(fgs, :breaks_non_abelian_gauge_group, true) + if haskey(attrs_data, :well_quantized_d3_tadpole) + set_attribute!(fgs, :d3_tadpole_constraint, attrs_dict[:well_quantized_d3_tadpole]) + end set_attribute!(model, :well_quantized_ambient_space_models_of_g4_fluxes, fgs) end @@ -214,6 +226,9 @@ function load_object(s::DeserializerState, ::Type{<: WeierstrassModel}, params:: set_attribute!(fgs, :is_well_quantized, true) set_attribute!(fgs, :is_vertical, true) set_attribute!(fgs, :breaks_non_abelian_gauge_group, true) + if haskey(attrs_data, :well_quantized_and_vertical_d3_tadpole) + set_attribute!(fgs, :d3_tadpole_constraint, attrs_dict[:well_quantized_and_vertical_d3_tadpole]) + end set_attribute!(model, :well_quantized_and_vertical_ambient_space_models_of_g4_fluxes, fgs) end @@ -224,6 +239,9 @@ function load_object(s::DeserializerState, ::Type{<: WeierstrassModel}, params:: set_attribute!(fgs, :is_well_quantized, true) set_attribute!(fgs, :is_vertical, true) set_attribute!(fgs, :breaks_non_abelian_gauge_group, false) + if haskey(attrs_data, :well_quantized_vertical_and_no_breaking_d3_tadpole) + set_attribute!(fgs, :d3_tadpole_constraint, attrs_dict[:well_quantized_vertical_and_no_breaking_d3_tadpole]) + end set_attribute!(model, :well_quantized_and_vertical_and_no_non_abelian_gauge_group_breaking_ambient_space_models_of_g4_fluxes, fgs) end From 19c19fb072e6bae294f4757a95c117cb18aef7bf Mon Sep 17 00:00:00 2001 From: Martin Bies Date: Sun, 19 Jan 2025 20:05:19 +0100 Subject: [PATCH 3/6] [FTheoryTools] Support D3-tadpole for individual G4-fluxes --- experimental/FTheoryTools/docs/src/g4.md | 1 + .../FTheoryTools/src/G4Fluxes/attributes.jl | 58 +++++++++++++++++++ .../FTheoryTools/src/G4Fluxes/properties.jl | 9 +-- 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/experimental/FTheoryTools/docs/src/g4.md b/experimental/FTheoryTools/docs/src/g4.md index 52ab935df586..43c16b13a9fc 100644 --- a/experimental/FTheoryTools/docs/src/g4.md +++ b/experimental/FTheoryTools/docs/src/g4.md @@ -22,6 +22,7 @@ We currently support the following attributes: ```@docs model(gf::G4Flux) cohomology_class(gf::G4Flux) +d3_tadpole_constraint(gf::G4Flux; check::Bool = true) ``` ## Methods diff --git a/experimental/FTheoryTools/src/G4Fluxes/attributes.jl b/experimental/FTheoryTools/src/G4Fluxes/attributes.jl index 34f0231822f0..3887ee3a4135 100644 --- a/experimental/FTheoryTools/src/G4Fluxes/attributes.jl +++ b/experimental/FTheoryTools/src/G4Fluxes/attributes.jl @@ -54,3 +54,61 @@ true ``` """ cohomology_class(gf::G4Flux) = gf.class + + + +##################################################### +# 2 Compute the D3-tadpole constraint +##################################################### + +@doc raw""" + d3_tadpole_constraint(gf::G4Flux; check::Bool = true) + +Return the d3-tapdole constraint of a G4-flux, that is compute the quantity +$- \frac{1}{2} \cdot G_4^2 + \frac{1}{24} \cdot \chi(\widehat{Y}_4) \stackrel{!}{\geq} 0$. + +```jldoctest; setup = :(Oscar.LazyArtifacts.ensure_artifact_installed("QSMDB", Oscar.LazyArtifacts.find_artifacts_toml(Oscar.oscardir))) +julia> qsm_model = literature_model(arxiv_id = "1903.00009", model_parameters = Dict("k" => 4)) +Hypersurface model over a concrete base + +julia> divs = torusinvariant_prime_divisors(ambient_space(qsm_model)); + +julia> e1 = cohomology_class(divs[35]);e2 = cohomology_class(divs[32]);e4 = cohomology_class(divs[34]); + +julia> u = cohomology_class(divs[33]);v = cohomology_class(divs[30]);pb_Kbar = cohomology_class(sum([divs[k] for k in 1:29])); + +julia> g4_class = (-3) // kbar3(qsm_model) * (5 * e1 * e4 + pb_Kbar * (-3 * e1 - 2 * e2 - 6 * e4 + pb_Kbar - 4 * u + v)); + +julia> g4 = g4_flux(qsm_model, g4_class, check = false) +G4-flux candidate + - Elementary quantization checks: not executed + - Tadpole cancellation check: not executed + - Verticality checks: not executed + - Non-abelian gauge group: breaking pattern not analyzed + +julia> d3_tadpole_constraint(g4, check = false) +12 +``` +""" +function d3_tadpole_constraint(gf::G4Flux; check::Bool = true) + if has_attribute(gf, :d3_tadpole_constraint) + return get_attribute(gf, :d3_tadpole_constraint)::QQFieldElem + end + m = model(gf) + @req (m isa WeierstrassModel || m isa GlobalTateModel || m isa HypersurfaceModel) "Tadpole cancellation checks for G4-fluxes only supported for Weierstrass, global Tate and hypersurface models" + @req base_space(m) isa NormalToricVariety "Tadpole cancellation checks for G4-flux currently supported only for toric base" + @req ambient_space(m) isa NormalToricVariety "Tadpole cancellation checks for G4-flux currently supported only for toric ambient space" + if check + @req is_complete(ambient_space(m)) "Computation of D3-tadpole constraint only supported for complete toric ambient spaces" + @req is_simplicial(ambient_space(m)) "Computation of D3-tadpole constraint only supported for simplicial toric ambient space" + end + cy = polynomial(cohomology_class(toric_divisor_class(ambient_space(m), degree(hypersurface_equation(m))))) + numb = QQ(euler_characteristic(m; check = check)//24 - 1//2*integrate(cohomology_class(ambient_space(m), polynomial(cohomology_class(gf)) * polynomial(cohomology_class(gf)) * cy); check = check)) + set_attribute!(gf, :d3_tadpole_constraint, numb) + if numb >= 0 && is_integer(numb) + set_attribute!(gf, :passes_tadpole_cancellation_check, true) + else + set_attribute!(gf, :passes_tadpole_cancellation_check, false) + end + return numb::QQFieldElem +end diff --git a/experimental/FTheoryTools/src/G4Fluxes/properties.jl b/experimental/FTheoryTools/src/G4Fluxes/properties.jl index 65471570972c..16fde1bdc11a 100644 --- a/experimental/FTheoryTools/src/G4Fluxes/properties.jl +++ b/experimental/FTheoryTools/src/G4Fluxes/properties.jl @@ -182,13 +182,8 @@ G4-flux candidate @req (m isa WeierstrassModel || m isa GlobalTateModel || m isa HypersurfaceModel) "Tadpole cancellation checks for G4-fluxes only supported for Weierstrass, global Tate and hypersurface models" @req base_space(m) isa NormalToricVariety "Tadpole cancellation checks for G4-flux currently supported only for toric base" @req ambient_space(m) isa NormalToricVariety "Tadpole cancellation checks for G4-flux currently supported only for toric ambient space" - - # Compute the cohomology class corresponding to the hypersurface equation - cy = polynomial(cohomology_class(toric_divisor_class(ambient_space(m), degree(hypersurface_equation(m))))) - - # Now check if the D3-tadpole cancellation condition holds - numb = euler_characteristic(m; check = false)/24 - 1/2*integrate(cohomology_class(ambient_space(m), polynomial(cohomology_class(g4)) * polynomial(cohomology_class(g4)) * cy); check = false) - if numb > 0 && is_integer(numb) + numb = d3_tadpole_constraint(g4, check = false) + if numb >= 0 && is_integer(numb) return true end return false From 03c24f5aff59db0c9ee188505ae19ce8550a0c6a Mon Sep 17 00:00:00 2001 From: Martin Bies Date: Tue, 21 Jan 2025 11:58:52 +0100 Subject: [PATCH 4/6] [FTheoryTools] Code improvements Co-authored-by: Max Horn --- .../FTheoryTools/src/FamilyOfG4Fluxes/attributes.jl | 12 ++++++------ .../src/FamilyOfG4Fluxes/special_constructors.jl | 8 ++++---- experimental/FTheoryTools/src/G4Fluxes/attributes.jl | 6 +----- experimental/FTheoryTools/src/G4Fluxes/properties.jl | 5 +---- 4 files changed, 12 insertions(+), 19 deletions(-) diff --git a/experimental/FTheoryTools/src/FamilyOfG4Fluxes/attributes.jl b/experimental/FTheoryTools/src/FamilyOfG4Fluxes/attributes.jl index 1a31e9563438..4b701299e36e 100644 --- a/experimental/FTheoryTools/src/FamilyOfG4Fluxes/attributes.jl +++ b/experimental/FTheoryTools/src/FamilyOfG4Fluxes/attributes.jl @@ -155,7 +155,7 @@ function d3_tadpole_constraint(fgs::FamilyOfG4Fluxes; check::Bool = true) if arxiv_doi(m) == "10.48550/arXiv.1511.03209" S = cox_ring(ambient_space(m)) gS = gens(cox_ring(ambient_space(m))) - linear_relations = matrix(QQ, matrix(ZZ, rays(ambient_space(m)))) + linear_relations = matrix(QQ, 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)] @@ -173,8 +173,7 @@ function d3_tadpole_constraint(fgs::FamilyOfG4Fluxes; check::Bool = true) numb_rat_parameters = ncols(matrix_rational(fgs)) # Create a polynomial ring with parameters ai for the integral_parameters and ri for the rational parameters - gens_strings = vcat([["a$(k)" for k in 1:numb_int_parameters], ["r$(k)" for k in 1:numb_rat_parameters]]...) - amb_ring, gens = polynomial_ring(QQ, gens_strings) + amb_ring, my_gens = polynomial_ring(QQ, "a#" => 1:numb_int_parameters, "r#" => 1: numb_rat_parameters) # Extract ambient space basis of G4-flux candidates used to express flux family in basis = ambient_space_models_of_g4_fluxes(m, check = check) @@ -207,7 +206,8 @@ function d3_tadpole_constraint(fgs::FamilyOfG4Fluxes; check::Bool = true) for l1 in 1:length(basis) for l2 in 1:length(basis) - gen1[l1] * gen2[l2] == 0 && continue + val = gen1[l1] * gen2[l2] + is_zero(val) && continue my_tuple = Tuple(sort([basis_indices[l1]..., basis_indices[l2]...])) @@ -219,13 +219,13 @@ function d3_tadpole_constraint(fgs::FamilyOfG4Fluxes; check::Bool = true) end end - inter_number += gen1[l1] * gen2[l2] * change + inter_number += val * change end end # Update the D3-tadpole constraint polynomial - tadpole_constraint_polynomial += inter_number * gens[k1] * gens[k2] + tadpole_constraint_polynomial += inter_number * my_gens[k1] * my_gens[k2] end end diff --git a/experimental/FTheoryTools/src/FamilyOfG4Fluxes/special_constructors.jl b/experimental/FTheoryTools/src/FamilyOfG4Fluxes/special_constructors.jl index 9cdc126e8cc7..1472c90c5d07 100644 --- a/experimental/FTheoryTools/src/FamilyOfG4Fluxes/special_constructors.jl +++ b/experimental/FTheoryTools/src/FamilyOfG4Fluxes/special_constructors.jl @@ -8,7 +8,7 @@ properties. This family is modelled by the restriction of cohomology classes on the toric ambient space to the hypersurface in question. In the toric ambient space, those cohomology classes are vertical, i.e. are of the form $a \wedge b$ for -$a,b \in H^(1,1)(X_\Sigma)$ with $X_\Sigma$. Note that this does NOT mean that +$a,b \in H^(1,1)(X_\Sigma)$ with $X_\Sigma$. Note that this does NOT mean that they are vertical on the hypersurface, which defines the actual F-theory geometry. We further subject this family to the consistency conditions for being well-quantized. Unless explicitly asked differently, it is this family of @@ -159,7 +159,7 @@ function well_quantized_ambient_space_models_of_g4_fluxes(m::AbstractFTheoryMode # (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)))) + linear_relations = matrix(QQ, 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)] @@ -400,7 +400,7 @@ function well_quantized_and_vertical_ambient_space_models_of_g4_fluxes(m::Abstra # (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)))) + linear_relations = matrix(QQ, 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)] @@ -735,7 +735,7 @@ function well_quantized_and_vertical_and_no_non_abelian_gauge_group_breaking_amb # (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)))) + linear_relations = matrix(QQ, 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)] diff --git a/experimental/FTheoryTools/src/G4Fluxes/attributes.jl b/experimental/FTheoryTools/src/G4Fluxes/attributes.jl index 3887ee3a4135..804b01376543 100644 --- a/experimental/FTheoryTools/src/G4Fluxes/attributes.jl +++ b/experimental/FTheoryTools/src/G4Fluxes/attributes.jl @@ -105,10 +105,6 @@ function d3_tadpole_constraint(gf::G4Flux; check::Bool = true) cy = polynomial(cohomology_class(toric_divisor_class(ambient_space(m), degree(hypersurface_equation(m))))) numb = QQ(euler_characteristic(m; check = check)//24 - 1//2*integrate(cohomology_class(ambient_space(m), polynomial(cohomology_class(gf)) * polynomial(cohomology_class(gf)) * cy); check = check)) set_attribute!(gf, :d3_tadpole_constraint, numb) - if numb >= 0 && is_integer(numb) - set_attribute!(gf, :passes_tadpole_cancellation_check, true) - else - set_attribute!(gf, :passes_tadpole_cancellation_check, false) - end + set_attribute!(gf, :passes_tadpole_cancellation_check, (numb >= 0 && is_integer(numb))) return numb::QQFieldElem end diff --git a/experimental/FTheoryTools/src/G4Fluxes/properties.jl b/experimental/FTheoryTools/src/G4Fluxes/properties.jl index 16fde1bdc11a..a4f02d4cfe82 100644 --- a/experimental/FTheoryTools/src/G4Fluxes/properties.jl +++ b/experimental/FTheoryTools/src/G4Fluxes/properties.jl @@ -183,10 +183,7 @@ G4-flux candidate @req base_space(m) isa NormalToricVariety "Tadpole cancellation checks for G4-flux currently supported only for toric base" @req ambient_space(m) isa NormalToricVariety "Tadpole cancellation checks for G4-flux currently supported only for toric ambient space" numb = d3_tadpole_constraint(g4, check = false) - if numb >= 0 && is_integer(numb) - return true - end - return false + return numb >= 0 && is_integer(numb) end From f33fe955d3dddc5403b926dde84de01845d419a6 Mon Sep 17 00:00:00 2001 From: Martin Bies Date: Tue, 21 Jan 2025 13:13:11 +0100 Subject: [PATCH 5/6] [FTheoryTools] Load inter_dict as Dict{NTuple{4, Int64}, ZZRingElem}() --- .../src/Serialization/hypersurface_models.jl | 11 ++++++++++- .../FTheoryTools/src/Serialization/tate_models.jl | 11 ++++++++++- .../src/Serialization/weierstrass_models.jl | 11 ++++++++++- experimental/FTheoryTools/test/FTM-1511-03209.jl | 9 +++++---- 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/experimental/FTheoryTools/src/Serialization/hypersurface_models.jl b/experimental/FTheoryTools/src/Serialization/hypersurface_models.jl index 70130807d935..d9893d2604f6 100644 --- a/experimental/FTheoryTools/src/Serialization/hypersurface_models.jl +++ b/experimental/FTheoryTools/src/Serialization/hypersurface_models.jl @@ -163,7 +163,16 @@ function load_object(s::DeserializerState, ::Type{<:HypersurfaceModel}, params:: # That is, we have a dictionary which assigns the tuple (i1, i2, i3, i4) - sorted in ascending order - the # intersection number k. In general, k could be a rational number! Cf. orbifold singularities. if haskey(attrs_data, :inter_dict) - set_attribute!(model, :inter_dict, attrs_data[:inter_dict]) + # We want this inter_dict to be of type Dict{NTuple{4, Int64}, ZZRingElem}(). + # Sadly, serializing and loading turns NTuple{4, Int64} into Tuple. + # So we need to massage this... Not at all good, as it doubles memory usage! + original_dict = attrs_data[:inter_dict] + new_dict = Dict{NTuple{4, Int64}, ZZRingElem}() + for (key, value) in original_dict + new_key = NTuple{4, Int64}(key) + new_dict[new_key] = value + end + set_attribute!(model, :inter_dict, new_dict) end # Some special intersection numbers known? If we intersect the toric divisors diff --git a/experimental/FTheoryTools/src/Serialization/tate_models.jl b/experimental/FTheoryTools/src/Serialization/tate_models.jl index a4e3e4c6e924..feee259cee49 100644 --- a/experimental/FTheoryTools/src/Serialization/tate_models.jl +++ b/experimental/FTheoryTools/src/Serialization/tate_models.jl @@ -165,7 +165,16 @@ function load_object(s::DeserializerState, ::Type{<: GlobalTateModel}, params::T # That is, we have a dictionary which assigns the tuple (i1, i2, i3, i4) - sorted in ascending order - the # intersection number k. In general, k could be a rational number! Cf. orbifold singularities. if haskey(attrs_data, :inter_dict) - set_attribute!(model, :inter_dict, attrs_data[:inter_dict]) + # We want this inter_dict to be of type Dict{NTuple{4, Int64}, ZZRingElem}(). + # Sadly, serializing and loading turns NTuple{4, Int64} into Tuple. + # So we need to massage this... Not at all good, as it doubles memory usage! + original_dict = attrs_data[:inter_dict] + new_dict = Dict{NTuple{4, Int64}, ZZRingElem}() + for (key, value) in original_dict + new_key = NTuple{4, Int64}(key) + new_dict[new_key] = value + end + set_attribute!(model, :inter_dict, new_dict) end # Some special intersection numbers known? If we intersect the toric divisors diff --git a/experimental/FTheoryTools/src/Serialization/weierstrass_models.jl b/experimental/FTheoryTools/src/Serialization/weierstrass_models.jl index e9e123e801bc..596c184cfb40 100644 --- a/experimental/FTheoryTools/src/Serialization/weierstrass_models.jl +++ b/experimental/FTheoryTools/src/Serialization/weierstrass_models.jl @@ -163,7 +163,16 @@ function load_object(s::DeserializerState, ::Type{<: WeierstrassModel}, params:: # That is, we have a dictionary which assigns the tuple (i1, i2, i3, i4) - sorted in ascending order - the # intersection number k. In general, k could be a rational number! Cf. orbifold singularities. if haskey(attrs_data, :inter_dict) - set_attribute!(model, :inter_dict, attrs_data[:inter_dict]) + # We want this inter_dict to be of type Dict{NTuple{4, Int64}, ZZRingElem}(). + # Sadly, serializing and loading turns NTuple{4, Int64} into Tuple. + # So we need to massage this... Not at all good, as it doubles memory usage! + original_dict = attrs_data[:inter_dict] + new_dict = Dict{NTuple{4, Int64}, ZZRingElem}() + for (key, value) in original_dict + new_key = NTuple{4, Int64}(key) + new_dict[new_key] = value + end + set_attribute!(model, :inter_dict, new_dict) end # Some special intersection numbers known? If we intersect the toric divisors diff --git a/experimental/FTheoryTools/test/FTM-1511-03209.jl b/experimental/FTheoryTools/test/FTM-1511-03209.jl index 0c1a71b7e073..f122ae2554c1 100644 --- a/experimental/FTheoryTools/test/FTM-1511-03209.jl +++ b/experimental/FTheoryTools/test/FTM-1511-03209.jl @@ -1,7 +1,8 @@ @testset "Test Downloading Artifact and elementary properties" begin - h = literature_model(arxiv_id = "1511.03209") - h_resolved = resolve(h, 1) + t = literature_model(arxiv_id = "1511.03209") + t_resolved = resolve(h, 1) - @test n_rays(ambient_space(h)) == 104 - @test n_rays(ambient_space(h_resolved)) == 310 + @test n_rays(ambient_space(t)) == 104 + @test n_rays(ambient_space(t_resolved)) == 310 + @test typeof(get_attribute(t_resolved, :inter_dict)) == Dict{NTuple{4, Int64}, ZZRingElem} end From 9b7eb731da00be593c2f2c5350e31f1ab9a5fe93 Mon Sep 17 00:00:00 2001 From: Martin Bies Date: Tue, 21 Jan 2025 14:34:19 +0100 Subject: [PATCH 6/6] [FTheoryTools] Use MPolyBuildCtx builder and optimize code --- .../src/FamilyOfG4Fluxes/attributes.jl | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/experimental/FTheoryTools/src/FamilyOfG4Fluxes/attributes.jl b/experimental/FTheoryTools/src/FamilyOfG4Fluxes/attributes.jl index 4b701299e36e..2f7b04cbcd8f 100644 --- a/experimental/FTheoryTools/src/FamilyOfG4Fluxes/attributes.jl +++ b/experimental/FTheoryTools/src/FamilyOfG4Fluxes/attributes.jl @@ -151,7 +151,7 @@ function d3_tadpole_constraint(fgs::FamilyOfG4Fluxes; check::Bool = true) Dict{String, ZZRingElem}() end::Dict{String, ZZRingElem} - # Compute data, that is frequently used by the sophisticated intersection product + # Compute data, that is used by the default/sophisticated intersection product if arxiv_doi(m) == "10.48550/arXiv.1511.03209" S = cox_ring(ambient_space(m)) gS = gens(cox_ring(ambient_space(m))) @@ -166,6 +166,8 @@ function d3_tadpole_constraint(fgs::FamilyOfG4Fluxes; check::Bool = true) scalings = scalings, sr_ideal_pos = sr_ideal_pos ) + else + cy = polynomial(cohomology_class(toric_divisor_class(ambient_space(m), degree(hypersurface_equation(m))))) end # Find the number of integral and rational parameters @@ -179,13 +181,11 @@ function d3_tadpole_constraint(fgs::FamilyOfG4Fluxes; check::Bool = true) basis = ambient_space_models_of_g4_fluxes(m, check = check) basis_indices = get_attribute(m, :ambient_space_models_of_g4_fluxes_indices)::Vector{Tuple{Int64, Int64}} - # Compute the cohomology class corresponding to the hypersurface equation - cy = polynomial(cohomology_class(toric_divisor_class(ambient_space(m), degree(hypersurface_equation(m))))) - - # Compute the tadpole constraint by iterating over all generators of the flux family - tadpole_constraint_polynomial = zero(amb_ring) + # Use MPolyBuildCtx to compute the tadpole constraint. + C = MPolyBuildCtx(amb_ring) + exp_vec = fill(0, numb_int_parameters + numb_rat_parameters) for k1 in 1:ngens(amb_ring) - for k2 in 1:ngens(amb_ring) + for k2 in k1:ngens(amb_ring) # Extract generator k1 if numb_int_parameters >= k1 @@ -204,7 +204,7 @@ function d3_tadpole_constraint(fgs::FamilyOfG4Fluxes; check::Bool = true) # Compute the intersection number of generator k1 and generator k2 inter_number = ZZ(0) for l1 in 1:length(basis) - for l2 in 1:length(basis) + for l2 in l1:length(basis) val = gen1[l1] * gen2[l2] is_zero(val) && continue @@ -219,18 +219,29 @@ function d3_tadpole_constraint(fgs::FamilyOfG4Fluxes; check::Bool = true) end end - inter_number += val * change + if l1 == l2 + inter_number += val * change + else + inter_number += 2 * val * change + end end end # Update the D3-tadpole constraint polynomial - tadpole_constraint_polynomial += inter_number * my_gens[k1] * my_gens[k2] + exp_vec[k1] += 1 + exp_vec[k2] += 1 + if k1 == k2 + push_term!(C, inter_number, exp_vec) + else + push_term!(C, 2 * inter_number, exp_vec) + end + exp_vec[k1] = 0 + exp_vec[k2] = 0 end end - - # Modify the tadpole constraint polynomial to reflect the actual constraint + tadpole_constraint_polynomial = finish(C) tadpole_constraint_polynomial = -1//2 * tadpole_constraint_polynomial + 1//24 * euler_characteristic(m, check = check) set_attribute!(fgs, :d3_tadpole_constraint, tadpole_constraint_polynomial)