From 8a75c2c346d58af1f2b4cb5969330be515e56ed4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Thu, 16 Jan 2025 17:37:56 +0100 Subject: [PATCH 1/2] All previous changes squashed --- Project.toml | 2 +- .../src/AbstractFTheoryModels/attributes.jl | 16 +- .../src/AbstractFTheoryModels/properties.jl | 24 +-- .../FamilyOfG4Fluxes/special_constructors.jl | 28 +-- .../FTheoryTools/src/G4Fluxes/auxiliary.jl | 35 +--- .../src/NormalToricVarieties/attributes.jl | 50 +++-- .../Schemes/src/ToricDivisors/attributes.jl | 36 ++-- .../AffineSchemes/Objects/Attributes.jl | 6 +- .../CoveredSchemes/Objects/Attributes.jl | 6 +- .../Schemes/FunctionField/FunctionFields.jl | 6 +- .../ProjectiveSchemes/Objects/Attributes.jl | 34 ++- .../ProjectiveSchemes/Objects/Properties.jl | 102 +++++---- .../Schemes/Sheaves/IdealSheaves.jl | 100 +++++---- .../EllipticSurface/EllipticSurface.jl | 52 +++-- .../Surfaces/EllipticSurface/Morphisms.jl | 10 +- .../CohomologyClasses/special_attributes.jl | 18 +- .../NormalToricVarieties/attributes.jl | 8 +- .../cohomCalg/special_attributes.jl | 198 +++++++++--------- src/Groups/group_characters.jl | 4 +- src/Groups/matrices/form_group.jl | 51 ++--- src/Modules/Posur.jl | 27 +-- src/Modules/mpolyquo-localizations.jl | 7 +- src/Rings/MPolyMap/AffineAlgebras.jl | 8 +- src/Rings/MPolyMap/flattenings.jl | 12 +- src/Rings/MPolyQuo.jl | 26 +-- src/Rings/mpoly-affine-algebras.jl | 20 +- src/Rings/mpoly-ideals.jl | 95 ++++----- src/Rings/mpoly-localizations.jl | 45 ++-- src/Rings/mpolyquo-localizations.jl | 37 ++-- 29 files changed, 469 insertions(+), 594 deletions(-) diff --git a/Project.toml b/Project.toml index 9f2c2ae9ea8e..ceb3db3b610f 100644 --- a/Project.toml +++ b/Project.toml @@ -26,7 +26,7 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" cohomCalg_jll = "5558cf25-a90e-53b0-b813-cadaa3ae7ade" [compat] -AbstractAlgebra = "0.44.0" +AbstractAlgebra = "0.44.4" AlgebraicSolving = "0.8.0" Distributed = "1.6" GAP = "0.13.0" diff --git a/experimental/FTheoryTools/src/AbstractFTheoryModels/attributes.jl b/experimental/FTheoryTools/src/AbstractFTheoryModels/attributes.jl index f6a7adda89cf..dd53e0f11dee 100644 --- a/experimental/FTheoryTools/src/AbstractFTheoryModels/attributes.jl +++ b/experimental/FTheoryTools/src/AbstractFTheoryModels/attributes.jl @@ -1299,21 +1299,19 @@ julia> h = euler_characteristic(qsm_model; check = false) 378 ``` """ -function euler_characteristic(m::AbstractFTheoryModel; check::Bool = true) +@attr Int function euler_characteristic(m::AbstractFTheoryModel; check::Bool = true) @req (m isa WeierstrassModel || m isa GlobalTateModel || m isa HypersurfaceModel) "Euler characteristic of F-theory model supported for Weierstrass, global Tate and hypersurface models only" @req base_space(m) isa NormalToricVariety "Euler characteristic of F-theory model currently supported only for toric base" @req ambient_space(m) isa NormalToricVariety "Euler characteristic of F-theory model currently supported only for toric ambient space" - return get_attribute!(m, :euler_characteristic) do - # Trigger potential short-cut computation of cohomology ring - cohomology_ring(ambient_space(m); check) + # Trigger potential short-cut computation of cohomology ring + cohomology_ring(ambient_space(m); check) - # Compute the cohomology class corresponding to the hypersurface equation - cy = cohomology_class(toric_divisor_class(ambient_space(m), degree(hypersurface_equation(m)))) + # Compute the cohomology class corresponding to the hypersurface equation + cy = cohomology_class(toric_divisor_class(ambient_space(m), degree(hypersurface_equation(m)))) - # Compute the Euler characteristic - return Int(integrate(chern_class(m, 4; check) * cy; check)) - end::Int + # Compute the Euler characteristic + return Int(integrate(chern_class(m, 4; check) * cy; check)) end diff --git a/experimental/FTheoryTools/src/AbstractFTheoryModels/properties.jl b/experimental/FTheoryTools/src/AbstractFTheoryModels/properties.jl index 1d54234a5028..08beb9da5fc3 100644 --- a/experimental/FTheoryTools/src/AbstractFTheoryModels/properties.jl +++ b/experimental/FTheoryTools/src/AbstractFTheoryModels/properties.jl @@ -121,11 +121,11 @@ raises an error. julia> qsm_model = literature_model(arxiv_id = "1903.00009", model_parameters = Dict("k" => 4)) Hypersurface model over a concrete base -julia> verify_euler_characteristic_from_hodge_numbers(qsm_model, check = false) +julia> verify_euler_characteristic_from_hodge_numbers(qsm_model; check = false) true ``` """ -function verify_euler_characteristic_from_hodge_numbers(m::AbstractFTheoryModel; check::Bool = true) +@attr Bool function verify_euler_characteristic_from_hodge_numbers(m::AbstractFTheoryModel; check::Bool = true) @req (m isa WeierstrassModel || m isa GlobalTateModel || m isa HypersurfaceModel) "Verification of Euler characteristic of F-theory model supported for Weierstrass, global Tate and hypersurface models only" @req base_space(m) isa NormalToricVariety "Verification of Euler characteristic of F-theory model currently supported only for toric base" @req ambient_space(m) isa NormalToricVariety "Verification of Euler characteristic of F-theory model currently supported only for toric ambient space" @@ -136,16 +136,14 @@ function verify_euler_characteristic_from_hodge_numbers(m::AbstractFTheoryModel; @req has_attribute(m, :h13) "Verification of Euler characteristic of F-theory model requires h13" @req has_attribute(m, :h22) "Verification of Euler characteristic of F-theory model requires h22" - return get_attribute!(m, :verify_euler_characteristic_from_hodge_numbers) do - # Computer Euler characteristic from integrating c4 - ec = euler_characteristic(m, check = check) + # Computer Euler characteristic from integrating c4 + ec = euler_characteristic(m; check) - # Compute Euler characteristic from adding Hodge numbers - ec2 = 4 + 2 * hodge_h11(m) - 4 * hodge_h12(m) + 2 * hodge_h13(m) + hodge_h22(m) + # Compute Euler characteristic from adding Hodge numbers + ec2 = 4 + 2 * hodge_h11(m) - 4 * hodge_h12(m) + 2 * hodge_h13(m) + hodge_h22(m) - # Compute result of verification - return ec == ec2 - end::Bool + # Compute result of verification + return ec == ec2 end @@ -170,11 +168,9 @@ julia> is_calabi_yau(qsm_model, check = false) true ``` """ -function is_calabi_yau(m::AbstractFTheoryModel; check::Bool = true) +@attr Bool function is_calabi_yau(m::AbstractFTheoryModel; check::Bool = true) @req (m isa WeierstrassModel || m isa GlobalTateModel || m isa HypersurfaceModel) "Verification of Euler characteristic of F-theory model supported for Weierstrass, global Tate and hypersurface models only" @req base_space(m) isa NormalToricVariety "Verification of Euler characteristic of F-theory model currently supported only for toric base" @req ambient_space(m) isa NormalToricVariety "Verification of Euler characteristic of F-theory model currently supported only for toric ambient space" - return get_attribute!(m, :is_calabi_yau) do - return is_trivial(chern_class(m, 1, check = check)) - end::Bool + return is_trivial(chern_class(m, 1; check)) end diff --git a/experimental/FTheoryTools/src/FamilyOfG4Fluxes/special_constructors.jl b/experimental/FTheoryTools/src/FamilyOfG4Fluxes/special_constructors.jl index 1472c90c5d07..1af68f16e08a 100644 --- a/experimental/FTheoryTools/src/FamilyOfG4Fluxes/special_constructors.jl +++ b/experimental/FTheoryTools/src/FamilyOfG4Fluxes/special_constructors.jl @@ -142,7 +142,7 @@ julia> passes_elementary_quantization_checks(g4) true ``` """ -function well_quantized_ambient_space_models_of_g4_fluxes(m::AbstractFTheoryModel; check::Bool = true) +@attr FamilyOfG4Fluxes function well_quantized_ambient_space_models_of_g4_fluxes(m::AbstractFTheoryModel; check::Bool = true) # (1) Entry checks @req base_space(m) isa NormalToricVariety "Computation of well-quantized G4-fluxes only supported for toric base and ambient spaces" @@ -151,10 +151,6 @@ function well_quantized_ambient_space_models_of_g4_fluxes(m::AbstractFTheoryMode @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_ambient_space_models_of_g4_fluxes) - return get_attribute(m, :well_quantized_ambient_space_models_of_g4_fluxes)::FamilyOfG4Fluxes - end - # (2) Compute data, that is frequently used by the sophisticated intersection product below S = cox_ring(ambient_space(m)) @@ -270,14 +266,12 @@ function well_quantized_ambient_space_models_of_g4_fluxes(m::AbstractFTheoryMode set_attribute!(fgs, :is_well_quantized, true) set_attribute!(fgs, :is_vertical, false) set_attribute!(fgs, :breaks_non_abelian_gauge_group, true) - set_attribute!(m, :well_quantized_ambient_space_models_of_g4_fluxes, fgs) set_attribute!(m, :inter_dict, inter_dict) set_attribute!(m, :s_inter_dict, s_inter_dict) # (10) Finally, return the result - return fgs::FamilyOfG4Fluxes - + return fgs end @@ -383,7 +377,7 @@ julia> passes_verticality_checks(qsm_g4_candidate) true ``` """ -function well_quantized_and_vertical_ambient_space_models_of_g4_fluxes(m::AbstractFTheoryModel; check::Bool = true) +@attr FamilyOfG4Fluxes function well_quantized_and_vertical_ambient_space_models_of_g4_fluxes(m::AbstractFTheoryModel; check::Bool = true) # (1) Entry checks @req base_space(m) isa NormalToricVariety "Computation of well-quantized G4-fluxes only supported for toric base and ambient spaces" @@ -392,9 +386,6 @@ function well_quantized_and_vertical_ambient_space_models_of_g4_fluxes(m::Abstra @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)::FamilyOfG4Fluxes - end # (2) Compute data, that is frequently used by the sophisticated intersection product below @@ -578,14 +569,12 @@ function well_quantized_and_vertical_ambient_space_models_of_g4_fluxes(m::Abstra set_attribute!(fgs, :is_well_quantized, true) set_attribute!(fgs, :is_vertical, true) set_attribute!(fgs, :breaks_non_abelian_gauge_group, true) - set_attribute!(m, :well_quantized_and_vertical_ambient_space_models_of_g4_fluxes, fgs) set_attribute!(m, :inter_dict, inter_dict) set_attribute!(m, :s_inter_dict, s_inter_dict) # (12) Finally, return the result - return fgs::FamilyOfG4Fluxes - + return fgs end @@ -718,7 +707,7 @@ julia> qsm_g4_candidate == g4_flux(qsm_model, g4_class) true ``` """ -function well_quantized_and_vertical_and_no_non_abelian_gauge_group_breaking_ambient_space_models_of_g4_fluxes(m::AbstractFTheoryModel; check::Bool = true) +@attr FamilyOfG4Fluxes function well_quantized_and_vertical_and_no_non_abelian_gauge_group_breaking_ambient_space_models_of_g4_fluxes(m::AbstractFTheoryModel; check::Bool = true) # (1) Entry checks @req base_space(m) isa NormalToricVariety "Computation of well-quantized G4-fluxes only supported for toric base and ambient spaces" @@ -727,9 +716,6 @@ function well_quantized_and_vertical_and_no_non_abelian_gauge_group_breaking_amb @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_and_no_non_abelian_gauge_group_breaking_ambient_space_models_of_g4_fluxes) - return get_attribute(m, :well_quantized_and_vertical_and_no_non_abelian_gauge_group_breaking_ambient_space_models_of_g4_fluxes)::FamilyOfG4Fluxes - end # (2) Compute data, that is frequently used by the sophisticated intersection product below @@ -938,12 +924,10 @@ function well_quantized_and_vertical_and_no_non_abelian_gauge_group_breaking_amb set_attribute!(fgs, :is_well_quantized, true) set_attribute!(fgs, :is_vertical, true) set_attribute!(fgs, :breaks_non_abelian_gauge_group, false) - set_attribute!(m, :well_quantized_and_vertical_and_no_non_abelian_gauge_group_breaking_ambient_space_models_of_g4_fluxes, fgs) set_attribute!(m, :inter_dict, inter_dict) set_attribute!(m, :s_inter_dict, s_inter_dict) # (12) Finally, return the result - return fgs::FamilyOfG4Fluxes - + return fgs end diff --git a/experimental/FTheoryTools/src/G4Fluxes/auxiliary.jl b/experimental/FTheoryTools/src/G4Fluxes/auxiliary.jl index 4eea3ff1cc63..9120fb1d56f9 100644 --- a/experimental/FTheoryTools/src/G4Fluxes/auxiliary.jl +++ b/experimental/FTheoryTools/src/G4Fluxes/auxiliary.jl @@ -41,20 +41,15 @@ julia> betti_number(Y, 4) == length(h22_basis) true ``` """ -function basis_of_h22(v::NormalToricVariety; check::Bool = true)::Vector{CohomologyClass} - +@attr Vector{CohomologyClass} function basis_of_h22(v::NormalToricVariety; check::Bool = true) # (0) Some initial checks if check @req is_complete(v) "Computation of basis of H22 is currently only supported for complete toric varieties" @req is_simplicial(v) "Computation of basis of H22 is currently only supported for simplicial toric varieties" end if dim(v) < 4 - set_attribute!(v, :basis_of_h22, Vector{CohomologyClass}()) - end - if has_attribute(v, :basis_of_h22) - return get_attribute(v, :basis_of_h22) + return Vector{CohomologyClass}() end - # (1) Prepare some data of the variety mnf = Oscar._minimal_nonfaces(v) ignored_sets = Set([Tuple(sort(Vector{Int}(Polymake.row(mnf, i)))) for i in 1:Polymake.nrows(mnf)]) @@ -146,17 +141,15 @@ function basis_of_h22(v::NormalToricVariety; check::Bool = true)::Vector{Cohomol # (10) Return the basis elements in terms of cohomology classes S = cohomology_ring(v, check = check) c_ds = [k.f for k in gens(S)] - final_list_of_tuples = [] + final_list_of_tuples = Tuple{Int64, Int64}[] for (key, value) in dict_of_filtered_quadratic_elements if value in new_good_positions push!(final_list_of_tuples, key) end end basis_of_h22 = [cohomology_class(v, MPolyQuoRingElem(c_ds[my_tuple[1]]*c_ds[my_tuple[2]], S)) for my_tuple in final_list_of_tuples] - set_attribute!(v, :basis_of_h22, basis_of_h22) set_attribute!(v, :basis_of_h22_indices, final_list_of_tuples) return basis_of_h22 - end @@ -170,12 +163,7 @@ end # has empty intersection with the hypersurface. The following method identifies the remaining pairs of # toric divisors d1, d2 that we must consider. -function _ambient_space_divisor_pairs_to_be_considered(m::AbstractFTheoryModel)::Vector{Tuple{Int64, Int64}} - - if has_attribute(m, :_ambient_space_divisor_pairs_to_be_considered) - return get_attribute(m, :_ambient_space_divisor_pairs_to_be_considered) - end - +@attr Vector{Tuple{Int64, Int64}} function _ambient_space_divisor_pairs_to_be_considered(m::AbstractFTheoryModel) 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)]) @@ -221,10 +209,8 @@ function _ambient_space_divisor_pairs_to_be_considered(m::AbstractFTheoryModel): end end - # Remember this result as attribute and return the findings. - set_attribute!(m, :_ambient_space_divisor_pairs_to_be_considered, list_of_elements) + # Return the findings. return list_of_elements - end @@ -234,12 +220,7 @@ end # 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 - +@attr Vector{Tuple{Int64, Int64}} function _ambient_space_base_divisor_pairs_to_be_considered(m::AbstractFTheoryModel) 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)]) @@ -285,10 +266,8 @@ function _ambient_space_base_divisor_pairs_to_be_considered(m::AbstractFTheoryMo 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 the findings. return list_of_elements - end diff --git a/experimental/Schemes/src/NormalToricVarieties/attributes.jl b/experimental/Schemes/src/NormalToricVarieties/attributes.jl index 44d2785bd02b..e2a4fed49b80 100644 --- a/experimental/Schemes/src/NormalToricVarieties/attributes.jl +++ b/experimental/Schemes/src/NormalToricVarieties/attributes.jl @@ -51,35 +51,33 @@ # too. On the other hand, none of the vⱼ was in τ⟂ for j > s, # so neither can be any convex combination, but the trivial one. # This proves the claim. Now (*) follows directly. -function _torusinvariant_weil_divisors(X::NormalToricVariety; check::Bool=false, algorithm::Symbol=:via_polymake) - return get_attribute!(X, :_torusinvariant_weil_divisors) do - ray_list = rays(polyhedral_fan(X)) - ideal_sheaves = Vector{AbsIdealSheaf}() - if algorithm == :via_polymake - ideal_sheaves = [_ideal_sheaf_via_polymake(X, i; check) for i in 1:length(ray_list)] - elseif algorithm == :via_oscar - for tau in ray_list - tau_dual = polarize(cone(tau)) - ideal_dict = IdDict{AbsAffineScheme, Ideal}() - for U in affine_charts(X) - if !(tau in cone(U)) - ideal_dict[U] = ideal(OO(U), one(OO(U))) - continue - end - sigma_dual = weight_cone(U) - hb = hilbert_basis(sigma_dual) - x = gens(OO(U)) - ideal_dict[U] = ideal(OO(U), [x[i] for i in 1:length(x) if !(-hb[i] in tau_dual)]) +@attr Vector{<:AbsWeilDivisor} function _torusinvariant_weil_divisors(X::NormalToricVariety; check::Bool=false, algorithm::Symbol=:via_polymake) + ray_list = rays(polyhedral_fan(X)) + ideal_sheaves = Vector{AbsIdealSheaf}() + if algorithm == :via_polymake + ideal_sheaves = [_ideal_sheaf_via_polymake(X, i; check) for i in 1:length(ray_list)] + elseif algorithm == :via_oscar + for tau in ray_list + tau_dual = polarize(cone(tau)) + ideal_dict = IdDict{AbsAffineScheme, Ideal}() + for U in affine_charts(X) + if !(tau in cone(U)) + ideal_dict[U] = ideal(OO(U), one(OO(U))) + continue end - push!(ideal_sheaves, IdealSheaf(X, ideal_dict; check)) + sigma_dual = weight_cone(U) + hb = hilbert_basis(sigma_dual) + x = gens(OO(U)) + ideal_dict[U] = ideal(OO(U), [x[i] for i in 1:length(x) if !(-hb[i] in tau_dual)]) end - else - error("algorithm not recognized") + push!(ideal_sheaves, IdealSheaf(X, ideal_dict; check)) end - generating_divisors = [WeilDivisor(X, ZZ, IdDict{AbsIdealSheaf, ZZRingElem}(I => one(ZZ))) for I in ideal_sheaves] - result = generating_divisors - return result - end::Vector{<:AbsWeilDivisor} + else + error("algorithm not recognized") + end + generating_divisors = [WeilDivisor(X, ZZ, IdDict{AbsIdealSheaf, ZZRingElem}(I => one(ZZ))) for I in ideal_sheaves] + result = generating_divisors + return result end function _ideal_sheaf_via_polymake(X::NormalToricVariety, i::Int; check::Bool=false) diff --git a/experimental/Schemes/src/ToricDivisors/attributes.jl b/experimental/Schemes/src/ToricDivisors/attributes.jl index 15e6d6cff60c..79df9d71633a 100644 --- a/experimental/Schemes/src/ToricDivisors/attributes.jl +++ b/experimental/Schemes/src/ToricDivisors/attributes.jl @@ -53,24 +53,22 @@ function forget_toric_structure(td::ToricDivisor) end # For method delegation. -function underlying_divisor(td::ToricDivisor; check::Bool=false, algorithm::Symbol=:direct) - return get_attribute!(td, :underlying_divisor) do - X = scheme(td) - iszero(coefficients(td)) && return WeilDivisor(X, ZZ) - if algorithm == :direct - a = coefficients(td)::Vector{ZZRingElem} - pos = [(c > 0 ? c : zero(ZZ)) for c in a] - neg = [(c < 0 ? -c : zero(ZZ)) for c in a] - is_zero(pos) && return -WeilDivisor(_ideal_sheaf_via_polymake(X, neg)) - is_zero(neg) && return WeilDivisor(_ideal_sheaf_via_polymake(X, pos)) - pos_div = WeilDivisor(_ideal_sheaf_via_polymake(X, pos)) - neg_div = WeilDivisor(_ideal_sheaf_via_polymake(X, neg)) - return pos_div - neg_div - else - g = _torusinvariant_weil_divisors(X; algorithm) - generating_divisors = _torusinvariant_weil_divisors(X; check, algorithm) - return sum(a*D for (a, D) in zip(coefficients(td), generating_divisors)) - end - end::WeilDivisor +@attr WeilDivisor function underlying_divisor(td::ToricDivisor; check::Bool=false, algorithm::Symbol=:direct) + X = scheme(td) + iszero(coefficients(td)) && return WeilDivisor(X, ZZ) + if algorithm == :direct + a = coefficients(td)::Vector{ZZRingElem} + pos = [(c > 0 ? c : zero(ZZ)) for c in a] + neg = [(c < 0 ? -c : zero(ZZ)) for c in a] + is_zero(pos) && return -WeilDivisor(_ideal_sheaf_via_polymake(X, neg)) + is_zero(neg) && return WeilDivisor(_ideal_sheaf_via_polymake(X, pos)) + pos_div = WeilDivisor(_ideal_sheaf_via_polymake(X, pos)) + neg_div = WeilDivisor(_ideal_sheaf_via_polymake(X, neg)) + return pos_div - neg_div + else + g = _torusinvariant_weil_divisors(X; algorithm) + generating_divisors = _torusinvariant_weil_divisors(X; check, algorithm) + return sum(a*D for (a, D) in zip(coefficients(td), generating_divisors)) + end end diff --git a/src/AlgebraicGeometry/Schemes/AffineSchemes/Objects/Attributes.jl b/src/AlgebraicGeometry/Schemes/AffineSchemes/Objects/Attributes.jl index c42041a84701..2011416f119d 100644 --- a/src/AlgebraicGeometry/Schemes/AffineSchemes/Objects/Attributes.jl +++ b/src/AlgebraicGeometry/Schemes/AffineSchemes/Objects/Attributes.jl @@ -443,11 +443,9 @@ julia> codim(Y) return dim(ideal(ambient_coordinate_ring(X), [zero(ambient_coordinate_ring(X))])) - dim(X) end -function degree(X::AffineScheme{BRT, RT}; check::Bool=true) where {BRT<:Field, RT} +@attr Int function degree(X::AffineScheme{BRT, RT}; check::Bool=true) where {BRT<:Field, RT} @check dim(X) == 0 "the affine scheme X needs to be zero-dimensional" - get_attribute!(X, :degree) do - return vector_space_dimension(OO(X)) - end::Int + return vector_space_dimension(OO(X)) end @doc raw""" diff --git a/src/AlgebraicGeometry/Schemes/CoveredSchemes/Objects/Attributes.jl b/src/AlgebraicGeometry/Schemes/CoveredSchemes/Objects/Attributes.jl index f94028e41347..a817b8752716 100644 --- a/src/AlgebraicGeometry/Schemes/CoveredSchemes/Objects/Attributes.jl +++ b/src/AlgebraicGeometry/Schemes/CoveredSchemes/Objects/Attributes.jl @@ -270,13 +270,11 @@ given by the pullback function return domain(inc), inc end -function ideal_sheaf_of_singular_locus( +@attr SingularLocusIdealSheaf function ideal_sheaf_of_singular_locus( X::AbsCoveredScheme; focus=zero_ideal_sheaf(X) # This should really be an AbsIdealSheaf, but the inclusion order forbids mentioning this here. ) - return get_attribute!(X, :ideal_sheaf_of_singular_locus) do - SingularLocusIdealSheaf(X; focus) - end::SingularLocusIdealSheaf + return SingularLocusIdealSheaf(X; focus) end function simplified_covering(X::AbsCoveredScheme) diff --git a/src/AlgebraicGeometry/Schemes/FunctionField/FunctionFields.jl b/src/AlgebraicGeometry/Schemes/FunctionField/FunctionFields.jl index 6182ba095cd7..aca524e3746d 100644 --- a/src/AlgebraicGeometry/Schemes/FunctionField/FunctionFields.jl +++ b/src/AlgebraicGeometry/Schemes/FunctionField/FunctionFields.jl @@ -68,10 +68,8 @@ represented by patch 1: 1 ``` """ -function function_field(X::AbsCoveredScheme; check::Bool=true) - return get_attribute!(X, :function_field) do - VarietyFunctionField(X, check=check) - end::VarietyFunctionField # can't make this more concrete just using the type of X +@attr VarietyFunctionField function function_field(X::AbsCoveredScheme; check::Bool=true) + return VarietyFunctionField(X, check=check) end ######################################################################## diff --git a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Attributes.jl b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Attributes.jl index 8168cd4ce0d0..c85c0e6be2c1 100644 --- a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Attributes.jl +++ b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Attributes.jl @@ -602,24 +602,22 @@ julia> geometric_genus(C) ``` """ -function geometric_genus(X::AbsProjectiveScheme{<:Field}; algorithm::Symbol=:default, check=true) - get_attribute!(X, :genus) do - I = defining_ideal(X) - I_sing = singular_generators(I) - if algorithm == :default - g = Singular.LibNormal.genus(I_sing) - elseif algorithm == :normalization - g = Singular.LibNormal.genus(I_sing, "nor") - elseif algorithm == :primary_decomposition - g = Singular.LibNormal.genus(I_sing, "prim") - else - error("algorithm not recognized") - end - if g == -1 - error("$(X) must be a geometrically integral curve") - end - return g - end::Int +@attr Int function geometric_genus(X::AbsProjectiveScheme{<:Field}; algorithm::Symbol=:default, check=true) + I = defining_ideal(X) + I_sing = singular_generators(I) + if algorithm == :default + g = Singular.LibNormal.genus(I_sing) + elseif algorithm == :normalization + g = Singular.LibNormal.genus(I_sing, "nor") + elseif algorithm == :primary_decomposition + g = Singular.LibNormal.genus(I_sing, "prim") + else + error("algorithm not recognized") + end + if g == -1 + error("$(X) must be a geometrically integral curve") + end + return g end diff --git a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Properties.jl b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Properties.jl index c0e4128af69f..5cf3f1a45564 100644 --- a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Properties.jl +++ b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Properties.jl @@ -60,66 +60,64 @@ false """ is_smooth(P::AbsProjectiveScheme; algorithm::Symbol=:default) -function is_smooth(P::AbsProjectiveScheme{<:Any, <:MPolyQuoRing}; algorithm::Symbol=:default) - get_attribute!(P, :is_smooth) do - if is_empty(P) - return true - end - - if algorithm == :default - if is_equidimensional(P) - algorithm = :projective_jacobian - elseif base_ring(P) isa Field - algorithm = :affine_cone - else - if !(base_ring(P) isa Field) - throw(NotImplementedError( - :is_smooth, - "is_smooth only implemented when the scheme is equidimensional or the base ring is a field" - )) - end - end - end - - algorithms = [ - :projective_jacobian, - :covered_jacobian, - :affine_cone, - ] - if !(algorithm in algorithms) - throw(ArgumentError( - "the optional argument to the function is_smooth can only be one" - * " of the following: " * join(algorithms, ", ") * "." - )) - end +@attr Bool function is_smooth(P::AbsProjectiveScheme{<:Any, <:MPolyQuoRing}; algorithm::Symbol=:default) + if is_empty(P) + return true + end - if algorithm == :covered_jacobian - if !(base_ring(P) isa Field) - throw(NotImplementedError( - :is_smooth, - "Algorithm `:covered_jacobian` only implemented when the base ring is a field" - # because this algorithm uses `is_smooth` for affine schemes, and `is_smooth` is not implemented for affine schemes over a non-field base ring - )) - end - return _jacobian_criterion(covered_scheme(P)) - elseif algorithm == :affine_cone + if algorithm == :default + if is_equidimensional(P) + algorithm = :projective_jacobian + elseif base_ring(P) isa Field + algorithm = :affine_cone + else if !(base_ring(P) isa Field) throw(NotImplementedError( :is_smooth, - "Algorithm `:affine_cone` only implemented when the base ring is a field" - # because this algorithm uses `is_smooth` for affine schemes, and `is_smooth` is not implemented for affine schemes over a non-field base ring + "is_smooth only implemented when the scheme is equidimensional or the base ring is a field" )) end + end + end + + algorithms = [ + :projective_jacobian, + :covered_jacobian, + :affine_cone, + ] + if !(algorithm in algorithms) + throw(ArgumentError( + "the optional argument to the function is_smooth can only be one" + * " of the following: " * join(algorithms, ", ") * "." + )) + end + + if algorithm == :covered_jacobian + if !(base_ring(P) isa Field) + throw(NotImplementedError( + :is_smooth, + "Algorithm `:covered_jacobian` only implemented when the base ring is a field" + # because this algorithm uses `is_smooth` for affine schemes, and `is_smooth` is not implemented for affine schemes over a non-field base ring + )) + end + return _jacobian_criterion(covered_scheme(P)) + elseif algorithm == :affine_cone + if !(base_ring(P) isa Field) + throw(NotImplementedError( + :is_smooth, + "Algorithm `:affine_cone` only implemented when the base ring is a field" + # because this algorithm uses `is_smooth` for affine schemes, and `is_smooth` is not implemented for affine schemes over a non-field base ring + )) + end # TODO: Implement `is_smooth` for affine schemes. Then, this algorithm would work for arbitrary schemes. A similar algorithm can be used for quasismoothness of subschemes of toric varieties. # We explain why the algorithm of `:affine_cone` works for arbitrary schemes over arbitrary base schemes. By Remark 13.38(1) of [GW20](@cite), the morphism from the pointed affine cone to $P$ is locally the morphism $\mathbb{A}_U^1 \setminus \{0\} \to U$, where $U$ is an affine open of $P$ and $\mathbb{A}_U^1$ is the relative affine 1-space over $U$. By Definition 6.14(1) of [GW20](@cite), the Jacobian matrix for $U$ differs from the Jacobian matrix for $P$ only by a column containing zeros, implying that the ranks of the Jacobian matrices are the same. Therefore, $P$ is smooth if and only if the affine cone is smooth outside the origin. - aff, _ = affine_cone(P) - sing, _ = singular_locus(aff) - origin = ideal(gens(ambient_coordinate_ring(sing))) - return isone(saturation(saturated_ideal(defining_ideal(sing)), origin)) - elseif algorithm == :projective_jacobian - return _projective_jacobian_criterion(P) - end - end::Bool + aff, _ = affine_cone(P) + sing, _ = singular_locus(aff) + origin = ideal(gens(ambient_coordinate_ring(sing))) + return isone(saturation(saturated_ideal(defining_ideal(sing)), origin)) + elseif algorithm == :projective_jacobian + return _projective_jacobian_criterion(P) + end end is_smooth(P::AbsProjectiveScheme{<:Ring, <:MPolyRing}; algorithm::Symbol=:default) = true diff --git a/src/AlgebraicGeometry/Schemes/Sheaves/IdealSheaves.jl b/src/AlgebraicGeometry/Schemes/Sheaves/IdealSheaves.jl index 33ff5e0eae81..82fbef459a6d 100644 --- a/src/AlgebraicGeometry/Schemes/Sheaves/IdealSheaves.jl +++ b/src/AlgebraicGeometry/Schemes/Sheaves/IdealSheaves.jl @@ -667,13 +667,11 @@ end #end # -function is_one(I::AbsIdealSheaf; covering::Covering=default_covering(scheme(I))) - return get_attribute!(I, :is_one) do - for U in keys(object_cache(I)) - !is_one(cheap_sub_ideal(I, U)) && !is_one(I(U)) && return false - end - return all(x->isone(I(x)), covering) - end::Bool +@attr Bool function is_one(I::AbsIdealSheaf; covering::Covering=default_covering(scheme(I))) + for U in keys(object_cache(I)) + !is_one(cheap_sub_ideal(I, U)) && !is_one(I(U)) && return false + end + return all(x->isone(I(x)), covering) end function is_one(I::PrimeIdealSheafFromChart; covering::Covering=default_covering(scheme(I))) @@ -684,40 +682,38 @@ function dim(I::PrimeIdealSheafFromChart) return dim(I(original_chart(I))) end -function is_one(I::SumIdealSheaf; covering::Covering=default_covering(scheme(I))) - return get_attribute!(I, :is_one) do - for U in keys(object_cache(I)) - !is_one(I(U)) && return false - end +@attr Bool function is_one(I::SumIdealSheaf; covering::Covering=default_covering(scheme(I))) + for U in keys(object_cache(I)) + !is_one(I(U)) && return false + end - J = summands(I) - k = findfirst(x->x isa PrimeIdealSheafFromChart, J) - if k !== nothing - P = J[k] - U = original_chart(P) - if !is_one(cheap_sub_ideal(I, U)) - is_one(I(U)) || return false - end - end - - if has_decomposition_info(covering) - dec = decomposition_info(covering) - for U in covering - D = ideal(OO(U), dec[U]) - K = D - for J in summands(I) # shortcut for trivial patches - if U in keys(object_cache(J)) - K = K + J(U) - end - end - isone(K) && continue - - isone(D + cheap_sub_ideal(I, U)) || isone(I(U)+D) || return false - end - return true + J = summands(I) + k = findfirst(x->x isa PrimeIdealSheafFromChart, J) + if k !== nothing + P = J[k] + U = original_chart(P) + if !is_one(cheap_sub_ideal(I, U)) + is_one(I(U)) || return false end - return all(x->(isone(cheap_sub_ideal(I, x)) || isone(I(x))), covering) - end::Bool + end + + if has_decomposition_info(covering) + dec = decomposition_info(covering) + for U in covering + D = ideal(OO(U), dec[U]) + K = D + for J in summands(I) # shortcut for trivial patches + if U in keys(object_cache(J)) + K = K + J(U) + end + end + isone(K) && continue + + isone(D + cheap_sub_ideal(I, U)) || isone(I(U)+D) || return false + end + return true + end + return all(x->(isone(cheap_sub_ideal(I, x)) || isone(I(x))), covering) end function is_one(I::ProductIdealSheaf; covering::Covering=default_covering(scheme(I))) @@ -1499,20 +1495,18 @@ function _one_patch_per_component(covering::Covering, comp::Vector{<:AbsIdealShe return new_cov end -function small_generating_set(I::MPolyLocalizedIdeal; algorithm::Symbol=:simple) - get_attribute!(I, :small_generating_set) do - L = base_ring(I) - poly_ideal = pre_saturated_ideal(I) - if algorithm == :simple - # do nothing more - elseif algorithm == :with_saturation - poly_ideal = saturated_ideal(I) - else - error("algorithm keyword not recognized") - end - g = small_generating_set(poly_ideal) - unique!(elem_type(L)[gg for gg in L.(g) if !iszero(gg)]) - end::Vector{elem_type(base_ring(I))} +@attr Vector{elem_type(base_ring(I))} function small_generating_set(I::MPolyLocalizedIdeal; algorithm::Symbol=:simple) + L = base_ring(I) + poly_ideal = pre_saturated_ideal(I) + if algorithm == :simple + # do nothing more + elseif algorithm == :with_saturation + poly_ideal = saturated_ideal(I) + else + error("algorithm keyword not recognized") + end + g = small_generating_set(poly_ideal) + unique!(elem_type(L)[gg for gg in L.(g) if !iszero(gg)]) end function saturation(I::AbsIdealSheaf, J::AbsIdealSheaf) diff --git a/src/AlgebraicGeometry/Surfaces/EllipticSurface/EllipticSurface.jl b/src/AlgebraicGeometry/Surfaces/EllipticSurface/EllipticSurface.jl index 3ccbb2ee1f8a..6a73c230cbcd 100644 --- a/src/AlgebraicGeometry/Surfaces/EllipticSurface/EllipticSurface.jl +++ b/src/AlgebraicGeometry/Surfaces/EllipticSurface/EllipticSurface.jl @@ -1033,36 +1033,34 @@ The keyword argument `reducible_singular_fibers_in_PP1` must be a list of vector the base field representing the points in projective space over which there are reducible fibers. Specify it to force this ordering of the basis vectors of the ambient space of the `algebraic_lattice` """ -function _trivial_lattice(X::EllipticSurface; reducible_singular_fibers_in_PP1=_reducible_fibers_disc(X)) +@attr Any function _trivial_lattice(X::EllipticSurface; reducible_singular_fibers_in_PP1=_reducible_fibers_disc(X)) S = X - get_attribute!(S, :_trivial_lattice) do - O = zero_section(S) - pt0, F = fiber(S) - set_attribute!(components(O)[1], :_self_intersection, -euler_characteristic(S)) - basisT = [F, O] - grams = [ZZ[0 1;1 -euler_characteristic(S)]] - sing = reducible_singular_fibers_in_PP1 - f = [[pt, fiber_components(S,pt)] for pt in sing] - fiber_componentsS = [] - for (pt, ft) in f - @vprint :EllipticSurface 2 "normalizing fiber: over $pt \n" - Ft0 = standardize_fiber(S, ft) - @vprint :EllipticSurface 2 "$(Ft0[1]) \n" - append!(basisT , Ft0[3][2:end]) - push!(grams,Ft0[4][2:end,2:end]) - push!(fiber_componentsS, vcat([pt], collect(Ft0))) - end - G = block_diagonal_matrix(grams) - # make way for some more pretty printing - for (pt,root_type,_,comp) in fiber_componentsS - for (i,I) in enumerate(comp) - name = string(root_type[1], root_type[2]) - set_attribute!(components(I)[1], :name, string("Component ", name, "_", i-1," of fiber over ", Tuple(pt))) - set_attribute!(components(I)[1], :_self_intersection, -2) - end + O = zero_section(S) + pt0, F = fiber(S) + set_attribute!(components(O)[1], :_self_intersection, -euler_characteristic(S)) + basisT = [F, O] + grams = [ZZ[0 1;1 -euler_characteristic(S)]] + sing = reducible_singular_fibers_in_PP1 + f = [[pt, fiber_components(S,pt)] for pt in sing] + fiber_componentsS = [] + for (pt, ft) in f + @vprint :EllipticSurface 2 "normalizing fiber: over $pt \n" + Ft0 = standardize_fiber(S, ft) + @vprint :EllipticSurface 2 "$(Ft0[1]) \n" + append!(basisT , Ft0[3][2:end]) + push!(grams,Ft0[4][2:end,2:end]) + push!(fiber_componentsS, vcat([pt], collect(Ft0))) + end + G = block_diagonal_matrix(grams) + # make way for some more pretty printing + for (pt,root_type,_,comp) in fiber_componentsS + for (i,I) in enumerate(comp) + name = string(root_type[1], root_type[2]) + set_attribute!(components(I)[1], :name, string("Component ", name, "_", i-1," of fiber over ", Tuple(pt))) + set_attribute!(components(I)[1], :_self_intersection, -2) end - return basisT, G, fiber_componentsS end + return basisT, G, fiber_componentsS end function _reducible_fibers_disc(X::EllipticSurface; sort::Bool=true) diff --git a/src/AlgebraicGeometry/Surfaces/EllipticSurface/Morphisms.jl b/src/AlgebraicGeometry/Surfaces/EllipticSurface/Morphisms.jl index ba8f47810feb..a085bacb96e1 100644 --- a/src/AlgebraicGeometry/Surfaces/EllipticSurface/Morphisms.jl +++ b/src/AlgebraicGeometry/Surfaces/EllipticSurface/Morphisms.jl @@ -94,12 +94,10 @@ end end -function raw_reduction_of_algebraic_lattice(X::EllipticSurface) - return get_attribute!(X, :raw_reduction_of_algebraic_lattice) do - X_red_raw, bc = raw_good_reduction(X) - basis_ambient, _, _= algebraic_lattice(X) - return red_dict = IdDict{AbsWeilDivisor, AbsWeilDivisor}(D=>_reduce_as_prime_divisor(bc, D) for D in basis_ambient) - end::IdDict +@attr IdDict function raw_reduction_of_algebraic_lattice(X::EllipticSurface) + X_red_raw, bc = raw_good_reduction(X) + basis_ambient, _, _= algebraic_lattice(X) + return red_dict = IdDict{AbsWeilDivisor, AbsWeilDivisor}(D=>_reduce_as_prime_divisor(bc, D) for D in basis_ambient) end @attr ZZMatrix function good_reduction_algebraic_lattice(X::EllipticSurface) diff --git a/src/AlgebraicGeometry/ToricVarieties/CohomologyClasses/special_attributes.jl b/src/AlgebraicGeometry/ToricVarieties/CohomologyClasses/special_attributes.jl index 293c7d49cfd6..06444ea2cde3 100644 --- a/src/AlgebraicGeometry/ToricVarieties/CohomologyClasses/special_attributes.jl +++ b/src/AlgebraicGeometry/ToricVarieties/CohomologyClasses/special_attributes.jl @@ -15,18 +15,14 @@ julia> ngens(cohomology_ring(p2)) 3 ``` """ -function cohomology_ring(v::NormalToricVarietyType; check::Bool = true) - if has_attribute(v, :cohomology_ring) - return get_attribute(v, :cohomology_ring) - end +@attr Any function cohomology_ring(v::NormalToricVarietyType; check::Bool = true) if check @req is_simplicial(v) && is_complete(v) "The cohomology ring is only supported for simplicial and complete toric varieties" end R, _ = graded_polynomial_ring(coefficient_ring(v), coordinate_names(v); cached=false) linear_relations = ideal_of_linear_relations(R, v) stanley_reisner = stanley_reisner_ideal(R, v) - set_attribute!(v, :cohomology_ring, quo(R, linear_relations + stanley_reisner)[1]) - return get_attribute(v, :cohomology_ring) + return quo(R, linear_relations + stanley_reisner)[1] end @@ -250,19 +246,15 @@ julia> betti_number(Y, 4) == length(h4_basis) true ``` """ -function basis_of_h4(v::NormalToricVariety; check::Bool = true)::Vector{CohomologyClass} +@attr Vector{CohomologyClass} function basis_of_h4(v::NormalToricVariety; check::Bool = true) if check @req is_complete(v) "Computation of basis of H4(X, Q) is currently only supported for complete toric varieties" @req is_simplicial(v) "Computation of basis of H4(X, Q) is currently only supported for simplicial toric varieties" end if dim(v) < 4 - set_attribute!(v, :basis_of_h4, Vector{CohomologyClass}()) - end - if has_attribute(v, :basis_of_h4) - return get_attribute(v, :basis_of_h4) + return Vector{CohomologyClass}() end - R = cohomology_ring(v, check = check) + R = cohomology_ring(v; check = check) basis_of_h4 = [cohomology_class(v, R(g)) for g in monomial_basis(R, [2])] - set_attribute!(v, :basis_of_h4, basis_of_h4) return basis_of_h4 end diff --git a/src/AlgebraicGeometry/ToricVarieties/NormalToricVarieties/attributes.jl b/src/AlgebraicGeometry/ToricVarieties/NormalToricVarieties/attributes.jl index 9855950206a5..fd34832e41ae 100644 --- a/src/AlgebraicGeometry/ToricVarieties/NormalToricVarieties/attributes.jl +++ b/src/AlgebraicGeometry/ToricVarieties/NormalToricVarieties/attributes.jl @@ -217,11 +217,9 @@ julia> coordinate_names(antv) end -function _cox_ring_weights(v::NormalToricVarietyType) - return get_attribute!(v, :cox_ring_weights) do - f = map_from_torusinvariant_weil_divisor_group_to_class_group(v) - return [f(x) for x in gens(torusinvariant_weil_divisor_group(v))] - end::Vector{FinGenAbGroupElem} +@attr Vector{FinGenAbGroupElem} function _cox_ring_weights(v::NormalToricVarietyType) + f = map_from_torusinvariant_weil_divisor_group_to_class_group(v) + return [f(x) for x in gens(torusinvariant_weil_divisor_group(v))] end diff --git a/src/AlgebraicGeometry/ToricVarieties/cohomCalg/special_attributes.jl b/src/AlgebraicGeometry/ToricVarieties/cohomCalg/special_attributes.jl index cb8712647934..aa699f302396 100644 --- a/src/AlgebraicGeometry/ToricVarieties/cohomCalg/special_attributes.jl +++ b/src/AlgebraicGeometry/ToricVarieties/cohomCalg/special_attributes.jl @@ -87,113 +87,109 @@ julia> all_cohomologies(toric_line_bundle(dP3, [1, 2, 3, 4])) 0 ``` """ -function all_cohomologies(l::ToricLineBundle) +@attr Vector{ZZRingElem} function all_cohomologies(l::ToricLineBundle) # check if we can apply cohomCalg v = toric_variety(l) if !((is_smooth(v) && is_complete(v)) || (is_simplicial(v) && is_projective(v))) throw(ArgumentError("cohomCalg only applies to toric varieties that are either smooth, complete or simplicial, projective")) end - # extract vector of currently-known cohomology dimensions (or create it if necessary) - return get_attribute!(l, :all_cohomologies) do - - # Minimal example: - # - # The following lines provide an interface to cohomCalg. This is easiest explained with an example. - # - # Example: Compute the cohomologies of the structure sheaf of the 2-dimensional projective space. - # - # Step 1: We trigger the following command so that cohomCalg computes these cohomologies for us: - # - # ./cohomCalg "vertex x1 | GLSM: ( 1 ); vertex x2 | GLSM: ( 1 ); vertex x3 | GLSM: ( 1 ); srideal [x1*x2*x3]; ambientcohom O(0 );" - # - # The notation GLSM is for generalized linear sigma model. - # This is a physics model which famously triggered interest in toric geometry for physics applications. - # The cohomCalg algorithm relies only on the grading of the Cox ring and the Stanley-Reisner ideal. - # <-> Those two pieces of information are (more or less) the defining data of a GLSM. - # - # Step 2: We receive the following return value from cohomCalg: - # - # "{True, {{1,0,0}, {{0, 1*1}}}}" - # - # The "True" tells us that the run was successful. Otherwise, we would find "False". - # - # Whenever we encounter "False", this most likely indicates wrong input data. This could be any of the following: - # (a) wrong variable names: cohomCalg accepts "x1, x2, ..." (and also "y1, y2, ..."), but "_x1, _x2" or "x[1]", "x[2]" will cause errors. - # (b) an inconsistent grading of the Cox ring: This could e.g. lead to infinitely many monoms of a fixed degree. - # (c) an inconsistent Stanley-Reisner ideal. - # - # For sake of simplicity, our implementation creates a dictionary that maps "our" variable names to "x1, x2, ...". - # The latter are then passed to cohomCalg. - # - # After this boolean, the above return value contains the line bundle cohomologies and some intermediate results. - # The first argument in the { }-brackets are the line bundle cohomologies in question. Here: {1,0,0}. - # - # By the cohomCalg algorithm, the line bundle cohomologies are given by certain rationoms, that is fractions of - # monoms in the Cox ring of the variety. Behind the scenes, cohomCalg reads-off monomials which contribute - # to the denominators of these rationoms. For sake of simplicity, let us refer to these monomials as "partial-denominators". - # - # Crucially: These partial-denominators are read-off from the Stanley-Reisner ideal. Hence, they encode information about - # the toric space and are not specific to a certain line bundle. In https://arxiv.org/abs/1802.08860, this is used to infer - # refined vanishing sets of line bundle cohomologies on toric spaces. Implementations of which are currently available in - # https://github.com/homalg-project/ToricVarieties_project and will be migrated to OSCAR soon. - # - # To make contact with a line bundle in question, pick a partial-denominator and look for all rationoms with multi-degree - # matching that of the line bundle in question. In particular, under the assumptions that the variety in question be either - # smooth, complete or alternatively simplicial, projective, one finds a finite number of such rationoms for each partial-denominator. - # - # Once these rationoms are identified, two questions remain: - # (1) To which line bundle cohomology do they contribute? - # (2) Could they encode more than a one-dimensional linear subspace of these cohomology spaces? - # - # The answers to both questions are involved and described in detail in the original work https://arxiv.org/pdf/1003.5217.pdf - # and the proofs of this algorithm in https://arxiv.org/abs/1006.2392, https://arxiv.org/abs/1006.0780. In particular note that - # the answer to (2) involved the evaluation of certain "remnant cohomologies", so that a single rationom may indeed encode - # a vector space of line bundle cohomologies which is strictly larger than 1. - # - # Let us now return to the above return value {{0, 1*1}}. The fact that this list contains only a single sub-list states that only - # a single partial-denominator was identified. The first value tells to which cohomology group it contributes. Here we find 0, - # so it contributes to H^0. The second value is, in the following order, the product of the multiplicity (as in response to - # (2) above) and the exact form of the partial-denominator. So here the multiplicity is 1 and the partial-denominator is 1. - # For other examples, we could for example find "2 * x2 * x3 * x5", which would mean that the multiplicity is 2 - # and the partial denominator in question is "x2 * x3 * x5". - # - # For more details, please refer to the cohomCalg manual: https://arxiv.org/pdf/1003.5217.pdf. - # - # Step 3: Extract "True" (or "False") and the first argument of the following "{ }" by suitable parsing. - # - # -> Hooray! We found the line bundle cohomologies in question. - - # obtain the command string - class = vec([ZZRingElem(x) for x in divisor_class(toric_divisor_class(l)).coeff]) - command = command_string(v, class) - - # execute cohomCalg - out = Pipe() - err = Pipe() - process = run(pipeline(ignorestatus(`$(cohomCalg_jll.cohomcalg()) --integrated --in=$(command)`), stdout=out, stderr=err)) - close(out.in) - close(err.in) - - # was there an error? - stderr = read(err, String) - code = process.exitcode - if code != 0 - error("cohomCalg encountered the error " * stderr) - end - - # read out the result - stdout = read(out, String) - result = [parse(ZZRingElem, c) for c in split(chop(chop(split(stdout, "{" )[4])), ",")] - - # consistency check - if length(result) != dim(v)+1 - error("cohomCalg should return list of length $(dim(v)+1) but returned list of length $(length(result))") - end - - # return result - return result - end::Vector{ZZRingElem} + # Minimal example: + # + # The following lines provide an interface to cohomCalg. This is easiest explained with an example. + # + # Example: Compute the cohomologies of the structure sheaf of the 2-dimensional projective space. + # + # Step 1: We trigger the following command so that cohomCalg computes these cohomologies for us: + # + # ./cohomCalg "vertex x1 | GLSM: ( 1 ); vertex x2 | GLSM: ( 1 ); vertex x3 | GLSM: ( 1 ); srideal [x1*x2*x3]; ambientcohom O(0 );" + # + # The notation GLSM is for generalized linear sigma model. + # This is a physics model which famously triggered interest in toric geometry for physics applications. + # The cohomCalg algorithm relies only on the grading of the Cox ring and the Stanley-Reisner ideal. + # <-> Those two pieces of information are (more or less) the defining data of a GLSM. + # + # Step 2: We receive the following return value from cohomCalg: + # + # "{True, {{1,0,0}, {{0, 1*1}}}}" + # + # The "True" tells us that the run was successful. Otherwise, we would find "False". + # + # Whenever we encounter "False", this most likely indicates wrong input data. This could be any of the following: + # (a) wrong variable names: cohomCalg accepts "x1, x2, ..." (and also "y1, y2, ..."), but "_x1, _x2" or "x[1]", "x[2]" will cause errors. + # (b) an inconsistent grading of the Cox ring: This could e.g. lead to infinitely many monoms of a fixed degree. + # (c) an inconsistent Stanley-Reisner ideal. + # + # For sake of simplicity, our implementation creates a dictionary that maps "our" variable names to "x1, x2, ...". + # The latter are then passed to cohomCalg. + # + # After this boolean, the above return value contains the line bundle cohomologies and some intermediate results. + # The first argument in the { }-brackets are the line bundle cohomologies in question. Here: {1,0,0}. + # + # By the cohomCalg algorithm, the line bundle cohomologies are given by certain rationoms, that is fractions of + # monoms in the Cox ring of the variety. Behind the scenes, cohomCalg reads-off monomials which contribute + # to the denominators of these rationoms. For sake of simplicity, let us refer to these monomials as "partial-denominators". + # + # Crucially: These partial-denominators are read-off from the Stanley-Reisner ideal. Hence, they encode information about + # the toric space and are not specific to a certain line bundle. In https://arxiv.org/abs/1802.08860, this is used to infer + # refined vanishing sets of line bundle cohomologies on toric spaces. Implementations of which are currently available in + # https://github.com/homalg-project/ToricVarieties_project and will be migrated to OSCAR soon. + # + # To make contact with a line bundle in question, pick a partial-denominator and look for all rationoms with multi-degree + # matching that of the line bundle in question. In particular, under the assumptions that the variety in question be either + # smooth, complete or alternatively simplicial, projective, one finds a finite number of such rationoms for each partial-denominator. + # + # Once these rationoms are identified, two questions remain: + # (1) To which line bundle cohomology do they contribute? + # (2) Could they encode more than a one-dimensional linear subspace of these cohomology spaces? + # + # The answers to both questions are involved and described in detail in the original work https://arxiv.org/pdf/1003.5217.pdf + # and the proofs of this algorithm in https://arxiv.org/abs/1006.2392, https://arxiv.org/abs/1006.0780. In particular note that + # the answer to (2) involved the evaluation of certain "remnant cohomologies", so that a single rationom may indeed encode + # a vector space of line bundle cohomologies which is strictly larger than 1. + # + # Let us now return to the above return value {{0, 1*1}}. The fact that this list contains only a single sub-list states that only + # a single partial-denominator was identified. The first value tells to which cohomology group it contributes. Here we find 0, + # so it contributes to H^0. The second value is, in the following order, the product of the multiplicity (as in response to + # (2) above) and the exact form of the partial-denominator. So here the multiplicity is 1 and the partial-denominator is 1. + # For other examples, we could for example find "2 * x2 * x3 * x5", which would mean that the multiplicity is 2 + # and the partial denominator in question is "x2 * x3 * x5". + # + # For more details, please refer to the cohomCalg manual: https://arxiv.org/pdf/1003.5217.pdf. + # + # Step 3: Extract "True" (or "False") and the first argument of the following "{ }" by suitable parsing. + # + # -> Hooray! We found the line bundle cohomologies in question. + + # obtain the command string + class = vec([ZZRingElem(x) for x in divisor_class(toric_divisor_class(l)).coeff]) + command = command_string(v, class) + + # execute cohomCalg + out = Pipe() + err = Pipe() + process = run(pipeline(ignorestatus(`$(cohomCalg_jll.cohomcalg()) --integrated --in=$(command)`), stdout=out, stderr=err)) + close(out.in) + close(err.in) + + # was there an error? + stderr = read(err, String) + code = process.exitcode + if code != 0 + error("cohomCalg encountered the error " * stderr) + end + + # read out the result + stdout = read(out, String) + result = [parse(ZZRingElem, c) for c in split(chop(chop(split(stdout, "{" )[4])), ",")] + + # consistency check + if length(result) != dim(v)+1 + error("cohomCalg should return list of length $(dim(v)+1) but returned list of length $(length(result))") + end + + # return result + return result end diff --git a/src/Groups/group_characters.jl b/src/Groups/group_characters.jl index 0c10ed48f385..bf9fc0a7f828 100644 --- a/src/Groups/group_characters.jl +++ b/src/Groups/group_characters.jl @@ -306,7 +306,7 @@ julia> Oscar.with_unicode() do ``` """ function character_table(G::Union{GAPGroup, FinGenAbGroup}, p::T = 0) where T <: IntegerUnion - tbls = get_attribute!(G, :character_tables, Dict{Int,Any}()) + tbls = get_attribute!(Dict{Int,Any}, G, :character_tables) return get!(tbls, p) do p != 0 && return mod(character_table(G, 0), p) iso = isomorphism_to_GAP_group(G) @@ -1285,7 +1285,7 @@ function Base.mod(tbl::GAPGroupCharacterTable, p::T) where T <: IntegerUnion @req is_prime(p) "p must be a prime integer" characteristic(tbl) == 0 || error("tbl mod p only for ordinary table tbl") - modtbls = get_attribute!(tbl, :brauer_tables, Dict{Int,Any}()) + modtbls = get_attribute!(Dict{Int,Any}, tbl, :brauer_tables) if !haskey(modtbls, p) modtblgap = mod(GapObj(tbl), GAP.Obj(p))::GapObj if modtblgap === GAP.Globals.fail diff --git a/src/Groups/matrices/form_group.jl b/src/Groups/matrices/form_group.jl index cdd80cab3735..60d97eedf190 100644 --- a/src/Groups/matrices/form_group.jl +++ b/src/Groups/matrices/form_group.jl @@ -679,12 +679,10 @@ Setting the parameters `depth` and `bacher_depth` to a positive value may improv performance. If set to `-1` (default), the used value of `depth` is chosen heuristically depending on the rank of `L`. By default, `bacher_depth` is set to `0`. """ -function isometry_group(L::Hecke.AbstractLat; depth::Int = -1, bacher_depth::Int = 0) - get_attribute!(L, :isometry_group) do - gens = automorphism_group_generators(L, depth = depth, bacher_depth = bacher_depth) - G = matrix_group(gens) - return G - end::MatrixGroup{elem_type(base_field(L)), dense_matrix_type(elem_type(base_field(L)))} +@attr MatrixGroup{elem_type(base_field(L)),dense_matrix_type(elem_type(base_field(L)))} function isometry_group(L::Hecke.AbstractLat; depth::Int=-1, bacher_depth::Int=0) + gens = automorphism_group_generators(L; depth, bacher_depth) + G = matrix_group(gens) + return G end @doc raw""" @@ -703,30 +701,27 @@ Setting the parameters `depth` and `bacher_depth` to a positive value may improv performance. If set to `-1` (default), the used value of `depth` is chosen heuristically depending on the rank of `L`. By default, `bacher_depth` is set to `0`. """ -function isometry_group(L::ZZLat; algorithm = :direct, depth::Int = -1, bacher_depth::Int = 0) - get_attribute!(L, :isometry_group) do - - # corner case - @req rank(L) <= 2 || is_definite(L) "Lattice must be definite or of rank at most 2" - if rank(L) == 0 - G = matrix_group(identity_matrix(QQ,degree(L))) - end +@attr MatrixGroup{QQFieldElem,QQMatrix} function isometry_group(L::ZZLat; algorithm=:direct, depth::Int=-1, bacher_depth::Int=0) + # corner case + @req rank(L) <= 2 || is_definite(L) "Lattice must be definite or of rank at most 2" + if rank(L) == 0 + G = matrix_group(identity_matrix(QQ, degree(L))) + end - if !is_definite(L) && (rank(L) == 2) - gene = automorphism_group_generators(L) - G = matrix_group(QQMatrix[change_base_ring(QQ, m) for m in gene]) - end + if !is_definite(L) && (rank(L) == 2) + gene = automorphism_group_generators(L) + G = matrix_group(QQMatrix[change_base_ring(QQ, m) for m in gene]) + end - if algorithm == :direct - gens = automorphism_group_generators(L, depth = depth, bacher_depth = bacher_depth) - G = matrix_group(gens) - elseif algorithm == :decomposition - G, _ = _isometry_group_via_decomposition(L, depth = depth, bacher_depth = bacher_depth) - else - error("Unknown algorithm: for the moment, we support :direct or :decomposition") - end - return G - end::MatrixGroup{QQFieldElem, QQMatrix} + if algorithm == :direct + gens = automorphism_group_generators(L; depth=depth, bacher_depth=bacher_depth) + G = matrix_group(gens) + elseif algorithm == :decomposition + G, _ = _isometry_group_via_decomposition(L; depth=depth, bacher_depth=bacher_depth) + else + error("Unknown algorithm: for the moment, we support :direct or :decomposition") + end + return G end """ diff --git a/src/Modules/Posur.jl b/src/Modules/Posur.jl index 31fb097c0e2e..3cfbc17ccaa4 100644 --- a/src/Modules/Posur.jl +++ b/src/Modules/Posur.jl @@ -234,14 +234,11 @@ not a free module, the user needs to specify a `base_ring_module` of ``M``. If ``M`` arises as a localization of some ``R``-module ``M'``, then this connection is cached here. """ -function base_ring_module(F::FreeMod{T}) where {T<:AbsLocalizedRingElem} - if !has_attribute(F, :base_ring_module) - L = base_ring(F) - R = base_ring(L) - Fb = FreeMod(R, ngens(F)) - set_attribute!(F, :base_ring_module, Fb) - end - return get_attribute(F, :base_ring_module)::base_ring_module_type(F) +@attr base_ring_module_type(F) function base_ring_module(F::FreeMod{T}) where {T<:AbsLocalizedRingElem} + L = base_ring(F) + R = base_ring(L) + Fb = FreeMod(R, ngens(F)) + return Fb end base_ring_module_type(::Type{FreeMod{T}}) where {T<:AbsLocalizedRingElem} = FreeMod{elem_type(base_ring_type(T))} @@ -249,13 +246,10 @@ base_ring_module_type(F::FreeMod{T}) where {T<:AbsLocalizedRingElem} = base_ring # for a free module F ≅ Sʳ over a localized ring S = R[U⁻¹] this # returns the canonical map F♭ ≅ Rʳ → Sʳ ≅ F. -function base_ring_module_map(F::FreeMod{T}) where {T<:AbsLocalizedRingElem} - if !has_attribute(F, :base_ring_module_map) +@attr morphism_type(base_ring_module_type(F), typeof(F)) function base_ring_module_map(F::FreeMod{T}) where {T<:AbsLocalizedRingElem} Fb = base_ring_module(F) f = hom(Fb, F, gens(F)) - set_attribute!(F, :base_ring_module_map, f) - end - return get_attribute(F, :base_ring_module_map)::morphism_type(base_ring_module_type(F), typeof(F)) + return f end # For a SubquoModule M over a localized ring S = R[U⁻¹] this returns the SubquoModule N over R @@ -263,7 +257,7 @@ end # been cached. function pre_saturated_module(M::SubquoModule{T}) where {T<:AbsLocalizedRingElem} has_attribute(M, :saturated_module) && return get_attribute(M, :saturated_module)::SubquoModule{elem_type(base_ring_type(T))} - if !has_attribute(M, :pre_saturated_module) + return get_attribute!(M, :pre_saturated_module) do (A, D) = clear_denominators(generator_matrix(M)) (B, E) = clear_denominators(relations_matrix(M)) S = base_ring(M) @@ -273,9 +267,8 @@ function pre_saturated_module(M::SubquoModule{T}) where {T<:AbsLocalizedRingElem Mb = SubquoModule(Fb, A, B) set_attribute!(M, :pre_saturation_data_gens, change_base_ring(S, D)) set_attribute!(M, :pre_saturation_data_rels, change_base_ring(S, E)) - set_attribute!(M, :pre_saturated_module, Mb) - end - return get_attribute(M, :pre_saturated_module)::SubquoModule{elem_type(base_ring_type(T))} + return Mb + end::SubquoModule{elem_type(base_ring_type(T))} end # For a SubquoModule M over a localized ring S = R[U⁻¹] and its current diff --git a/src/Modules/mpolyquo-localizations.jl b/src/Modules/mpolyquo-localizations.jl index cd8f37fef4e8..9c49737e7e5f 100644 --- a/src/Modules/mpolyquo-localizations.jl +++ b/src/Modules/mpolyquo-localizations.jl @@ -76,7 +76,7 @@ end function pre_saturated_module(M::SubquoModule{T}) where {T<:MPolyQuoLocRingElem} has_attribute(M, :saturated_module) && return get_attribute(M, :saturated_module)::SubquoModule{elem_type(base_ring_type(T))} - if !has_attribute(M, :pre_saturated_module) + return get_attribute!(M, :pre_saturated_module) do S = base_ring(M) R = base_ring(S) (A, D) = clear_denominators(generator_matrix(M)) @@ -93,9 +93,8 @@ function pre_saturated_module(M::SubquoModule{T}) where {T<:MPolyQuoLocRingElem} Mb = SubquoModule(Fb, A, B) set_attribute!(M, :pre_saturation_data_gens, change_base_ring(S, D)) set_attribute!(M, :pre_saturation_data_rels, change_base_ring(S, E)) - set_attribute!(M, :pre_saturated_module, Mb) - end - return get_attribute(M, :pre_saturated_module)::SubquoModule{elem_type(base_ring_type(T))} + return Mb + end::SubquoModule{elem_type(base_ring_type(T))} end # The kernel routine has to be overwritten since the base_ring_module of a diff --git a/src/Rings/MPolyMap/AffineAlgebras.jl b/src/Rings/MPolyMap/AffineAlgebras.jl index 0023fd757740..a0fb5d2146a8 100644 --- a/src/Rings/MPolyMap/AffineAlgebras.jl +++ b/src/Rings/MPolyMap/AffineAlgebras.jl @@ -48,11 +48,9 @@ end Return the kernel of `F`. """ -function kernel(f::AffAlgHom) - get_attribute!(f, :kernel) do - C = codomain(f) - return preimage(f, ideal(C, [zero(C)])) - end # TODO: need some ideal_type(domain(f)) here :) +@attr Any function kernel(f::AffAlgHom) # TODO: need some ideal_type(domain(f)) here :) + C = codomain(f) + return preimage(f, ideal(C, [zero(C)])) end ############################################################################## diff --git a/src/Rings/MPolyMap/flattenings.jl b/src/Rings/MPolyMap/flattenings.jl index d6397025f702..cd05674910b0 100644 --- a/src/Rings/MPolyMap/flattenings.jl +++ b/src/Rings/MPolyMap/flattenings.jl @@ -455,16 +455,12 @@ function flat_counterparts(phi::RingFlattening) end ### Some basic functionality -function flatten(R::MPolyRing; cached::Bool=false) - return get_attribute!(R, :flatten) do - RingFlattening(R; cached) - end::RingFlattening{typeof(R)} +@attr RingFlattening{typeof(R)} function flatten(R::MPolyRing; cached::Bool=false) + return RingFlattening(R; cached) end -function flatten(R::MPolyQuoRing; cached::Bool=false) - return get_attribute!(R, :flatten) do - RingFlattening(R; cached) - end::RingFlattening{typeof(R)} +@attr RingFlattening{typeof(R)} function flatten(R::MPolyQuoRing; cached::Bool=false) + return RingFlattening(R; cached) end function (phi::RingFlattening)(I::MPolyIdeal) diff --git a/src/Rings/MPolyQuo.jl b/src/Rings/MPolyQuo.jl index 1be0346592c1..481619da0f5d 100644 --- a/src/Rings/MPolyQuo.jl +++ b/src/Rings/MPolyQuo.jl @@ -554,12 +554,10 @@ end return is_prime(saturated_ideal(I)) end -function radical(I::MPolyQuoIdeal; eliminate_variables::Bool=true) - get_attribute!(I, :radical) do - R = base_ring(I) - J = saturated_ideal(I) - return ideal(R, [g for g in R.(gens(radical(J; eliminate_variables))) if !iszero(g)]) - end::typeof(I) +@attr typeof(I) function radical(I::MPolyQuoIdeal; eliminate_variables::Bool=true) + R = base_ring(I) + J = saturated_ideal(I) + return ideal(R, [g for g in R.(gens(radical(J; eliminate_variables))) if !iszero(g)]) end # The following is to streamline the programmer's @@ -1886,18 +1884,16 @@ julia> small_generating_set(a) ``` """ -function small_generating_set( +@attr Vector{elem_type(base_ring(I))} function small_generating_set( I::MPolyQuoIdeal; algorithm::Symbol=:simple ) - return get_attribute!(I, :small_generating_set) do - # For non-homogeneous ideals, we do not have a notion of minimal generating - # set, but Singular.mstd still provides a good heuristic to find a small - # generating set. - Q = base_ring(I) - # Temporary workaround, see #3499 - unique!(filter!(!iszero, Q.(small_generating_set(saturated_ideal(I); algorithm)))) - end::Vector{elem_type(base_ring(I))} + # For non-homogeneous ideals, we do not have a notion of minimal generating + # set, but Singular.mstd still provides a good heuristic to find a small + # generating set. + Q = base_ring(I) + # Temporary workaround, see #3499 + unique!(filter!(!iszero, Q.(small_generating_set(saturated_ideal(I); algorithm)))) end # in the graded case, reusing a cached gb makes sense, so use minimal_generating set there diff --git a/src/Rings/mpoly-affine-algebras.jl b/src/Rings/mpoly-affine-algebras.jl index 925ae4186ca3..5a44d32fcf39 100644 --- a/src/Rings/mpoly-affine-algebras.jl +++ b/src/Rings/mpoly-affine-algebras.jl @@ -950,17 +950,15 @@ julia> is_normal(A) true ``` """ -function is_normal(A::MPolyQuoRing; check::Bool=true) - return get_attribute!(A, :is_normal) do - @req coefficient_ring(A) isa AbstractAlgebra.Field "Only implemented if coefficient ring is a field" - @req is_perfect(coefficient_ring(A)) "Only implemented if coefficient ring is a perfect field" - @req !(base_ring(A) isa MPolyDecRing) "Not implemented for quotients of decorated rings" - !check || is_reduced(A) || return false - - I = A.I - f = Singular.LibNormal.isNormal(singular_generators(I))::Int - return Bool(f) - end +@attr Bool function is_normal(A::MPolyQuoRing; check::Bool=true) + @req coefficient_ring(A) isa AbstractAlgebra.Field "Only implemented if coefficient ring is a field" + @req is_perfect(coefficient_ring(A)) "Only implemented if coefficient ring is a perfect field" + @req !(base_ring(A) isa MPolyDecRing) "Not implemented for quotients of decorated rings" + !check || is_reduced(A) || return false + + I = A.I + f = Singular.LibNormal.isNormal(singular_generators(I))::Int + return Bool(f) end @doc raw""" diff --git a/src/Rings/mpoly-ideals.jl b/src/Rings/mpoly-ideals.jl index 6258c5efcf79..caae8c2f7312 100644 --- a/src/Rings/mpoly-ideals.jl +++ b/src/Rings/mpoly-ideals.jl @@ -606,28 +606,23 @@ Ideal generated by 3*a^15*b^4*c^5*d^5 ``` """ -function radical( - I::MPolyIdeal{T}; - eliminate_variables::Bool=true - ) where {T <: MPolyRingElem} - get_attribute!(I, :radical) do - if eliminate_variables - is_known_to_be_radical(I) && return I - # Calling `elimpart` (within `simplify`) turns out to significantly speed things up in many cases. - R = base_ring(I) - Q, pr = quo(R, I) - S, iso, iso_inv = simplify(Q) - is_zero(ngens(S)) && return I # This only happens when all variables can be eliminated. - # Then the ideal defines a reduced point. - J = modulus(S) - pre_res = _compute_radical(J) - pre_res = ideal(R, elem_type(R)[lift(iso_inv(S(g))) for g in gens(pre_res)]) - res = ideal(R, small_generating_set(pre_res + I)) - set_attribute!(res, :is_radical=>true) - return res - end - return _compute_radical(I) - end::MPolyIdeal{T} +@attr MPolyIdeal{T} function radical(I::MPolyIdeal{T}; eliminate_variables::Bool=true) where {T <: MPolyRingElem} + if eliminate_variables + is_known_to_be_radical(I) && return I + # Calling `elimpart` (within `simplify`) turns out to significantly speed things up in many cases. + R = base_ring(I) + Q, pr = quo(R, I) + S, iso, iso_inv = simplify(Q) + is_zero(ngens(S)) && return I # This only happens when all variables can be eliminated. + # Then the ideal defines a reduced point. + J = modulus(S) + pre_res = _compute_radical(J) + pre_res = ideal(R, elem_type(R)[lift(iso_inv(S(g))) for g in gens(pre_res)]) + res = ideal(R, small_generating_set(pre_res + I)) + set_attribute!(res, :is_radical=>true) + return res + end + return _compute_radical(I) end function _compute_radical(I::T) where {T <: MPolyIdeal} @@ -651,40 +646,38 @@ function _compute_radical(I::T) where {T <: MPolyIdeal} end # Rerouting via expansion of the coefficient field -function radical( +@attr MPolyIdeal{T} function radical( I::MPolyIdeal{T}; factor_generators::Bool=true, eliminate_variables::Bool=true ) where {U<:Union{AbsSimpleNumFieldElem, <:Hecke.RelSimpleNumFieldElem}, T<:MPolyRingElem{U}} is_known_to_be_radical(I) && return I - get_attribute!(I, :radical) do - is_one(I) && return I - R = base_ring(I) - J = ideal(R, zero(R)) - if factor_generators - # In practice this will often lead to significant speedup due to reduction of degrees. - # TODO: is the following faster? radical(ab,c) = intersect(radical(a,c),radical(b,c)) - for g in gens(I) - is_zero(g) && continue - fact = factor(g) - is_empty(fact) && continue - h = one(g) - for (x, k) in fact - h = h*x - end - J = J + ideal(R, h) + is_one(I) && return I + R = base_ring(I) + J = ideal(R, zero(R)) + if factor_generators + # In practice this will often lead to significant speedup due to reduction of degrees. + # TODO: is the following faster? radical(ab,c) = intersect(radical(a,c),radical(b,c)) + for g in gens(I) + is_zero(g) && continue + fact = factor(g) + is_empty(fact) && continue + h = one(g) + for (x, k) in fact + h = h*x end - else - J = I + J = J + ideal(R, h) end - R_flat, iso, iso_inv = _expand_coefficient_field_to_QQ(R) - I_flat = ideal(R_flat, iso_inv.(gens(J))) - I_flat_rad = radical(I_flat; eliminate_variables) - Irad = iso(I_flat_rad) - set_attribute!(Irad, :is_radical => true) - @hassert :IdealSheaves 2 !is_one(Irad) - Irad - end::MPolyIdeal{T} + else + J = I + end + R_flat, iso, iso_inv = _expand_coefficient_field_to_QQ(R) + I_flat = ideal(R_flat, iso_inv.(gens(J))) + I_flat_rad = radical(I_flat; eliminate_variables) + Irad = iso(I_flat_rad) + set_attribute!(Irad, :is_radical => true) + @hassert :IdealSheaves 2 !is_one(Irad) + return Irad end function map_coefficients(mp, I::MPolyIdeal; parent = nothing) @@ -707,8 +700,8 @@ Computes the radical. end function is_known_to_be_radical(I::Ideal) - has_attribute(I, :is_radical) && get_attribute(I, :is_radical) === true && return true - has_attribute(I, :is_prime) && get_attribute(I, :is_prime) === true && return true + get_attribute(I, :is_radical, false) && return true + get_attribute(I, :is_prime, false) && return true return false end diff --git a/src/Rings/mpoly-localizations.jl b/src/Rings/mpoly-localizations.jl index 3811794b4acb..a1c592de8c1c 100644 --- a/src/Rings/mpoly-localizations.jl +++ b/src/Rings/mpoly-localizations.jl @@ -1610,24 +1610,21 @@ function _diagonal_sparse_matrix(L::Ring, v::Vector{T}) where {T<:RingElem} return A end -function coordinate_shift( +@attr Map function coordinate_shift( L::MPolyLocRing{<:Any, <:Any, <:Any, <:Any, <:MPolyComplementOfKPointIdeal} ) - if !has_attribute(L, :coordinate_shift) - U = inverted_set(L) - a = point_coordinates(U) - R = base_ring(L) - Ls = MPolyLocRing(R, MPolyComplementOfKPointIdeal(R, [0 for i in 1:ngens(R)])) - xs = [ x + a for (x, a) in zip(gens(base_ring(L)), a) ] - xs_inv = [ x - a for (x, a) in zip(gens(base_ring(L)), a) ] - shift = MapFromFunc( - L, Ls, - f -> Ls(evaluate(numerator(f), xs), evaluate(denominator(f), xs), check=false), - g -> L(evaluate(numerator(g), xs_inv), evaluate(denominator(g), xs_inv), check=false), - ) - set_attribute!(L, :coordinate_shift, shift) - end - return get_attribute(L, :coordinate_shift)::Map + U = inverted_set(L) + a = point_coordinates(U) + R = base_ring(L) + Ls = MPolyLocRing(R, MPolyComplementOfKPointIdeal(R, [0 for i in 1:ngens(R)])) + xs = [ x + a for (x, a) in zip(gens(base_ring(L)), a) ] + xs_inv = [ x - a for (x, a) in zip(gens(base_ring(L)), a) ] + shift = MapFromFunc( + L, Ls, + f -> Ls(evaluate(numerator(f), xs), evaluate(denominator(f), xs), check=false), + g -> L(evaluate(numerator(g), xs_inv), evaluate(denominator(g), xs_inv), check=false), + ) + return shift end @@ -2641,7 +2638,7 @@ true ### Some auxiliary functions @attr MPolyLocalizedIdeal function radical(I::MPolyLocalizedIdeal) - has_attribute(I, :is_prime) && get_attribute(I, :is_prime) && return I + get_attribute(I, :is_prime, false) && return I # heuristics have shown that the radical of the saturated ideal # is often quicker #J = pre_saturated_ideal(I) @@ -2778,19 +2775,17 @@ small_generating_set(I::MPolyLocalizedIdeal{<:MPolyLocRing{<:Field, <:FieldElem, <:MPolyRing, <:MPolyRingElem, <:MPolyComplementOfKPointIdeal}}) = minimal_generating_set(I) -function small_generating_set( +@attr Vector{elem_type(base_ring(I))} function small_generating_set( I::MPolyLocalizedIdeal{<:MPolyLocRing{<:Field, <:FieldElem, <:MPolyRing, <:MPolyRingElem, <:MPolyPowersOfElement}}; algorithm::Symbol=:simple ) - get_attribute!(I, :small_generating_set) do - L = base_ring(I) - R = base_ring(L) - #I_min = L.(small_generating_set(saturated_ideal(I))) - I_min = L.(small_generating_set(ideal(R, numerator.(gens(I))))) - filter(!iszero, I_min) - end::Vector{elem_type(base_ring(I))} + L = base_ring(I) + R = base_ring(L) + #I_min = L.(small_generating_set(saturated_ideal(I))) + I_min = L.(small_generating_set(ideal(R, numerator.(gens(I))))) + filter(!iszero, I_min) end dim(R::MPolyLocRing{<:Field, <:FieldElem, <:MPolyRing, <:MPolyRingElem, <:MPolyComplementOfPrimeIdeal}) = nvars(base_ring(R)) - dim(prime_ideal(inverted_set(R))) diff --git a/src/Rings/mpolyquo-localizations.jl b/src/Rings/mpolyquo-localizations.jl index 99e9fc757ec0..b3894b363892 100644 --- a/src/Rings/mpolyquo-localizations.jl +++ b/src/Rings/mpolyquo-localizations.jl @@ -144,11 +144,8 @@ inverted_set(L::MPolyQuoLocRing) = L.S Given ``L = (𝕜[x₁,…,xₙ]/I)[S⁻¹]``, return ``IS⁻¹``. """ -function modulus(L::MPolyQuoLocRing) - if !has_attribute(L, :modulus) - set_attribute!(L, :modulus, localized_ring(L)(L.I)) - end - return get_attribute(L, :modulus)::ideal_type(localized_ring_type(L)) +@attr ideal_type(localized_ring_type(L)) function modulus(L::MPolyQuoLocRing) + return localized_ring(L)(L.I) end ### for compatibility -- also provide modulus in the trivial case @@ -871,7 +868,7 @@ function iszero(a::MPolyQuoLocRingElem{<:Any, <:Any, <:Any, <:Any, <:MPolyComple # In case that the original quotient ring A is an integral domain # the localization map is injective and a is zero iff its numerator is zero. I = modulus(underlying_quotient(parent(a))) - if has_attribute(I, :is_prime) && get_attribute(I, :is_prime) === true + if get_attribute(I, :is_prime, false) return lifted_numerator(a) in I end return lift(a) in modulus(parent(a)) @@ -2102,8 +2099,8 @@ end ### Some auxiliary functions @attr T function radical(I::T) where {T<:MPolyQuoLocalizedIdeal} - has_attribute(I, :is_prime) && get_attribute(I, :is_prime) && return I - has_attribute(I, :is_radical) && get_attribute(I, :is_radical) && return I + get_attribute(I, :is_prime, false) && return I + get_attribute(I, :is_radical, false) && return I R = base_ring(I) R_simp, iso, iso_inv = simplify(R) # This usually does not cost much I_simp = ideal(R_simp, restricted_map(iso).(lifted_numerator.(gens(I)))) @@ -2524,35 +2521,31 @@ If `I` is the zero ideal an empty list is returned. If the localization is at a point, a minimal set of generators is returned. """ -function small_generating_set( +@attr Vector{elem_type(base_ring(I))} function small_generating_set( I::MPolyQuoLocalizedIdeal{<:MPolyQuoLocRing{<:Field, <:FieldElem, <:MPolyRing, <:MPolyRingElem, <:MPolyComplementOfKPointIdeal}, <:Any,<:Any}; algorithm::Symbol=:simple ) - get_attribute!(I, :small_generating_set) do - Q = base_ring(I) - L = localized_ring(Q) - J = pre_image_ideal(I) - unique!(filter(!iszero, Q.(small_generating_set(J; algorithm)))) - end::Vector{elem_type(base_ring(I))} + Q = base_ring(I) + L = localized_ring(Q) + J = pre_image_ideal(I) + return unique!(filter(!iszero, Q.(small_generating_set(J; algorithm)))) end -function small_generating_set( +@attr Vector{elem_type(base_ring(I))} function small_generating_set( I::MPolyQuoLocalizedIdeal{<:MPolyQuoLocRing{<:Field, <:FieldElem, <:MPolyRing, <:MPolyRingElem, <:MPolyPowersOfElement} }; algorithm::Symbol=:simple ) - get_attribute!(I, :small_generating_set) do - Q = base_ring(I) - L = localized_ring(Q) + Q = base_ring(I) + L = localized_ring(Q) - J = pre_image_ideal(I) - unique!(filter(!iszero, Q.(small_generating_set(J; algorithm)))) - end::Vector{elem_type(base_ring(I))} + J = pre_image_ideal(I) + return unique!(filter(!iszero, Q.(small_generating_set(J; algorithm)))) end @attr Int function dim(R::MPolyLocRing) From b346152f3f30991d5324182302dc339fd331ed5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Wed, 22 Jan 2025 14:55:31 +0100 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Max Horn --- src/AlgebraicGeometry/Surfaces/EllipticSurface/Morphisms.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AlgebraicGeometry/Surfaces/EllipticSurface/Morphisms.jl b/src/AlgebraicGeometry/Surfaces/EllipticSurface/Morphisms.jl index a085bacb96e1..5e2fdc0e64b3 100644 --- a/src/AlgebraicGeometry/Surfaces/EllipticSurface/Morphisms.jl +++ b/src/AlgebraicGeometry/Surfaces/EllipticSurface/Morphisms.jl @@ -94,10 +94,10 @@ end end -@attr IdDict function raw_reduction_of_algebraic_lattice(X::EllipticSurface) +@attr IdDict{AbsWeilDivisor, AbsWeilDivisor} function raw_reduction_of_algebraic_lattice(X::EllipticSurface) X_red_raw, bc = raw_good_reduction(X) basis_ambient, _, _= algebraic_lattice(X) - return red_dict = IdDict{AbsWeilDivisor, AbsWeilDivisor}(D=>_reduce_as_prime_divisor(bc, D) for D in basis_ambient) + return IdDict{AbsWeilDivisor, AbsWeilDivisor}(D=>_reduce_as_prime_divisor(bc, D) for D in basis_ambient) end @attr ZZMatrix function good_reduction_algebraic_lattice(X::EllipticSurface)