Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ToricVarieties: Improve existing blowup functionality #2228

Merged
merged 6 commits into from
Apr 14, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -60,7 +60,8 @@ weighted_projective_space(::Type{NormalToricVariety}, w::Vector{T}; set_attribut
### Further Constructions

```@docs
blowup_on_ith_minimal_torus_orbit(v::AbstractNormalToricVariety, n::Int, coordinate_name::String; set_attributes::Bool = true)
blow_up(v::AbstractNormalToricVariety, I::MPolyIdeal; coordinate_name::String = "e", set_attributes::Bool = true)
blow_up(v::AbstractNormalToricVariety, n::Int; coordinate_name::String = "e", set_attributes::Bool = true)
Base.:*(v::AbstractNormalToricVariety, w::AbstractNormalToricVariety; set_attributes::Bool = true)
normal_toric_varieties_from_star_triangulations(P::Polyhedron; set_attributes::Bool = true)
normal_toric_varieties_from_glsm(charges::ZZMatrix; set_attributes::Bool = true)
2 changes: 1 addition & 1 deletion docs/src/PolyhedralGeometry/fans.md
Original file line number Diff line number Diff line change
@@ -64,6 +64,6 @@ nrays(PF::PolyhedralFan)
rays(PF::PolyhedralFan{T}) where T<:scalar_types
rays_modulo_lineality(PF::PolyhedralFan{T}) where T<:scalar_types
primitive_collections(PF::PolyhedralFan)
starsubdivision(PF::PolyhedralFan{T}, n::Int) where T<:scalar_types
star_subdivision(PF::PolyhedralFan{T}, n::Int) where T<:scalar_types
*(PF1::PolyhedralFan, PF2::PolyhedralFan)
```
Original file line number Diff line number Diff line change
@@ -536,55 +536,120 @@ end


############################
# 4: Advanced constructions
# 4: Blowups
############################

@doc raw"""
blowup_on_ith_minimal_torus_orbit(v::AbstractNormalToricVariety, n::Int, coordinate_name::String; set_attributes::Bool = true)
blow_up(v::AbstractNormalToricVariety, I::MPolyIdeal; coordinate_name::String = "e", set_attributes::Bool = true)

Return the blowup of the normal toric variety `v` on its i-th minimal torus orbit.
Blowup the toric variety by subdividing the cone in the list
of *all* cones of the fan of `v` which corresponds to the
provided ideal `I`. Note that this cone need not be maximal.

By default, we pick "e" as the name of the homogeneous coordinate for
the exceptional divisor. As third optional argument on can supply
a custom variable name.

# Examples
```jldoctest
julia> P2 = projective_space(NormalToricVariety, 2)
Normal, non-affine, smooth, projective, gorenstein, fano, 2-dimensional toric variety without torusfactor
julia> P3 = projective_space(NormalToricVariety, 3)
Normal, non-affine, smooth, projective, gorenstein, fano, 3-dimensional toric variety without torusfactor

julia> (x1,x2,x3,x4) = gens(cox_ring(P3))
4-element Vector{MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}}:
x1
x2
x3
x4

julia> I = ideal([x2,x3])
ideal(x2, x3)

julia> bP2 = blowup_on_ith_minimal_torus_orbit(P2, 1, "e")
julia> bP3 = blow_up(P3, I)
Normal toric variety

julia> cox_ring(bP2)
Multivariate Polynomial Ring in x2, x3, x1, e over Rational Field graded by
x2 -> [1 0]
julia> cox_ring(bP3)
Multivariate Polynomial Ring in x1, x2, e, x3, x4 over Rational Field graded by
x1 -> [1 0]
x2 -> [0 1]
e -> [1 -1]
x3 -> [0 1]
x4 -> [1 0]
```
"""
function blow_up(v::AbstractNormalToricVariety, I::MPolyIdeal; coordinate_name::String = "e", set_attributes::Bool = true)
@req parent(gens(I)[1]) == cox_ring(v) "The ideal must be contained in the cox ring of the toric variety"
indices = [findfirst(y -> y == x, gens(cox_ring(v))) for x in gens(I)]
@req length(indices) == ngens(I) "All generators must be indeterminates of the cox ring of the toric variety"
cone_list = cones(v)
cone_indices = [filter(l -> cone_list[k,l], 1:ncols(cone_list)) for k in 1:n_cones(v)]
cone_index = findfirst(x -> x == indices, cone_indices)
@req cone_index !== nothing "There is no corresponding cone that could be subdivided"
return blow_up(v, cone_index; coordinate_name = coordinate_name, set_attributes = set_attributes)
end


@doc raw"""
blow_up(v::AbstractNormalToricVariety, n::Int; coordinate_name::String = "e", set_attributes::Bool = true)

Blowup the toric variety by subdividing the n-th cone in the list
of *all* cones of the fan of `v`. This cone need not be maximal.

By default, we pick "e" as the name of the homogeneous coordinate for
the exceptional divisor. As third optional argument on can supply
a custom variable name.

# Examples
```jldoctest
julia> P3 = projective_space(NormalToricVariety, 3)
Normal, non-affine, smooth, projective, gorenstein, fano, 3-dimensional toric variety without torusfactor

julia> cones(P3)
14×4 IncidenceMatrix
[1, 2, 3]
[2, 3, 4]
[1, 3, 4]
[1, 2, 4]
[2, 3]
[1, 3]
[1, 2]
[3, 4]
[2, 4]
[1, 4]
[2]
[3]
[1]
[4]

julia> bP3 = blow_up(P3, 5)
Normal toric variety

julia> cox_ring(bP3)
Multivariate Polynomial Ring in x1, x2, e, x3, x4 over Rational Field graded by
x1 -> [1 0]
e -> [-1 1]
x2 -> [0 1]
e -> [1 -1]
x3 -> [0 1]
x4 -> [1 0]
```
"""
function blowup_on_ith_minimal_torus_orbit(v::AbstractNormalToricVariety, n::Int, coordinate_name::String; set_attributes::Bool = true)
# compute the blow-up variety
new_fan = starsubdivision(fan(v), n)
function blow_up(v::AbstractNormalToricVariety, n::Int; coordinate_name::String = "e", set_attributes::Bool = true)
new_fan = star_subdivision(fan(v), n)
new_variety = normal_toric_variety(new_fan; set_attributes = set_attributes)

# extract the old and new rays
# the new cones are in general given by first (in general) permuting the old rays and then adding a new ray (not necessarily at the last position)
old_rays = rays(fan(v))
new_rays = rays(new_fan)

# check for name clash with variable name chosen for blowup
old_vars = [string(x) for x in gens(cox_ring(v))]
isnothing(findfirst(x->occursin(coordinate_name, x), old_vars)) ||
throw(ArgumentError("The provided name for the blowup coordinate is already taken as homogeneous coordinate of the provided toric variety"))

# set up Cox ring of new variety
new_vars = [if new_rays[i] in old_rays old_vars[findfirst(x->x==new_rays[i], old_rays)] else coordinate_name end for i in 1:length(new_rays)]
@req findfirst(x->occursin(coordinate_name, x), old_vars) === nothing "The name for the blowup coordinate is already taken"
new_vars = [if new_rays[i] in rays(fan(v)) old_vars[findfirst(x->x==new_rays[i], rays(fan(v)))] else coordinate_name end for i in 1:length(new_rays)]
set_attribute!(new_variety, :coordinate_names, new_vars)
weights = [map_from_torusinvariant_weil_divisor_group_to_class_group(new_variety)(x) for x in gens(torusinvariant_weil_divisor_group(new_variety))]
set_attribute!(new_variety, :cox_ring_weights, weights)

return new_variety
end



############################
# 5: Cartesian product
############################

@doc raw"""
Base.:*(v::AbstractNormalToricVariety, w::AbstractNormalToricVariety; set_attributes::Bool = true)

@@ -644,9 +709,10 @@ function Base.:*(v::AbstractNormalToricVariety, w::AbstractNormalToricVariety; s
end


############################
# 5: Toric varieties from triangulations
############################

########################################
# 6: Toric varieties from triangulations
########################################

@doc raw"""
normal_toric_varieties_from_star_triangulations(P::Polyhedron; set_attributes::Bool = true)
@@ -696,9 +762,10 @@ function normal_toric_varieties_from_star_triangulations(P::Polyhedron; set_attr
end


############################
# 6: Toric varieties from GLSMs
############################

###############################
# 7: Toric varieties from GLSMs
###############################

@doc raw"""
normal_toric_varieties_from_glsm(charges::ZZMatrix; set_attributes::Bool = true)
@@ -766,8 +833,9 @@ end
normal_toric_varieties_from_glsm(charges::Vector{Vector{T}}; set_attributes::Bool = true) where {T <: IntegerUnion} = normal_toric_varieties_from_glsm(matrix(ZZ, charges); set_attributes = set_attributes)



############################
### 7: Display
### 8: Display
############################
function Base.show(io::IO, v::AbstractNormalToricVariety)
# initiate properties string
2 changes: 2 additions & 0 deletions src/Deprecations.jl
Original file line number Diff line number Diff line change
@@ -231,3 +231,5 @@ end
# Deprecated after 0.12.0
@deprecate contains(P::Polyhedron, v::AbstractVector) Base.in(v, P)
@deprecate contains(C::Cone, v::AbstractVector) Base.in(v, C)
@deprecate blowup_on_ith_minimal_torus_orbit(v::AbstractNormalToricVariety, n::Int, coordinate_name::String; set_attributes::Bool = true) blow_up(v, n; coordinate_name = coordinate_name, set_attributes = set_attributes)
@deprecate starsubdivision(PF::_FanLikeType{T}, n::Int) where T<:scalar_types star_subdivision(PF, n)
3 changes: 1 addition & 2 deletions src/Exports.jl
Original file line number Diff line number Diff line change
@@ -271,7 +271,6 @@ export binomial_primary_decomposition
export bipyramid
export birkhoff_polytope
export blocks
export blowup_on_ith_minimal_torus_orbit
export bond_matroid
export borcherds_method
export boundary_lattice_points
@@ -1228,8 +1227,8 @@ export standard_spec
export stanley_reisner_ideal
export stanley_reisner_ring
export star_subcomplex
export star_subdivision
export star_triangulations
export starsubdivision
export strongly_connected_components
export structure_sheaf
export structure_tropical_jacobian
104 changes: 63 additions & 41 deletions src/PolyhedralGeometry/PolyhedralFan/properties.jl
Original file line number Diff line number Diff line change
@@ -514,22 +514,24 @@ end
###############################################################################

@doc raw"""
starsubdivision(PF::PolyhedralFan, n::Int)
star_subdivision(PF::PolyhedralFan, n::Int)

Return the star subdivision of a polyhedral fan at its n-th maximal torus orbit.
Return the star subdivision of a polyhedral fan at its n-th torus orbit.
Note that this torus orbit need not be maximal. We follow definition 3.3.17
of [CLS11](@cite).

# Examples
```jldoctest
julia> star = starsubdivision(normal_fan(simplex(3)), 1)
julia> star = star_subdivision(normal_fan(simplex(3)), 1)
Polyhedral fan in ambient dimension 3

julia> rays(star)
5-element SubObjectIterator{RayVector{QQFieldElem}}:
[0, 1, 0]
[0, 0, 1]
[-1, -1, -1]
[1, 0, 0]
[0, 0, 1]
[1, 1, 1]
[0, 1, 0]
[-1, -1, -1]

julia> ray_indices(maximal_cones(star))
6×5 IncidenceMatrix
@@ -541,45 +543,65 @@ julia> ray_indices(maximal_cones(star))
[1, 4, 5]
```
"""
function starsubdivision(PF::_FanLikeType{T}, n::Int) where T<:scalar_types
# extract defining information on the fan
maxcones = IncidenceMatrix(pm_object(PF).MAXIMAL_CONES)
R = Polymake.common.primitive(pm_object(PF).RAYS)

# check if n-th maximal cone does exist
if length(maxcones) < n
throw(ArgumentError("Cannot subdivide maximal cone $n as it does not exist!"))
end
nthmaxcone = Polymake.row(maxcones, n)

# construct this cone and check if it is smooth
cone = Polymake.fan.cone(pm_object(PF), n-1)
if !cone.SMOOTH_CONE
throw(ArgumentError("Cannot subdivide maximal cone $n as it is not smooth!"))
end

# compute new rays to be added from star subdivision
newindex = size(R,1) + 1
newray = sum([R[i,:] for i in nthmaxcone])

# add this ray to form list of the new rays
newrays = [R; transpose(newray)]

# identify all maximal cones in the new fan
d = Polymake.polytope.dim(cone)
newmaxcones = [Vector{Int64}(Polymake.row(maxcones, i)) for i in 1:(Polymake.nrows(maxcones)) if i!= n]
for subset in subsets(Vector{Int64}(nthmaxcone), d-1)
tmp = Vector{Int64}(subset)
append!(tmp, newindex)
function star_subdivision(PF::_FanLikeType{T}, n::Int) where T<:scalar_types

# check if n-th cone exist
@req n <= n_cones(PF) "Cannot subdivide cone $n as it does not exist"

# check if n-th cone can be subdivided
cone_list = cones(PF)
nthcone = Polymake.row(cone_list, n)
@req length(nthcone) > 1 "Cannot subdivide cone $n as it is generated by a single ray"

# check if nth cone is smooth
@req _cone_is_smooth(PF, nthcone) "Cannot subdivide maximal cone $n as it is not smooth"

# compute new ray
R = Polymake.common.primitive(Oscar.pm_object(PF).RAYS)
newindex = size(R,1) + 1
newray = sum([R[i,:] for i in nthcone])

# compute new rays
newrays = [R; transpose(newray)]

# compute the new maximal cones
max_cone_indices = ray_indices(maximal_cones(PF))
cone_indices = Polymake.row(cone_list, n)
newmaxcones = (Vector{Int})[]
for i in 1:n_maximal_cones(PF)
indices_ith_max_cone = Polymake.row(max_cone_indices, i)
if issubset(cone_indices, indices_ith_max_cone)
@req _cone_is_smooth(PF, indices_ith_max_cone) "All cones containing sigma need to be smooth"
for subset in subsets(Vector{Int64}(cone_indices), length(cone_indices)-1)
tmp = Base.setdiff(indices_ith_max_cone, cone_indices)
tmp = Base.union(subset, tmp)
push!(tmp, newindex)
push!(newmaxcones, tmp)
end
else
push!(newmaxcones, Vector{Int}(indices_ith_max_cone))
end
newmaxcones = IncidenceMatrix(newmaxcones)

# return the new fan
return PolyhedralFan{T}(newrays, newmaxcones)

end
newmaxcones = IncidenceMatrix(newmaxcones)

# return the new fan
return PolyhedralFan{T}(newrays, newmaxcones)

end


function _cone_is_smooth(PF::_FanLikeType, c::AbstractSet{<:Integer})
R = matrix(ZZ, rays(PF))
return _is_unimodular(R[Vector{Int}(c),:])
end

function _is_unimodular(M::ZZMatrix)
nrows(M) <= ncols(M) || return false
n = nrows(M)
return abs(det(snf(M)[:,1:n])) == 1
end


###############################################################################
## Cartesian/Direct product
###############################################################################
4 changes: 2 additions & 2 deletions test/AlgebraicGeometry/ToricVarieties/toric_blowups.jl
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ using Test
@testset "Blowup of toric varieties (set_attributes = $set_attributes)" for set_attributes in [true, false]

P2 = projective_space(NormalToricVariety, 2; set_attributes)
BP2 = blowup_on_ith_minimal_torus_orbit(P2, 1, "e"; set_attributes)
BP2 = blow_up(P2, 1; coordinate_name = "e", set_attributes = set_attributes)

@testset "Basic properties of BP2" begin
@test is_normal(BP2) == true
@@ -27,4 +27,4 @@ using Test
@test euler_characteristic(BP2) == 4
@test rank(picard_group(BP2)) == 2
end
end
end