diff --git a/docs/src/AlgebraicGeometry/ToricVarieties/BlowupMorphisms.md b/docs/src/AlgebraicGeometry/ToricVarieties/BlowupMorphisms.md index 90945edf9cdd..f38e0ce92741 100644 --- a/docs/src/AlgebraicGeometry/ToricVarieties/BlowupMorphisms.md +++ b/docs/src/AlgebraicGeometry/ToricVarieties/BlowupMorphisms.md @@ -49,6 +49,10 @@ toric: ```@docs blow_up(v::NormalToricVariety, exceptional_ray::AbstractVector{<:IntegerUnion}; coordinate_name::String = "e") ``` +The ray can alternatively be given using minimal supercone coordinates: +```@docs +blow_up_along_minimal_supercone_coordinates(v::NormalToricVarietyType, minimal_supercone_coords::AbstractVector{<:RationalUnion}; coordinate_name::Union{String, Nothing} = nothing) +``` Most generally, we encode the closed subscheme along which we blow up by a homogeneous ideal in the Cox ring. Such blowups are often non-toric, i.e. the return value of the following method could well be non-toric. diff --git a/docs/src/PolyhedralGeometry/fans.md b/docs/src/PolyhedralGeometry/fans.md index fdcef23d9a0d..be8c47048125 100644 --- a/docs/src/PolyhedralGeometry/fans.md +++ b/docs/src/PolyhedralGeometry/fans.md @@ -51,6 +51,8 @@ cones(PF::PolyhedralFan, cone_dim::Int) cones(PF::PolyhedralFan) minimal_supercone_coordinates(PF::PolyhedralFan, v::AbstractVector{<:RationalUnion}) minimal_supercone_indices(PF::PolyhedralFan, v::AbstractVector{<:RationalUnion}) +is_minimal_supercone_coordinate_vector(PF::PolyhedralFan, v::AbstractVector{<:RationalUnion}) +standard_coordinates(PF::PolyhedralFan, coords::AbstractVector{<:RationalUnion}) n_maximal_cones(PF::PolyhedralFan) n_cones(PF::PolyhedralFan) n_rays(PF::PolyhedralFan) diff --git a/docs/src/PolyhedralGeometry/intro.md b/docs/src/PolyhedralGeometry/intro.md index fe2c713027af..3b26aaf372e4 100644 --- a/docs/src/PolyhedralGeometry/intro.md +++ b/docs/src/PolyhedralGeometry/intro.md @@ -84,7 +84,7 @@ The primitive generator, also called minimal generator, of a ray can be accessed as follows: ```@docs -primitive_generator(r::RayVector) +primitive_generator(r::AbstractVector{T}) where T<:RationalUnion ``` `AbstractCollection[PointVector]` can be given as: diff --git a/experimental/Schemes/src/Schemes.jl b/experimental/Schemes/src/Schemes.jl index 6e66f3f7f1ec..8d4fd9cb0bad 100644 --- a/experimental/Schemes/src/Schemes.jl +++ b/experimental/Schemes/src/Schemes.jl @@ -35,6 +35,7 @@ export SpaceGerm export ambient_germ export basis_representation +export blow_up_along_minimal_supercone_coordinates export complete_intersection_germ export cox_ring_module_homomorphism export defining_ring_element @@ -53,6 +54,7 @@ export minimal_supercone_coordinates_of_exceptional_ray export point export rational_point_coordinates export standard_covering +export standard_coordinates export strict_transform export strict_transform_with_index export total_transform diff --git a/experimental/Schemes/src/ToricBlowups/constructors.jl b/experimental/Schemes/src/ToricBlowups/constructors.jl index f954fd59b256..2261499d07c0 100644 --- a/experimental/Schemes/src/ToricBlowups/constructors.jl +++ b/experimental/Schemes/src/ToricBlowups/constructors.jl @@ -177,6 +177,31 @@ function blow_up(v::NormalToricVarietyType, exceptional_ray::AbstractVector{<:In return ToricBlowupMorphism(v, blown_up_variety, coordinate_name, exceptional_ray, exceptional_ray, center_unnormalized) end +@doc raw""" + blow_up_along_minimal_supercone_coordinates(v::NormalToricVarietyType, minimal_supercone_coords::AbstractVector{<:IntegerUnion}; coordinate_name::Union{String, Nothing} = nothing) + +This method first constructs the ray `r` by calling `standard_coordinates`, then blows up `v` along `r` using `blow_up`. + +# Examples + +```jldoctest +julia> P2 = projective_space(NormalToricVariety, 2) +Normal toric variety + +julia> f = blow_up_along_minimal_supercone_coordinates(P2, [2, 3, 0]) +Toric blowup morphism +``` +""" +function blow_up_along_minimal_supercone_coordinates(v::NormalToricVarietyType, minimal_supercone_coords::AbstractVector{<:RationalUnion}; coordinate_name::Union{String, Nothing} = nothing) + coords = Vector{QQFieldElem}(minimal_supercone_coords) + ray_QQ = Vector{QQFieldElem}(standard_coordinates(polyhedral_fan(v), coords)) + ray = primitive_generator(ray_QQ) + @assert ray == ray_QQ "The input vector must correspond to a primitive generator of a ray" + phi = blow_up(v, ray; coordinate_name=coordinate_name) + set_attribute!(phi, :minimal_supercone_coordinates_of_exceptional_ray, coords) + return phi +end + @doc raw""" blow_up(v::NormalToricVariety, n::Int; coordinate_name::String = "e") diff --git a/experimental/Schemes/test/runtests.jl b/experimental/Schemes/test/runtests.jl index 9490393f2175..8a66e80292d3 100644 --- a/experimental/Schemes/test/runtests.jl +++ b/experimental/Schemes/test/runtests.jl @@ -15,6 +15,15 @@ @test exceptional_prime_divisor(bl1) == toric_divisor(domain(bl1), [1,0,0,0]) end +@testset "Blow ups along minimal supercone coordinates" begin + P2 = projective_space(NormalToricVariety, 2) + f_1 = blow_up_along_minimal_supercone_coordinates(P2, [2, 3, 0]) + f_2 = blow_up(P2, [2, 3]) + pf_1 = polyhedral_fan(domain(f_1)) + pf_2 = polyhedral_fan(domain(f_2)) + @test Set(rays(pf_1)) == Set(rays(pf_2)) +end + @testset "Total and strict transforms in Cox rings" begin # Affine space, (2, 3)-blowup X = affine_space(NormalToricVariety, 2) diff --git a/src/PolyhedralGeometry/PolyhedralFan/properties.jl b/src/PolyhedralGeometry/PolyhedralFan/properties.jl index 230c675635f7..a4051a5f7cc8 100644 --- a/src/PolyhedralGeometry/PolyhedralFan/properties.jl +++ b/src/PolyhedralGeometry/PolyhedralFan/properties.jl @@ -282,7 +282,7 @@ function cones(PF::_FanLikeType) end @doc raw""" - primitive_generator(r::RayVector) -> Vector{ZZRingElem} + primitive_generator(r::AbstractVector{T}) where T<:RationalUnion -> Vector{ZZRingElem} Returns the primitive generator, also called minimal generator, of a ray. @@ -302,10 +302,11 @@ julia> primitive_generator(r) -1 ``` """ -function primitive_generator(r::RayVector) +function primitive_generator(r::AbstractVector{T}) where {T<:RationalUnion} result = numerator.(lcm([denominator(i) for i in r]) * r) - result = 1 / gcd(result) * result - convert(Vector{ZZRingElem}, result) + g = gcd(result) + result = map(x -> div(x, g), result) + return Vector{ZZRingElem}(result) end @doc raw""" @@ -404,7 +405,7 @@ function minimal_supercone_coordinates( PF::PolyhedralFan, v::AbstractVector{<:RationalUnion} ) # This function probably only makes sense for fans with no lineality - @req is_pointed(PF) "PolyhedralFan must be pointed." + @req is_pointed(PF) "The polyhedral fan must be pointed." inds = sort(collect(minimal_supercone_indices(PF, v))) M_ZZ = matrix(ZZ, rays(PF))[inds, :] @@ -440,6 +441,72 @@ function minimal_supercone_coordinates( return result end +@doc raw""" + is_minimal_supercone_coordinate_vector(PF::PolyhedralFan, v::AbstractVector{<:RationalUnion}) + -> Bool + +Given a pointed polyhedral fan `PF` and a vector `v` of length equal to +the number of rays of `PF`, this function checks that both of the +following are true: + * all of the entries of `v` are nonnegative, + * `v` is in some maximal cone of `PF`. + +# Examples +```jldoctest +julia> PF = normal_fan(Oscar.simplex(3)) +Polyhedral fan in ambient dimension 3 + +julia> is_minimal_supercone_coordinate_vector(PF, [1, 1, 1, 0]) +true + +julia> is_minimal_supercone_coordinate_vector(PF, [1, 1, 1, 1]) +false +``` +""" +function is_minimal_supercone_coordinate_vector( + PF::PolyhedralFan, v::AbstractVector{<:RationalUnion} +) + @req is_pointed(PF) "The polyhedral fan must be pointed." + @assert length(v) == n_rays(PF) "Length of v must match the number of rays." + isnothing(findfirst(x -> x < 0, v)) || return false + positive_indices = [i for i in 1:length(v) if v[i] > 0] + maximal_cones_incidence_matrix = maximal_cones(IncidenceMatrix, PF) + maximal_cones_indices = map( + i -> row(maximal_cones_incidence_matrix, i), + 1:n_rows(maximal_cones_incidence_matrix), + ) + for i in 1:n_rows(maximal_cones_incidence_matrix) + issubset(positive_indices, maximal_cones_indices[i]) && return true + end + return false +end + +@doc raw""" + standard_coordinates(PF::PolyhedralFan, v::AbstractVector{<:RationalUnion}) + -> Vector{QQFieldElem} + +If `is_minimal_supercone_coordinate_vector(PF, v)` is true, then return the dot product of `v` and the vector of primitive generators of the rays of `PF`. + +# Examples +```jldoctest +julia> PF = normal_fan(Oscar.simplex(3)) +Polyhedral fan in ambient dimension 3 + +julia> standard_coordinates(PF, [1, 1, 0, 1]) +3-element Vector{QQFieldElem}: + 0 + 0 + -1 +``` +""" +function standard_coordinates(PF::PolyhedralFan, coords::AbstractVector{<:RationalUnion}) + @assert is_minimal_supercone_coordinate_vector( + PF, coords + ) "Input vector must be a minimal supercone coordinate vector" + primitive_ray_generators = Vector{Vector{QQFieldElem}}(map(primitive_generator, rays(PF))) + return Vector{QQFieldElem}(sum(coords .* primitive_ray_generators)) +end + ############################################################################### ############################################################################### ### Access properties diff --git a/src/exports.jl b/src/exports.jl index 3858b2071b00..0dd3e2c74f0f 100644 --- a/src/exports.jl +++ b/src/exports.jl @@ -1114,7 +1114,7 @@ export minimal_faces export minimal_generating_set export minimal_generator export minimal_size_generating_set, has_minimal_size_generating_set, set_minimal_size_generating_set -export minimal_supercone_coordinates, minimal_supercone_indices +export minimal_supercone_coordinates, minimal_supercone_indices, is_minimal_supercone_coordinate_vector export minimal_nonfaces export minimal_normal_subgroups, has_minimal_normal_subgroups, set_minimal_normal_subgroups export minimal_primes @@ -1556,6 +1556,7 @@ export stable_set_polytope export standard_basis export standard_basis_highest_corner export standard_basis_with_transformation_matrix +export standard_coordinates export standard_tableaux export stanley_reisner_ideal export stanley_reisner_ring diff --git a/test/PolyhedralGeometry/polyhedral_fan.jl b/test/PolyhedralGeometry/polyhedral_fan.jl index 777e7e9d9888..7bb884043f4c 100644 --- a/test/PolyhedralGeometry/polyhedral_fan.jl +++ b/test/PolyhedralGeometry/polyhedral_fan.jl @@ -149,6 +149,14 @@ end @test minimal_supercone_coordinates(PF, [-1, -1, 1]) == [0, 0, 2, 1] @test issetequal(minimal_supercone_indices(PF, [-2//3, QQFieldElem(-4//3), 1]), [1, 3, 4]) @test minimal_supercone_coordinates(PF, [-2//3, -4//3, 1]) == [2//3, 0, 7//3, 4//3] + + @test is_minimal_supercone_coordinate_vector(PF, [1, 1, 1, 0]) + @test !is_minimal_supercone_coordinate_vector(PF, [1, 1, 1, 1]) + @test !is_minimal_supercone_coordinate_vector(PF, [1, 1, -1, 0]) + + @test standard_coordinates(PF, [1, 2, 3, 0]) == [1, 2, 3] + @test standard_coordinates(PF, [1, 1, 0, 1]) == [0, 0, -1] + @test standard_coordinates(PF, [1, 0, 0, 1]) == [0, -1, -1] # Construct a nonsimplicial fan PF = face_fan(cube(3))