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

Decomposition info #2504

Merged
52 changes: 49 additions & 3 deletions experimental/Schemes/CoveredProjectiveSchemes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,13 @@ function blow_up_chart(W::AbsSpec{<:Field, <:MPolyRing}, I::MPolyIdeal;
set_attribute!(Y, :exceptional_divisor, E)
set_attribute!(IPY, :exceptional_divisor, E)

# Prepare the decomposition data
decomp_dict = IdDict{AbsSpec, Vector{RingElem}}()
for k in 1:ngens(I)
U = affine_charts(Y)[i]
decomp_dict[U] = gens(OO(U))[1:k-1] # Relies on the projective variables coming first!
end

# Cache the isomorphism on the complement of the center
p_res_dict = IdDict{AbsSpec, AbsSpecMor}()
for i in 1:ngens(I)
Expand All @@ -304,6 +311,7 @@ function blow_up_chart(W::AbsSpec{<:Field, <:MPolyRing}, I::MPolyIdeal;
)
end
set_attribute!(p, :isos_on_complement_of_center, p_res_dict)
set_decomposition_info!(default_covering(Y), decomp_dict)
return IPY
else
# construct the blowup by elimination.
Expand Down Expand Up @@ -345,6 +353,15 @@ function blow_up_chart(W::AbsSpec{<:Field, <:MPolyRing}, I::MPolyIdeal;
SpecMor(UW, VW, vcat([g[j]*inv(g[i]) for j in 1:ngens(I) if j != i], gens(OO(UW))), check=false)
)
end

# Prepare the decomposition data
decomp_dict = IdDict{AbsSpec, Vector{RingElem}}()
for k in 1:ngens(I)
U = affine_charts(Y)[k]
decomp_dict[U] = gens(OO(U))[1:k-1] # Relies on the projective variables coming first!
end

set_decomposition_info!(default_covering(Y), decomp_dict)
set_attribute!(p, :isos_on_complement_of_center, p_res_dict)
return IPY
end
Expand Down Expand Up @@ -392,6 +409,15 @@ function blow_up_chart(W::AbsSpec{<:Field, <:RingType}, I::Ideal;
)
end
set_attribute!(p, :isos_on_complement_of_center, p_res_dict)

# Prepare the decomposition data
decomp_dict = IdDict{AbsSpec, Vector{RingElem}}()
for k in 1:ngens(I)
U = affine_charts(Y)[k]
decomp_dict[U] = gens(OO(U))[1:k-1] # Relies on the projective variables coming first!
end
set_decomposition_info!(default_covering(Y), decomp_dict)

return Bl_W
end

Expand Down Expand Up @@ -820,7 +846,7 @@ end
end
end
result_covering = Covering(result_patches, result_glueings, check=false)

# Now we need to add glueings
for U in patches(C)
for V in patches(C)
Expand All @@ -844,14 +870,34 @@ end
p = covered_projection_to_base(PP)
cov_mor = covering_morphism(p)
cov_mor_dict = morphisms(cov_mor)
for V in keys(cov_mor_dict)
projection_dict[V] = cov_mor_dict[V]
for (V, phi) in cov_mor_dict
projection_dict[V] = phi
end
end

# Assemble the decomposition information if applicable
decomp_dict = IdDict{AbsSpec, Vector{RingElem}}()
if has_decomposition_info(C)
for V in patches(C)
cov_part = default_covering(parts[V])
if has_decomposition_info(cov_part)
for U in patches(cov_part)
pr = projection_dict[U]
decomp_dict[U] = vcat(decomposition_info(cov_part)[U],
elem_type(OO(U))[pullback(pr)(a) for a in decomposition_info(C)[V]]
)
end
end
end
end
if length(keys(decomp_dict)) == length(patches(result_covering))
set_decomposition_info!(result_covering, decomp_dict)
end

# TODO: Remove the internal checks in the constructors below
covering_map = CoveringMorphism(result_covering, C, projection_dict, check=false)
set_attribute!(P, :covering_projection_to_base, covering_map)

return result
end

Expand Down
14 changes: 14 additions & 0 deletions experimental/Schemes/CoveredScheme.jl
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,16 @@ affine_refinements(C::Covering) = C.affine_refinements
U = Vector{AbsSpec}()
# TODO: Check that all weights are equal to one. Otherwise the routine is not implemented.
s = symbols(S)
decomp_info = IdDict{AbsSpec, Vector{RingElem}}()
for i in 0:r
R, x = polynomial_ring(kk, [Symbol("("*String(s[k+1])*"//"*String(s[i+1])*")") for k in 0:r if k != i])
phi = hom(S, R, vcat(gens(R)[1:i], [one(R)], gens(R)[i+1:r]), check=false)
I = ideal(R, phi.(gens(defining_ideal(X))))
push!(U, Spec(quo(R, I)[1]))
decomp_info[last(U)] = gens(OO(last(U)))[1:i]
end
result = Covering(U)
set_decomposition_info!(result, decomp_info)
for i in 1:r
for j in i+1:r+1
x = gens(base_ring(OO(U[i])))
Expand Down Expand Up @@ -146,11 +149,14 @@ end
U = Vector{AbsSpec}()
# TODO: Check that all weights are equal to one. Otherwise the routine is not implemented.
s = symbols(S)
decomp_info = IdDict{AbsSpec, Vector{RingElem}}()
for i in 0:r
R, x = polynomial_ring(kk, [Symbol("("*String(s[k+1])*"//"*String(s[i+1])*")") for k in 0:r if k != i])
push!(U, Spec(R))
decomp_info[last(U)] = gens(OO(last(U)))[1:i]
end
result = Covering(U)
set_decomposition_info!(result, decomp_info)
for i in 1:r
for j in i+1:r+1
x = gens(OO(U[i]))
Expand Down Expand Up @@ -193,6 +199,7 @@ end
# ideal sheaf is trivial on some affine open part.
if r == 0
result = Covering(Y)
set_decomposition_info!(result, Y, elem_type(OO(Y))[])
pU[Y] = identity_map(Y)
covered_projection = CoveringMorphism(result, result, pU, check=false)
set_attribute!(X, :covering_projection_to_base, covered_projection)
Expand All @@ -202,6 +209,7 @@ end
# TODO: Check that all weights are equal to one. Otherwise the routine is not implemented.
s = symbols(S)
# for each homogeneous variable, set up the chart
decomp_info = IdDict{AbsSpec, Vector{RingElem}}()
for i in 0:r
R_fiber, x = polynomial_ring(kk, [Symbol("("*String(s[k+1])*"//"*String(s[i+1])*")") for k in 0:r if k != i])
F = Spec(R_fiber)
Expand All @@ -211,8 +219,10 @@ end
patch = subscheme(ambient_space, elem_type(OO(ambient_space))[evaluate(f, vcat(fiber_vars[1:i], [one(OO(ambient_space))], fiber_vars[i+1:end])) for f in mapped_polys])
push!(U, patch)
pU[patch] = restrict(pY, patch, Y, check=false)
decomp_info[last(U)] = gens(OO(last(U)))[1:i]
end
result = Covering(U)
set_decomposition_info!(result, decomp_info)
for i in 1:r
for j in i+1:r+1
x = gens(base_ring(OO(U[i])))
Expand Down Expand Up @@ -252,22 +262,26 @@ end
# ideal sheaf is trivial on some affine open part.
if r == 0
result = Covering(Y)
set_decomposition_info!(result, Y, elem_type(OO(Y))[])
pU[Y] = identity_map(Y)
covered_projection = CoveringMorphism(result, result, pU, check=false)
set_attribute!(X, :covering_projection_to_base, covered_projection)
return result
end

decomp_info = IdDict{AbsSpec, Vector{RingElem}}()
s = symbols(S)
# for each homogeneous variable, set up the chart
for i in 0:r
R_fiber, x = polynomial_ring(kk, [Symbol("("*String(s[k+1])*"//"*String(s[i+1])*")") for k in 0:r if k != i])
F = Spec(R_fiber)
ambient_space, pF, pY = product(F, Y)
push!(U, ambient_space)
decomp_info[last(U)] = gens(OO(last(U)))[1:i]
pU[ambient_space] = pY
end
result = Covering(U)
set_decomposition_info!(result, decomp_info)
for i in 1:r
for j in i+1:r+1
x = ambient_coordinates(U[i])
Expand Down
10 changes: 10 additions & 0 deletions experimental/Schemes/IdealSheaves.jl
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ function subscheme(I::IdealSheaf)
C = default_covering(X)
new_patches = [subscheme(U, I(U)) for U in basic_patches(C)]
new_glueings = IdDict{Tuple{AbsSpec, AbsSpec}, AbsGlueing}()
decomp_dict = IdDict{AbsSpec, Vector{RingElem}}()
for (U, V) in keys(glueings(C))
i = C[U]
j = C[V]
Expand All @@ -290,6 +291,15 @@ function subscheme(I::IdealSheaf)
new_glueings[(Vnew, Unew)] = LazyGlueing(Vnew, Unew, inverse, new_glueings[(Unew, Vnew)])
end
Cnew = Covering(new_patches, new_glueings, check=false)

# Inherit decomposition information if applicable
if has_decomposition_info(C)
for k in 1:length(new_patches)
U = new_patches[k]
V = basic_patches(C)[k]
set_decomposition_info!(Cnew, U, elem_type(OO(U))[OO(U)(a, check=false) for a in decomposition_info(C)[V]])
end
end
return CoveredScheme(Cnew)
end

Expand Down
55 changes: 35 additions & 20 deletions experimental/Schemes/WeilDivisor.jl
Original file line number Diff line number Diff line change
Expand Up @@ -210,34 +210,49 @@ function intersect(D::WeilDivisor, E::WeilDivisor)
return result
end

function colength(I::IdealSheaf)
function colength(I::IdealSheaf; covering::Covering=default_covering(scheme(I)))
X = scheme(I)
C = default_covering(X)
patches_todo = copy(affine_charts(X))
patches_todo = copy(patches(covering))
patches_done = AbsSpec[]
result = 0
while length(patches_todo) != 0
U = pop!(patches_todo)
J = I(U)
# To avoid overcounting, throw away all components that
# were already visible in other charts.
for V in patches_done
if !haskey(glueings(C), (U, V))
continue
if has_decomposition_info(covering)
HechtiDerLachs marked this conversation as resolved.
Show resolved Hide resolved
h = decomposition_info(covering)[U]
# The elements in h indicate where components must
# be located so that they can not be spotted in other charts.
# We iteratively single out these components by adding a sufficiently high
# power of the equation to the ideal.
Comment on lines +223 to +226
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...and this here how this can be brought to work.

The next step would be to automatically keep track of this information for blowups. Then integration of cycles should go through in little time once we allow weil divisor components to be non-prime.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need this information to down to subschemes.

for f in h
g = f
while !(g in ideal(OO(U), g*f) + J)
g = g * g
end
J = J + ideal(OO(U), g)
isone(J) && break
end
G = C[U, V]
(UV, VU) = glueing_domains(G)
UV isa PrincipalOpenSubset || error("method is only implemented for simple glueings")
f = complement_equation(UV)
# Find a sufficiently high power of f such that it throws
# away all components away from the horizon, but does not affect
# those on the horizon itself.
k = 0
while !(f^(k) in ideal(OO(U), f^(k+1)) + J)
k = k + 1
else
# To avoid overcounting, throw away all components that
# were already visible in other charts.
for V in patches_done
if !haskey(glueings(covering), (U, V))
continue
end
G = covering[U, V]
(UV, VU) = glueing_domains(G)
UV isa PrincipalOpenSubset || error("method is only implemented for simple glueings")
f = complement_equation(UV)
# Find a sufficiently high power of f such that it throws
# away all components away from the horizon, but does not affect
# those on the horizon itself.
g = f
while !(g in ideal(OO(U), g*f) + J)
g = g * g
end
J = J + ideal(OO(U), g)
isone(J) && break
end
J = J + ideal(OO(U), f^k)
isone(J) && break
end
if !isone(J)
JJ = leading_ideal(saturated_ideal(J))
Expand Down
10 changes: 10 additions & 0 deletions src/AlgebraicGeometry/Schemes/Covering/Morphisms/Methods.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ function simplify(C::Covering)
Cnew = Covering(new_patches, new_glueings, check=false)
i_cov_mor = CoveringMorphism(Cnew, C, iDict, check=false)
j_cov_mor = CoveringMorphism(C, Cnew, jDict, check=false)

# Carry over the decomposition information.
if has_decomposition_info(C)
for U in new_patches
V = codomain(i_cov_mor[U])
pb = pullback(i_cov_mor[U])
set_decomposition_info!(Cnew, U, elem_type(OO(U))[pb(a) for a in decomposition_info(C)[V]])
end
end

return Cnew, i_cov_mor, j_cov_mor
end

Expand Down
39 changes: 39 additions & 0 deletions src/AlgebraicGeometry/Schemes/Covering/Objects/Attributes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,42 @@ function glueing_graph(C::Covering)
return C.glueing_graph
end

@doc raw"""
decomposition_info(C::Covering)

Return an `IdDict` `D` with the `patches` ``Uᵢ`` of `C` as keys and values a list
of elements ``fᵢ₁,…,fᵢᵣ ∈ 𝒪(Uᵢ)``. These elements are chosen so that for every
affine patch `Uᵢ` of ``X`` in the covering `C` the closed subvarieties ``Zᵢ ⊂ Uᵢ``
defined by the ``fᵢⱼ`` give rise to a decomposition of ``X`` as a **disjoint** union
``X = \bigcup_{i} Z_i`` of locally closed subvarieties.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So $f_{i1}=0$?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't understand this.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is $Z_i$ exactly? I guess an example would help.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$Z_i \subset U_i$ is the subvariety defined by the elements $f_{i,1}, \dots, f_{i,r}$ returned by the call decomposition_info(X)[U_i].

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

O.k. please add this to the docstring with the next pr.

Copy link
Collaborator

@simonbrandhorst simonbrandhorst Jul 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But still how do you get

$X = \bigcup_{i} Z_i$?

Shouldn't $\bigcup_{i} Z_i\subseteq U_i \subset X$?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This must hold by construction of the decomposition_info. You do not get a decomposition with inclusion maps, etc. You get a list of ring elements for every patch and you may continue working with them while assuming that the decomposition described above is a disjoint union.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still don't get it. Because I do not get your definition of a decomposition_info.
Please give clean mathematical definition.


This information can be used for local computations in any chart ``Uᵢ`` of ``X``
as above to focus on phenomena occuring exclusively along ``Zᵢ`` and assuming
that other cases have been handled by computations in other charts. A key
application is counting points of zero-dimensional subschemes: To avoid overcounting,
we need to only consider points in ``Uᵢ`` which are located within ``Zᵢ`` and
then sum these up to all points in ``X``.

!!! note This attribute might not be defined! Use `has_decomposition_info(C)` to check whether this information is available for the given covering.
"""
function decomposition_info(C::Covering)
return C.decomp_info
end

function set_decomposition_info!(C::Covering, U::AbsSpec, f::Vector{<:RingElem})
if !isdefined(C, :decomp_info)
C.decomp_info = IdDict{AbsSpec, Vector{RingElem}}()
end
all(x->parent(x) === OO(U), f) || error("elements do not belong to the correct ring")
decomposition_info(C)[U] = f
end

function set_decomposition_info!(C::Covering, D::IdDict{<:AbsSpec, <:Vector{<:RingElem}})
C.decomp_info = D
end

function has_decomposition_info(C::Covering)
isdefined(C, :decomp_info) || return false
all(x->haskey(C.decomp_info, x), patches(C)) || return false
return true
end
10 changes: 10 additions & 0 deletions src/AlgebraicGeometry/Schemes/Covering/Objects/Methods.jl
Original file line number Diff line number Diff line change
Expand Up @@ -348,5 +348,15 @@ function base_change(phi::Any, C::Covering)
mor_dict[V] = phi
end

# Maintain decomposition information if applicable
decomp_dict = IdDict{AbsSpec, Vector{RingElem}}()
if has_decomposition_info(C)
for (U, psi) in patch_change
V = codomain(psi)
decomp_dict[U] = elem_type(OO(U))[pullback(psi)(a) for a in decomposition_info(C)[V]]
end
end
set_decomposition_info!(CC, decomp_dict)

return CC, CoveringMorphism(CC, C, mor_dict, check=true) # TODO: Set to false after testing
end
1 change: 1 addition & 0 deletions src/AlgebraicGeometry/Schemes/Covering/Objects/Types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ mutable struct Covering{BaseRingType}
glueing_graph::Graph{Undirected}
transition_graph::Graph{Undirected}
edge_dict::Dict{Tuple{Int, Int}, Int}
decomp_info::IdDict{<:AbsSpec, <:Vector{<:RingElem}}

function Covering(
patches::Vector{<:AbsSpec},
Expand Down
17 changes: 17 additions & 0 deletions test/AlgebraicGeometry/Schemes/CoveredProjectiveSchemes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,20 @@ end
I_sing_Y1 = image_ideal(inc_Y1)
@test !is_smooth(Y1)
end

@testset "decomposition information" begin
P3 = projective_space(QQ, 3)
X = covered_scheme(P3)
S = homogeneous_coordinate_ring(P3)
(x,y, z, w) = gens(S)
A = S[x y z; y z w]
I = ideal(S, minors(A, 2))
II = ideal_sheaf(P3, I)
pr = blow_up(II)
Y = domain(projection(pr))
@test oscar.has_decomposition_info(oscar.simplified_covering(Y))
E = exceptional_divisor(pr)
IE = ideal_sheaf(E)
Z = subscheme(IE)
@test oscar.has_decomposition_info(oscar.simplified_covering(Z))
end
8 changes: 8 additions & 0 deletions test/AlgebraicGeometry/Schemes/CoveredScheme.jl
Original file line number Diff line number Diff line change
Expand Up @@ -234,3 +234,11 @@ end
(a, b, c) = base_change(pr, inc_X)
@test compose(a, inc_X) == compose(b, c)
end

@testset "decomposition info" begin
P3 = projective_space(ZZ, 3)
X = covered_scheme(P3)
kk = GF(29)
X29, f = base_change(kk, X)
@test oscar.has_decomposition_info(default_covering(X29))
end
Loading