From fe84dfc73ba56f096dc5dc329e84ef38c7b32563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anne=20Fr=C3=BChbis-Kr=C3=BCger?= <77079696+afkafkafk13@users.noreply.github.com> Date: Wed, 15 May 2024 13:36:27 +0200 Subject: [PATCH] Zariski/Lipman approach to resolution of singularities for 2-dim. schemes (#3639) * normalization morphism and Lipman * definition of NormalizationMorphism * handling of exceptional divisor/locus for mixed blowup sequences --------- Co-authored-by: anne --- experimental/Schemes/BlowupMorphism.jl | 15 +- experimental/Schemes/Resolution_structure.jl | 555 +++++++++++++++--- .../Schemes/CoveredSchemes/Objects/Methods.jl | 7 +- .../Schemes/Resolution_structure.jl | 43 +- 4 files changed, 523 insertions(+), 97 deletions(-) diff --git a/experimental/Schemes/BlowupMorphism.jl b/experimental/Schemes/BlowupMorphism.jl index c2e10c7dca01..de375a031379 100644 --- a/experimental/Schemes/BlowupMorphism.jl +++ b/experimental/Schemes/BlowupMorphism.jl @@ -542,6 +542,10 @@ For a `BlowupMorphism` ``p : Y → X`` and an `EffectiveCartierDivisor` ``C`` o strict transform of ``C`` on ``Y``. """ function strict_transform(p::AbsSimpleBlowdownMorphism, C::EffectiveCartierDivisor) + return strict_transform_with_multiplicity(p,C)[1] +end + +function strict_transform_with_multiplicity(p::AbsSimpleBlowdownMorphism, C::EffectiveCartierDivisor) X = scheme(C) Y = domain(p) X === codomain(p) || error("cartier divisor is not defined on the codomain of the morphism") @@ -597,7 +601,7 @@ function strict_transform(p::AbsSimpleBlowdownMorphism, C::EffectiveCartierDivis ## we are good to go now C_strict = EffectiveCartierDivisor(Y, ID, check=false) - return C_strict + return C_strict,multEInC end function strict_transform(p::AbsSimpleBlowdownMorphism, C::CartierDivisor) @@ -862,16 +866,17 @@ end # fields for caching, may be filled during computation ex_div::Vector{<:EffectiveCartierDivisor} # list of exc. divisors arising from individual steps # lives in domain(maps[end]) + control::Int # value of control for controlled transform ex_mult::Vector{Int} # multiplicities of exceptional divisors removed from - # controlled or weak transform, not set for is_embedded == false - # and transform_type == strict - controlled_transform::AbsIdealSheaf # holds weak or controlled transform according to transform_type + # total transform, not set for is_embedded == false + # or transform_type == strict + controlled_transform::AbsIdealSheaf # holds weak or controlled transform according to transform_type # fields for caching to be filled a posteriori (on demand, only if partial_res==false) underlying_morphism::CompositeCoveredSchemeMorphism{DomainType, CodomainType} exceptional_divisor::CartierDivisor # exceptional divisor of composed_map exceptional_locus::WeilDivisor # exceptional locus of composed map - exceptional_divisor_on_X::WeilDivisor # exceptional divisor of composed_map + exceptional_divisor_on_X::CartierDivisor # exceptional divisor of composed_map # restricted to domain(embeddings[end]) function BlowUpSequence(maps::Vector{<:BlowupMorphism}) diff --git a/experimental/Schemes/Resolution_structure.jl b/experimental/Schemes/Resolution_structure.jl index 898cd3645a13..55cb5dff97a6 100644 --- a/experimental/Schemes/Resolution_structure.jl +++ b/experimental/Schemes/Resolution_structure.jl @@ -1,54 +1,148 @@ -## Warnung: show auf desingMor geht noch nicht!!! -export _desing_curve -export find_refinement_with_local_system_of_params +export find_refinement_with_local_system_of_params +export inclusion_morphisms +export embedded_desingularization +export desingularization +export desingularization_only_blowups +export exceptional_locus +export NormalizationMorphism +export locus_of_maximal_order + +############################################################################## +## Concrete Type for normalization +## very similar to CoveredSchemeMorphism, but allowing disjoint handling +## of disjoint components +############################################################################## +@doc raw""" + NormalizationMorphism{ + DomainType<:AbsCoveredScheme, + CodomainType<:AbsCoveredScheme + } <:AbsCoveredSchemeMorphism{ + DomainType, + CodomainType, + Nothing, + NormalizationMorphism, + } +A datastructure to encode normalizations of covered schemes. + +It is described as the morphism from the new scheme to the original one, containing +information on the decomposition of the new scheme into disjoint components. +(This is the type of the return value of `normalization(X::AbsCoveredScheme)`.) +""" +@attributes mutable struct NormalizationMorphism{ + DomainType<:AbsCoveredScheme, + CodomainType<:AbsCoveredScheme + } <:AbsCoveredSchemeMorphism{ + DomainType, + CodomainType, + Nothing, + NormalizationMorphism, + } + + underlying_morphism::CoveredSchemeMorphism + inclusions::Vector{<:AbsCoveredSchemeMorphism} + + function NormalizationMorphism( + f::CoveredSchemeMorphism, + inclusions::Vector{<:AbsCoveredSchemeMorphism}; + check::Bool=true + ) + @check is_normal(X) "not a normalization morphism" + @assert all(inc->codomain(inc) === domain(f), inclusions) "domains and codomains do not match" + ret_value = new{typeof(domain(f)),typeof(codomain(f))}(f,inclusions) + return ret_value + end + + function NormalizationMorphism( + f::CoveredSchemeMorphism; + check::Bool=true + ) + @check is_normal(X) "not a normalization morphism" + ret_value = new{typeof(domain(f)),typeof(codomain(f))}(f,[identity_map(X)]) + return ret_value + end + +end ##################################################################################################### # Desingularization morphism: birational map between covered schemes with smooth domain ##################################################################################################### +@doc raw""" + MixedBlowUpSequence{ + DomainType<:AbsCoveredScheme, + CodomainType<:AbsCoveredScheme + }<:AbsDesingMor{ DomainType, + CodomainType, + MixedBlowUpSequence{DomainType, CodomainType} + } +A datastructure to encode sequences of blow-ups and normalizations of covered schemes +as needed for desingularization of non-embedded schemes by the approaches of Zariski and of +Lipman. +""" + +@attributes mutable struct MixedBlowUpSequence{ + DomainType<:AbsCoveredScheme, + CodomainType<:AbsCoveredScheme + }<:AbsDesingMor{ DomainType, + CodomainType, + MixedBlowUpSequence{DomainType, CodomainType} + } + maps::Vector{Union{<:BlowupMorphism,<:NormalizationMorphism}} # count right to left: + # original scheme is codomain of map 1 + # boolean flags + resolves_sing::Bool # domain not smooth yet? + is_trivial::Bool # codomain already smooth? + + # fields for caching, to be filled during desingularization + # always carried along to domain(maps[end])) using strict_transform + ex_div::Vector{AbsIdealSheaf} # list of exc. divisors arising from individual steps + + # keep track of the normalization steps + normalization_steps::Vector{Int} + + # fields for caching to be filled a posteriori (on demand, only if partial_res==false) + underlying_morphism::CompositeCoveredSchemeMorphism{DomainType, CodomainType} + exceptional_divisor::AbsWeilDivisor + exceptional_locus::AbsAlgebraicCycle + + function MixedBlowUpSequence(maps::Vector{<:AbsCoveredSchemeMorphism}) + n = length(maps) + for i in 1:n + @assert all(x->((x isa BlowupMorphism) || (x isa NormalizationMorphism)), maps) "only blow-ups and normalizations allowed" + end + for i in 1:n-1 + @assert domain(maps[i]) === codomain(maps[i+1]) "not a sequence of morphisms" + end + resi = new{typeof(domain(maps[end])),typeof(codomain(first(maps)))}(maps) + resi.normalization_steps = [i for i in 1:n if maps[i] isa NormalizationMorphism] + return resi + end -# Fehlt: NormalizationMorphism fuer Schemata -- muessten wir haben, sobald wir Lipman machen wollen -# -#@attributes mutable struct LipmanStyleSequence{ -# DomainType<:AbsCoveredScheme, -# CodomainType<:AbsCoveredScheme -# } <: AbsDesingMor{ -# DomainType, -# CodomainType, -# } -# maps::Vector{: CartierDivisor + +Return a `CartierDivisor` on the `domain` of `f` which is the +exceptional divisor of the sequence of blow-ups `f`. + +# Example +```jldoctest +julia> R,(x,y) = polynomial_ring(QQ,2); + +julia> I=ideal(R,[x^2-y^5]); + +julia> W = AffineScheme(R); + +julia> IS = IdealSheaf(W,I); + +julia> X = subscheme(IS); + +julia> U = first(affine_charts(X)); + +julia> phi = desingularization_only_blowups(X); + +julia> exceptional_divisor(phi) +Cartier divisor + on scheme over QQ covered with 3 patches +with coefficients in integer ring +defined by the formal sum of + 1 * effective cartier divisor on scheme over QQ covered with 3 patches +``` +""" +function exceptional_divisor(f::BlowUpSequence) + f.is_embedded && return _exceptional_divisor_in_ambient(f) + return _exceptional_divisor_non_embedded(f) +end + +@doc raw""" + exceptional_locus(f::AbsBlowUpSequence) + +Return a `WeilDivisor` on the `domain` of `f` which is the +exceptional divisor of the sequence of blow-ups `f`. + +# Example +```jldoctest +julia> R,(x,y) = polynomial_ring(QQ,2); + +julia> I=ideal(R,[x^2-y^5]); + +julia> W = AffineScheme(R); + +julia> IS = IdealSheaf(W,I); + +julia> X = subscheme(IS); + +julia> U = first(affine_charts(X)); + +julia> phi = desingularization_only_blowups(X); + +julia> exceptional_locus(phi) +Effective weil divisor + on scheme over QQ covered with 3 patches +with coefficients in integer ring +given as the formal sum of + 1 * sheaf of ideals + +``` +""" +function exceptional_locus(phi::BlowUpSequence) + if !isdefined(phi, :exceptional_locus) + phi.exceptional_locus = weil_divisor(exceptional_divisor(phi)) + end + return phi.exceptional_locus +end + +@doc raw""" + exceptional_divisor_with_multiplicities(f::BlowUpSequence) --> CartierDivisor + +Return a `CartierDivisor` `C` on the `domain` of the emmbedded desingularization morphism `f` +which is the exceptional divisor of the sequence of blow-ups `f` in the ambient scheme. +""" +function exceptional_divisor_with_multiplicities(f::BlowUpSequence) + f.is_embedded || error("only available for embedded desingularization") + f.transform_type != :strict || error("only available for weak and controlled transforms") + + ex_div_list = exceptional_divisor_list(f) + C = sum(f.ex_mult[i] * cartier_divisor(ex_div_list[i]) for i in 1:length(ex_div_list)) + return C +end + +function _exceptional_divisor_in_ambient(f::BlowUpSequence) + f.is_embedded || error("only for embedded desingularization") + !isdefined(f,:exceptional_divisor) || return f.exceptional_divisor + f.exceptional_divisor = sum(f.ex_div; init=CartierDivisor(domain(f),ZZ)) + return f.exceptional_divisor +end + +function _exceptional_divisor_non_embedded(f::MixedBlowUpSequence) + !isdefined(f,:exceptional_divisor) || return f.exceptional_divisor + + ex_div_list = exceptional_divisor_list(f) + C = WeilDivisor(scheme(ex_div_list[1]),ZZ) + for i in 2:length(ex_div_list) + dim(ex_div_list[i])== -1 && continue # kick out empty ones + C = C + weil_divisor(ex_div_list[i]) + end + + f.exceptional_divisor = C + return C +end + +function _exceptional_divisor_non_embedded(f::BlowUpSequence) + !isdefined(f,:exceptional_divisor_on_X) || return f.exceptional_divisor_on_X + + ex_div_list = exceptional_divisor_list(f) + C = CartierDivisor(scheme(ex_div_list[1]),ZZ) + for i in 1:length(ex_div_list) +# do we want to introduce is_empty for divisors? + dim(ideal_sheaf(ex_div_list[i]))== -1 && continue # kick out empty ones + # caution: dim(CartierDivisor) is not computed, + # but inferred + # ==> need to pass to ideal_sheaf first + C = C + cartier_divisor(ex_div_list[i]) + end + + f.exceptional_divisor_on_X = C + return C +end + +function exceptional_divisor(f::MixedBlowUpSequence) + !isdefined(f,:exceptional_divisor_on_X) || return f.exceptional_divisor_on_X + f.resolves_sing || error("exceptional locus need not be a divisor for intermediate steps -- use exceptional_locus") + + return _exceptional_divisor_non_embedded(f) +end + +function exceptional_locus(f::MixedBlowUpSequence) + !isdefined(f,:exceptional_locus) || return f.exceptional_locus + + ex_div_list = exceptional_divisor_list(f) # these are IdealSheaves for MixedBlowUpSequences + # they might even have the wrong dimension + C = AlgebraicCycle(scheme(ex_div_list[1]),ZZ) # ==> we cannot expect to obtain a divisor, only a cycle + for E in ex_div_list + dim(E) != -1 || continue # kick out empty ones + C = C + algebraic_cycle(E) + end + + return C +end + ################################################################################################## # setting values in DesingMors -- Watch out: only place with direct access to fields!!! ################################################################################################## @@ -64,39 +306,87 @@ function add_map!(f::BlowUpSequence, phi::BlowupMorphism) ex_div = [strict_transform(phi,E) for E in f.ex_div[1:end]] push!(ex_div, exceptional_divisor(phi)) f.ex_div = ex_div + if isdefined(f, :underlying_morphism) + f.underlying_morphism = CompositeCoveredSchemeMorphism(reverse(morphisms(f))) + end return f end -function initialize_blow_up_sequence(phi::BlowupMorphism) - f = BlowUpSequence([phi]) - f.ex_div = [exceptional_divisor(phi)] - f.is_trivial = is_one(center(phi)) - f.resolves_sing = false # we have no information, wether we are done - # without further computation - f.is_embedded = false +function add_map!(f::MixedBlowUpSequence, phi::BlowupMorphism) + push!(f.maps, phi) + ex_div = (AbsIdealSheaf)[strict_transform(phi,E) for E in f.ex_div] + push!(ex_div, ideal_sheaf(exceptional_divisor(phi))) + f.ex_div = ex_div + if isdefined(f, :underlying_morphism) + f.underlying_morphism = CompositeCoveredSchemeMorphism(reverse(morphisms(f))) + end + return f +end + +function add_map!(f::MixedBlowUpSequence, phi::NormalizationMorphism) + push!(f.maps, phi) + sl = ideal_sheaf_of_singular_locus(codomain(phi)) + ex_div = (AbsIdealSheaf)[pullback(phi,E) for E in exceptional_divisorlist(f,true)] + push!(ex_div,pullback(phi, sl)) + f.ex_div = ex_div + push!(f.normalization_steps,length(f.maps)) + if isdefined(f, :underlying_morphism) + f.underlying_morphism = CompositeCoveredSchemeMorphism(reverse(morphisms(f))) + end return f end function add_map_embedded!(f::BlowUpSequence, phi::BlowupMorphism) push!(f.maps, phi) - ex_div = typeof(f.ex_div[1])[strict_transform(phi, E) for E in f.ex_div[1:end]] + + strict_list = [strict_transform_with_multiplicity(phi,E) for E in f.ex_div] + ex_div = [a[1] for a in strict_list] push!(ex_div, exceptional_divisor(phi)) f.ex_div = ex_div + + excess_mult = sum(a[2] for a in strict_list) if f.transform_type == :strict X_strict, inc_strict,_ = strict_transform(phi, f.embeddings[end]) push!(f.embeddings, inc_strict) elseif f.transform_type == :weak I_trans,b = weak_transform_with_multiplicity(phi, f.controlled_transform) - push!(f.ex_mult,b) + push!(f.ex_mult,b + excess_mult) f.controlled_transform = I_trans + f.control = b else - I_trans = controlled_transform(phi, f.controlled_transform, f.ex_mult[end]) + I_trans = controlled_transform(phi, f.controlled_transform, f.control) f.controlled_transform = I_trans push!(f.ex_mult, f.ex_mult[end]) end + if isdefined(f, :underlying_morphism) + f.underlying_morphism = CompositeCoveredSchemeMorphism(reverse(morphisms(f))) + end return f end +function initialize_blow_up_sequence(phi::BlowupMorphism) + f = BlowUpSequence([phi]) + f.ex_div = [exceptional_divisor(phi)] + f.is_trivial = is_one(center(phi)) + f.resolves_sing = false # we have no information, wether we are done + # without further computation + f.is_embedded = false + return f +end + +function initialize_mixed_blow_up_sequence(phi::NormalizationMorphism, I::AbsIdealSheaf) + f = MixedBlowUpSequence([phi]) + f.ex_div = [pullback(phi,I)] + f.is_trivial = is_one(I) + f.resolves_sing = false # we have no information, wether we are done + # without further computation + return f +end + +function initialize_mixed_blow_up_sequence(phi::BlowupMorphism) + return mixed_blow_up_sequence(initialize_blow_up_sequence(phi)) +end + function initialize_embedded_blowup_sequence(phi::BlowupMorphism, inc::CoveredClosedEmbedding) f = BlowUpSequence([phi]) f.ex_div = [exceptional_divisor(phi)] @@ -111,7 +401,7 @@ function initialize_embedded_blowup_sequence(phi::BlowupMorphism, inc::CoveredCl else f.is_trivial = true f.embeddings = [inc, inc] - f.resolves_sing = false + f.resolves_sing = false # should be set elsewhere end return f end @@ -129,8 +419,9 @@ function initialize_embedded_blowup_sequence(phi::BlowupMorphism, I::AbsIdealShe I_trans = controlled_transform(phi, I, b) f.transform_type = :controlled end - f.controlled_transform = I_trans # CAUTION: b is considered set once and for all + f.controlled_transform = I_trans f.ex_mult = [b] + f.control = b f.resolves_sing = false # we have no information, whether we are done # without further computation else @@ -138,16 +429,40 @@ function initialize_embedded_blowup_sequence(phi::BlowupMorphism, I::AbsIdealShe f.controlled_transform = I f.transform_type = :weak f.ex_mult = [0] - f.resolves_sing = false + f.resolves_sing = false # should be set elsewhere end return f end +function forget_embedding(f::BlowUpSequence) +## create new BlowUpSequence, where maps contains maps between the domains of f +## - set is_embedded to false +## - inherit resolves_sing, is_trivial +## - new ex_div is induced divisor arising from f.ex_div on domain(f.maps[end]) +## forget last blow-ups arising after the X has become smooth + error("not implemented yet") +end + +function mixed_blow_up_sequence(f::BlowUpSequence) + phi = MixedBlowUpSequence(morphisms(f)) + phi.resolves_sing = f.resolves_sing + phi.is_trivial = f.is_trivial + phi.ex_div = [ideal_sheaf(E) for E in f.ex_div] + phi.normalization_steps = Vector{Int}[] + if isdefined(f, :underlying_morphism) + phi.underlying_morphism = f.underlying_morphism + end + if isdefined(f, :exceptional_divisor) + phi.exceptional_divisor = f.exceptional_divisor + end + return phi +end + ################################################################################################## # desingularization workers ################################################################################################## -function embedded_desingularization(f::Oscar.CoveredClosedEmbedding; algorithm::Symbol=:BEV) +function embedded_desingularization(f::CoveredClosedEmbedding; algorithm::Symbol=:BEV) I_sl = ideal_sheaf_of_singular_locus(domain(f)) ## trivial case: domain(f) was already smooth @@ -191,27 +506,66 @@ function desingularization(X::AbsCoveredScheme; algorithm::Symbol=:Lipman) return_value = BlowUpSequence(maps) return_value.resolves_sing = true return_value.is_trivial = true - return return_value + return mixed_blow_up_sequence(return_value) end + Xnorm, phi = normalization(X) + incs = phi.inclusions + f = initialize_mixed_blow_up_sequence(phi,I_sl) + I_sl = ideal_sheaf_of_singular_locus(Xnorm) + ## I_sl non-empty, we need to do something # here the keyword algorithm ensures that the desired method is called dimX = dim(X) if dimX == 1 - return _desing_curve(X, I_sl) + return_value = f + return_value.resolves_sing = true + elseif ((dimX == 2) && (algorithm==:Lipman)) + return_value = _desing_lipman(Xnorm, I_sl, f) + elseif ((dimX == 2) && (algorithm==:Jung)) + error("not implemented yet") +# second_seq = _desing_jung(Xnorm,f) +# return_value = extend(phi, second_seq) + else + error("not implemented yet") +# second_seq = forget_embedding(_desing_BEV(Xnorm)) +# return_value = extend(phi, second_seq) end -# if ((dimX == 2) && (algorithm==:Lipman)) -# error("not implemented yet") -# return_value = _desing_lipman(X, I_sl) -# return return_value -# end -# if ((dimX == 2) && (algorithm==:Jung)) + + return return_value +end + +function desingularization_only_blowups(X::AbsCoveredScheme; algorithm::Symbol=:Lipman) + I_sl = ideal_sheaf_of_singular_locus(X) + + ## trivial case: X is already smooth + if is_one(I_sl) + id_X = identity_blow_up(X) + maps = [id_X] + return_value = BlowUpSequence(maps) + return_value.resolves_sing = true + return_value.is_trivial = true + return mixed_blow_up_sequence(return_value) + end + + + ## I_sl non-empty, we need to do something + # here the keyword :algorithm ensures that the desired method is called + dimX = dim(X) + if dimX == 1 + return_value = _desing_curve(X, I_sl) +# elseif ((dimX == 2) && (algorithm==:Jung)) # error("not implemented yet") # return_value = _desing_jung(X) -# end - error("not implemented yet") + else + error("not implemented yet") + return_value = forget_embedding(_desing_BEV(X)) + end + + return return_value end + function desingularization(X::AbsAffineScheme; algorithm::Symbol=:BEV) return desingularization(CoveredScheme(X); algorithm) end @@ -241,6 +595,40 @@ function _desing_curve(X::AbsCoveredScheme, I_sl::AbsIdealSheaf) return phi end +function _desing_lipman(X::AbsCoveredScheme, I_sl::AbsIdealSheaf, f::MixedBlowUpSequence) + dim(X) == 2 || error("Lipman's algorithm is not applicable") + + if dim(I_sl) == 1 # called for a non-normal X + Xnorm, phi = normalization(X) + incs = phi.inclusions + f = initialize_mixed_blow_up_sequence(phi,I_sl) + I_sl_temp = ideal_sheaf_of_singular_locus(Xnorm) + else + I_sl_temp = I_sl + end + + decomp = maximal_associated_points(I_sl_temp) + + while !is_one(I_sl_temp) + while length(decomp) > 0 + I = small_generating_set(pop!(decomp)) + f = _do_blow_up!(f,I) + if length(decomp)>0 + decomp = [strict_transform(last_map(f),J) for J in decomp] + end + end + I_sl_temp = ideal_sheaf_of_singular_locus(domain(last_map(f))) + if dim(I_sl_temp) == 1 + f = _do_normalization!(f) + I_sl_temp = ideal_sheaf_of_singular_locus(domain(last_map(f))) + end + decomp = maximal_associated_points(I_sl_temp) + end + + f.resolves_sing = true + return f +end + function _desing_emb_curve(f::CoveredClosedEmbedding, I_sl::AbsIdealSheaf) ## note: I_sl not unit_ideal_sheaf, because this has been caught before in embedded_desingularization(f) decomp = maximal_associated_points(pushforward(f)(I_sl)) @@ -318,7 +706,6 @@ function _ensure_ncr!(f::AbsDesingMor) return f end - function _do_blow_up!(f::AbsDesingMor, cent::AbsIdealSheaf) old_sequence = morphisms(f) X = domain(old_sequence[end]) @@ -328,6 +715,12 @@ function _do_blow_up!(f::AbsDesingMor, cent::AbsIdealSheaf) return(f) end +function _do_normalization!(f::MixedBlowUpSequence) + Xnorm, phi = normalization(domain(last_map(f))) + add_map!(f,phi) + return f +end + function _do_blow_up_embedded!(phi::AbsDesingMor,cent::AbsIdealSheaf) old_sequence = morphisms(phi) X = domain(old_sequence[end]) @@ -474,7 +867,7 @@ end # locus of order at least b and of maximal order ################################################################################################## -function max_order_locus(I::AbsIdealSheaf) +function locus_of_maximal_order(I::AbsIdealSheaf) return _delta_list(I)[end] end @@ -729,38 +1122,31 @@ is_graded(R::Ring) = false # experimental/Schemes/BlowupMorphism.jl ######################################################################## -function exceptional_divisor(phi::BlowUpSequence) - #TODO: Check whether the full resolution has already been computed? - if !isdefined(phi, :exceptional_divisor) - phi.exceptional_divisor = sum(phi.ex_div; init=CartierDivisor(domain(phi), ZZ)) - end - return phi.exceptional_divisor -end - -function exceptional_locus(phi::BlowUpSequence) - if !isdefined(phi, :exceptional_locus) - phi.exceptional_locus = weil_divisor(exceptional_divisor(phi)) - end - return phi.exceptional_locus -end - # The following two methods will be ambiguous in general # so we need to repeat the procedure for the specific types # of the second argument. -function strict_transform(phi::BlowUpSequence, a::Any) - for psi in morhpisms(phi) +function strict_transform(phi::Union{BlowUpSequence,MixedBlowUpSequence}, a::Any) + for psi in morphisms(phi) a = strict_transform(psi, a) end return a end -function total_transform(phi::BlowUpSequence, a::Any) +function total_transform(phi::Union{BlowUpSequence,MixedBlowUpSequence}, a::Any) for psi in morphisms(phi) a = total_transform(psi, a) end return a end +function total_transform(phi::NormalizationMorphism, a::Any) + return pullback(phi,a) +end + +function strict_transform(phi::NormalizationMorphism, a::Any) + return pullback(phi,a) +end + function strict_transform(phi::BlowUpSequence, a::AbsIdealSheaf) for psi in morphisms(phi) a = strict_transform(psi, a) @@ -775,7 +1161,12 @@ function total_transform(phi::BlowUpSequence, a::AbsIdealSheaf) return a end -function center(phi::BlowUpSequence) +function last_center(phi::BlowUpSequence) return center(last_map(phi)) end +function last_center(phi::MixedBlowUpSequence) + lm = last_map(phi) + lm isa BlowupMorphism || return unit_ideal_sheaf(codomain(lm)) + return center(lm) +end diff --git a/src/AlgebraicGeometry/Schemes/CoveredSchemes/Objects/Methods.jl b/src/AlgebraicGeometry/Schemes/CoveredSchemes/Objects/Methods.jl index b215a33aa684..15a095752157 100644 --- a/src/AlgebraicGeometry/Schemes/CoveredSchemes/Objects/Methods.jl +++ b/src/AlgebraicGeometry/Schemes/CoveredSchemes/Objects/Methods.jl @@ -221,7 +221,7 @@ with default covering 2: [(x//y), (z//y)] 3: [(x//z), (y//z)] -julia> Y, pr_mor, injs = normalization(X); +julia> Y, pr_mor = normalization(X); julia> Y Scheme @@ -259,7 +259,7 @@ given by the pullback functions (x//z) -> x (y//z) -> y -julia> injs +julia> inclusion_morphisms(pr_mor) 1-element Vector{CoveredSchemeMorphism{CoveredScheme{QQField}, CoveredScheme{QQField}, AbsAffineSchemeMor}}: Hom: scheme over QQ covered with 3 patches -> scheme over QQ covered with 3 patches ``` @@ -280,7 +280,8 @@ function normalization(X::AbsCoveredScheme; check::Bool=true) merge!(pr_dict, pr_dicts...) pr_covering_mor = CoveringMorphism(default_covering(Y), default_covering(X), pr_dict; check=false) pr_mor = CoveredSchemeMorphism(Y, X, pr_covering_mor; check=false) - return Y, pr_mor, injs + pr_mor = Oscar.NormalizationMorphism(pr_mor,injs; check=false) + return Y, pr_mor end function _normalization_integral(X::AbsCoveredScheme; check::Bool=true) diff --git a/test/AlgebraicGeometry/Schemes/Resolution_structure.jl b/test/AlgebraicGeometry/Schemes/Resolution_structure.jl index 9922acad004a..928934d93456 100644 --- a/test/AlgebraicGeometry/Schemes/Resolution_structure.jl +++ b/test/AlgebraicGeometry/Schemes/Resolution_structure.jl @@ -5,7 +5,7 @@ IS = IdealSheaf(W,I) WC = scheme(IS) inc_X = Oscar.CoveredClosedEmbedding(WC,IS) - phi = Oscar.embedded_desingularization(inc_X) + phi = embedded_desingularization(inc_X) H = IdealSheaf(W, ideal(R, x + 3*y), covered_scheme=WC) @test is_subset(total_transform(phi, H), strict_transform(phi, H)) @test length(phi.ex_div) == 4 @@ -18,6 +18,8 @@ @test is_one(ideal_sheaf(phi.ex_div[3]) + ideal_sheaf(phi.ex_div[4]) + image_ideal(phi.embeddings[end])) @test !is_empty(singular_locus(domain(phi.embeddings[2]))[1]) @test is_empty(singular_locus(domain(phi.embeddings[3]))[1]) + @test length(components(exceptional_divisor(phi))) == 4 + @test length(components(exceptional_locus(phi))) == 4 end @testset "non-embedded desingularization of curves" begin @@ -27,10 +29,10 @@ end IS = IdealSheaf(W,I) X = subscheme(IS) U = first(affine_charts(X)) - phi = Oscar.desingularization(X) + phi = desingularization_only_blowups(X) H = IdealSheaf(U, ideal(OO(U), x + 3*y), covered_scheme=X) @test is_subset(total_transform(phi, H), strict_transform(phi, H)) - center(phi) + @test dim(center(Oscar.last_map(phi))) == 0 @test length(phi.ex_div) == 2 aff_charts = affine_charts(domain(phi)) sl1,_ = singular_locus(aff_charts[1]) @@ -39,6 +41,33 @@ end @test is_one(modulus(OO(sl1))) @test is_one(modulus(OO(sl2))) @test is_one(modulus(OO(sl3))) + @test length(components(exceptional_divisor(phi))) == 1 + @test length(components(exceptional_locus(phi))) == 1 + psi = desingularization(X) + @test length(morphisms(psi)) == 1 + @test morphism(psi,1) isa NormalizationMorphism +end + +@testset "non-embedded desingularization Lipman (dim=2)" begin + R,(x,y,z) = polynomial_ring(QQ,3) + I=ideal(R,[(x^2-y^5)*(x^2+y^2+z^4)]) + W = AffineScheme(R) + IS = IdealSheaf(W,I) + X = subscheme(IS) + U = first(affine_charts(X)) + phi = desingularization(X) + @test morphism(phi,1) isa NormalizationMorphism + @test morphism(phi,2) isa BlowupMorphism + @test morphism(phi,3) isa BlowupMorphism + aff_charts = affine_charts(domain(phi)) + sl1,_ = singular_locus(aff_charts[1]) + @test is_one(modulus(OO(sl1))) + sl5,_ = singular_locus(aff_charts[5]) + @test is_one(modulus(OO(sl5))) + sl6,_ = singular_locus(aff_charts[6]) + @test is_one(modulus(OO(sl6))) + @test length(components(exceptional_divisor(phi))) == 2 + @test_broken length(components(exceptional_locus(phi))) == 2 end @testset "order of an ideal" begin @@ -47,7 +76,7 @@ end I = ideal(R,[(x+y)^3+z^4]) IS = IdealSheaf(W,I) WC = scheme(IS) - IY = Oscar.max_order_locus(IS) + IY = locus_of_maximal_order(IS) decomp = Oscar.maximal_associated_points(IY) @test length(decomp) == 1 @test decomp[1] == IdealSheaf(W,ideal(R,[z,x+y]), covered_scheme=WC) @@ -55,8 +84,8 @@ end li = Oscar._delta_list(JS) @test length(li) == 3 @test li[1] == JS - @test Oscar.radical(li[2]) == IdealSheaf(W,ideal(R,[x,z]), covered_scheme=WC) - @test Oscar.radical(li[2]) == Oscar.radical(Oscar.locus_of_order_geq_b(JS,2)) - @test Oscar.radical(li[3]) == IdealSheaf(W,ideal(R,[x,y,z]),covered_scheme=WC) + @test radical(li[2]) == IdealSheaf(W,ideal(R,[x,z]), covered_scheme=WC) + @test radical(li[2]) == radical(Oscar.locus_of_order_geq_b(JS,2)) + @test radical(li[3]) == IdealSheaf(W,ideal(R,[x,y,z]),covered_scheme=WC) end