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

Banff presentation rebased #3898

Merged
merged 6 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
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
42 changes: 32 additions & 10 deletions experimental/Schemes/src/IdealSheaves.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1564,7 +1564,11 @@
end

### PrimeIdealSheafFromChart
function produce_object(F::PrimeIdealSheafFromChart, U2::AbsAffineScheme)
function produce_object(
F::PrimeIdealSheafFromChart, U2::AbsAffineScheme;
algorithm::Symbol=:pushforward # Either :pushforward or :pullback
# This determines how to extend through the gluings.
)
# Initialize some local variables
X = scheme(F)
OOX = OO(X)
Expand Down Expand Up @@ -1620,14 +1624,29 @@
glue = default_covering(X)[W, V2]
f, g = gluing_morphisms(glue)
if glue isa SimpleGluing || (glue isa LazyGluing && first(gluing_domains(glue)) isa PrincipalOpenSubset)
complement_equation(codomain(g)) in F(W) && return ideal(OO(U2), one(OO(U2))) # We know the ideal is prime. No need to saturate!
I2 = F(codomain(g))
I = pullback(g)(I2)
I = ideal(OO(V2), lifted_numerator.(gens(I)))
I = _iterative_saturation(I, lifted_numerator(complement_equation(domain(g))))
result = OOX(V2, U2)(ideal(OO(V2), lifted_numerator.(gens(I))))
@hassert :IdealSheaves 1 is_one(result) || is_prime(result)
return result
if algorithm == :pushforward
complement_equation(codomain(g)) in F(W) && return ideal(OO(U2), one(OO(U2))) # We know the ideal is prime. No need to saturate!
pb_f = pullback(f)::AbsLocalizedRingHom
pb_f_res = restricted_map(pb_f)
@assert domain(pb_f_res) === ambient_coordinate_ring(V2)
Q = preimage(pb_f_res, F(domain(f)))
rest = OOX(V2, U2)
result = ideal(OO(U2), rest.(gens(Q)))
@hassert :IdealSheaves 1 !isone(Q)
@hassert :IdealSheaves 1 is_prime(result)
set_attribute!(result, :is_prime=>true)
return result
elseif algorithm == :pullback
I2 = F(codomain(g))
I = pullback(g)(I2)
I = ideal(OO(V2), lifted_numerator.(gens(I)))
I = _iterative_saturation(I, lifted_numerator(complement_equation(domain(g))))
result = OOX(V2, U2)(ideal(OO(V2), lifted_numerator.(gens(I))))
@hassert :IdealSheaves 1 is_one(result) || is_prime(result)
return result
else
error("algorithm not recognized")

Check warning on line 1648 in experimental/Schemes/src/IdealSheaves.jl

View check run for this annotation

Codecov / codecov/patch

experimental/Schemes/src/IdealSheaves.jl#L1648

Added line #L1648 was not covered by tests
end
else
Z = subscheme(W, F(W))
pZ = preimage(g, Z, check=false)
Expand Down Expand Up @@ -1684,7 +1703,9 @@
if any(x->x===U, patches(dom))
f_loc = f_cov[U]
V = codomain(f_loc)
return pullback(f_loc)(original_ideal_sheaf(I)(V))
KK = original_ideal_sheaf(I)(V)
@assert base_ring(KK) === OO(V)
return pullback(f_loc)(KK)
end

# We are in a chart below a patch in the domain covering
Expand Down Expand Up @@ -1785,6 +1806,7 @@
if has_ancestor(x->(x===U2), U)
iso = _flatten_open_subscheme(U, U2) # an embedding U -> V \subseteq U2
iso_inv = inverse(iso)
P = II(U)

Check warning on line 1809 in experimental/Schemes/src/IdealSheaves.jl

View check run for this annotation

Codecov / codecov/patch

experimental/Schemes/src/IdealSheaves.jl#L1809

Added line #L1809 was not covered by tests
pb_P = pullback(iso_inv)(P)
# avoids a saturation by discarding denominators but only produces a subideal
result = ideal(OO(U2), [g for g in OO(U2).(lifted_numerator.(gens(pb_P))) if !iszero(g)])
Expand Down
2 changes: 1 addition & 1 deletion experimental/Schemes/src/MorphismFromRationalFunctions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,7 @@
min_var = minimum([ngens(OO(V)) for V in all_V])
all_V = [V for V in all_V if ngens(OO(V)) == min_var]
deg_bound = minimum([maximum([total_degree(lifted_numerator(g)) for g in gens(I(V))]) for V in all_V])
all_V = [V for V in all_V if minimum([total_degree(lifted_numerator(g)) for g in gens(I(V))]) == deg_bound]
all_V = [V for V in all_V if maximum([total_degree(lifted_numerator(g)) for g in gens(I(V))]) == deg_bound]

Check warning on line 779 in experimental/Schemes/src/MorphismFromRationalFunctions.jl

View check run for this annotation

Codecov / codecov/patch

experimental/Schemes/src/MorphismFromRationalFunctions.jl#L779

Added line #L779 was not covered by tests
V = first(all_V)

all_U = copy(affine_charts(X))
Expand Down
123 changes: 111 additions & 12 deletions experimental/Schemes/src/WeilDivisor.jl
Original file line number Diff line number Diff line change
Expand Up @@ -439,16 +439,27 @@
return true
end

function has_dimension_leq_zero(I::SumIdealSheaf; covering::Covering=default_covering(scheme(I)))
function has_dimension_leq_zero(I::SumIdealSheaf;
covering::Covering=default_covering(scheme(I)),
use_decomposition_info::Bool=true
)
J = summands(I)
k = findfirst(x->x isa PrimeIdealSheafFromChart, J)
if k !== nothing
P = J[k]
U = original_chart(P)
if !has_dimension_leq_zero(cheap_sub_ideal(I, U))
has_dimension_leq_zero(I(U)) || return false
end
end

# k = findfirst(x->x isa PrimeIdealSheafFromChart, J)
# if k !== nothing
# P = J[k]
# U = original_chart(P)
# if has_decomposition_info(covering) && use_decomposition_info
# K = ideal(OO(U), OO(U).(decomposition_info(covering)[U]))
# if !has_dimension_leq_zero(cheap_sub_ideal(I, U) + K)
# has_dimension_leq_zero(I(U) + K) || return false
# end
# else
# if !has_dimension_leq_zero(cheap_sub_ideal(I, U))
# has_dimension_leq_zero(I(U)) || return false
# end
# end
# end

common_patches = keys(object_cache(first(J)))
for JJ in J[2:end]
Expand All @@ -461,8 +472,56 @@

all_patches = patches(covering)
for U in all_patches
if !has_dimension_leq_zero(cheap_sub_ideal(I, U))
has_dimension_leq_zero(I(U)) || return false
patch_ok = false
# go through the object cache of the summands
if U in keys(object_cache(I))
i = I(U)
if has_decomposition_info(covering) && use_decomposition_info
K = ideal(OO(U), OO(U).(decomposition_info(covering)[U]))
has_dimension_leq_zero(K + i) && (patch_ok = true)
else
has_dimension_leq_zero(i) && (patch_ok = true)

Check warning on line 483 in experimental/Schemes/src/WeilDivisor.jl

View check run for this annotation

Codecov / codecov/patch

experimental/Schemes/src/WeilDivisor.jl#L483

Added line #L483 was not covered by tests
end
patch_ok && continue
end

# Do the same for the summands
for j in summands(I)
if U in keys(object_cache(j))
j_loc = j(U)
if has_decomposition_info(covering) && use_decomposition_info
K = ideal(OO(U), OO(U).(decomposition_info(covering)[U]))
has_dimension_leq_zero(K + j_loc) && (patch_ok = true)
else
has_dimension_leq_zero(j_loc) && (patch_ok = true)

Check warning on line 496 in experimental/Schemes/src/WeilDivisor.jl

View check run for this annotation

Codecov / codecov/patch

experimental/Schemes/src/WeilDivisor.jl#L496

Added line #L496 was not covered by tests
end
patch_ok && break
end
end
patch_ok && continue

# repeat with cheap sub-ideals
for j in summands(I)
j_cheap = cheap_sub_ideal(j, U)
if has_decomposition_info(covering) && use_decomposition_info
K = ideal(OO(U), OO(U).(decomposition_info(covering)[U]))
has_dimension_leq_zero(K + j_cheap) && (patch_ok = true)
else
has_dimension_leq_zero(j_cheap) && (patch_ok = true)

Check warning on line 510 in experimental/Schemes/src/WeilDivisor.jl

View check run for this annotation

Codecov / codecov/patch

experimental/Schemes/src/WeilDivisor.jl#L510

Added line #L510 was not covered by tests
end
patch_ok && break
end
patch_ok && continue

if has_decomposition_info(covering) && use_decomposition_info
K = ideal(OO(U), OO(U).(decomposition_info(covering)[U]))
if !has_dimension_leq_zero(cheap_sub_ideal(I, U) + K)
has_dimension_leq_zero(I(U) + K) || return false
end
else
if !has_dimension_leq_zero(cheap_sub_ideal(I, U))
has_dimension_leq_zero(I(U)) || return false

Check warning on line 523 in experimental/Schemes/src/WeilDivisor.jl

View check run for this annotation

Codecov / codecov/patch

experimental/Schemes/src/WeilDivisor.jl#L522-L523

Added lines #L522 - L523 were not covered by tests
end
end
end
return true
Expand All @@ -479,13 +538,53 @@
return get_attribute(I, :_self_intersection)::Int
end

function _is_known_to_be_one(I::AbsIdealSheaf, U::AbsAffineScheme;
Copy link
Collaborator

Choose a reason for hiding this comment

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

May I suggest to name this function
has_is_one(I::AbsIdealSheaf, U::AbsAffineScheme)
and in its body to call
has_is_one(I::Ideal) ?
We have the has_is_... syntax already in some other places.
It means: has cached the value already ( or it is trivial to compute).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I saw has_is_one being introduced. However, it is something different: Here we ask whether an ideal sheaf is known to be isomorphic to the unit ideal sheaf. has_is_one is asking whether it's easy to decide this question. The implementations are different and it would be more work to adapt this here. Since it's an internal function, I suggest to leave this for the moment.

dec_inf::Vector = elem_type(OO(U))[]
)
K = ideal(OO(U), dec_inf)
if U in keys(object_cache(I))
i = I(U)
has_attribute(i, :is_one) && get_attribute(i, :is_one) === true && return true
one(OO(U)) in gens(i) && return true
is_one(K + i) && return true
end
j = cheap_sub_ideal(I, U)
is_one(j + K) && return true
return false
end

function _is_known_to_be_one(I::SumIdealSheaf, U::AbsAffineScheme;
dec_inf::Vector = elem_type(OO(U))[]
)
K = ideal(OO(U), dec_inf)
for J in summands(I)
if U in keys(object_cache(J))
j = J(U)
has_attribute(j, :is_one) && get_attribute(j, :is_one) === true && return true
one(OO(U)) in gens(j) && return true
is_one(K + j) && return true
end
end
if U in keys(object_cache(I))
i = I(U)
has_attribute(i, :is_one) && get_attribute(i, :is_one) === true && return true
one(OO(U)) in gens(i) && return true
is_one(K + i) && return true
end
j = cheap_sub_ideal(I, U)
is_one(j + K) && return true
return false
end


function colength(I::AbsIdealSheaf; covering::Covering=default_covering(scheme(I)))
X = scheme(I)
all_patches = copy(patches(covering))
patches_done = AbsAffineScheme[]
patches_todo = AbsAffineScheme[]
for U in all_patches
if U in keys(object_cache(I)) && has_attribute(I(U), :is_one) && is_one(I(U))
dec_inf = (has_decomposition_info(covering) ? elem_type(OO(U))[OO(U)(g) for g in decomposition_info(covering)[U]] : elem_type(OO(U))[])
if _is_known_to_be_one(I, U; dec_inf)
push!(patches_done, U)
else
push!(patches_todo, U)
Expand Down
9 changes: 6 additions & 3 deletions src/Rings/mpolyquo-localizations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1369,15 +1369,18 @@ end
n = ngens(P)
imgs_y = t[r+1:(r+n)]
imgs_x = t[r+n+1:end]
I = ideal(A, vcat([one(A) - theta[i]*evaluate(den, imgs_y) for (i, den) in enumerate(denoms)], # Rabinowitsch relations
# Sometimes for unnecessarily complicated sets of generators for I the computation
# wouldn't finish. We try to pass to a `small_generating_set` to hopefully reduce the dependency
# on a particular set of generators.
J = ideal(A, vcat([one(A) - theta[i]*evaluate(den, imgs_y) for (i, den) in enumerate(denoms)], # Rabinowitsch relations
[theta[i]*evaluate(num, imgs_y) - imgs_x[i] for (i, num) in enumerate(nums)], # Graph relations
[evaluate(g, imgs_y) for g in gens(I)])) # codomain's modulus
[evaluate(g, imgs_y) for g in small_generating_set(I)])) # codomain's modulus
# We eliminate the Rabinowitsch variables first, the codomain variables second,
# and finally get to the domain variables. This elimination should be quicker
# than one which does not know the Rabinowitsch property.
oo = degrevlex(theta)*degrevlex(imgs_y)*degrevlex(imgs_x)
#oo = lex(theta)*lex(imgs_y)*lex(imgs_x)
gb = groebner_basis(I, ordering=oo)
gb = groebner_basis(J, ordering=oo)

# TODO: Speed up and use build context.
res_gens = elem_type(A)[f for f in gb if all(e->all(k->is_zero(e[k]), 1:(n+r)), exponents(f))]
Expand Down
11 changes: 11 additions & 0 deletions test/AlgebraicGeometry/Schemes/IdealSheaves.jl
Original file line number Diff line number Diff line change
Expand Up @@ -248,3 +248,14 @@ end
@test 0 in dim.(comp2)
end

@testset "production of ideals" begin
IP2 = projective_space(QQ, [:x, :y, :z])
P2 = covered_scheme(IP2)
U = first(affine_charts(P2))
y, z = gens(OO(U))
I = ideal(OO(U), y-z)
II = IdealSheaf(P2, U, I)
Oscar.produce_object(II, affine_charts(P2)[2]; algorithm=:pullback)
Oscar.produce_object(II, affine_charts(P2)[3]; algorithm=:pushforward)
end

Loading