From 7beaaedbcf547d99d22d1de7e06d8e66b6cf85e8 Mon Sep 17 00:00:00 2001 From: Matthias Zach <85350711+HechtiDerLachs@users.noreply.github.com> Date: Thu, 28 Sep 2023 17:15:25 +0200 Subject: [PATCH] Computeralgebra Rundbrief (#2854) * Implement unions and intersections of projective schemes, closed embeddings for projective schemes. conversion of projective closed embeddings to covered closed embeddings, composition of closed embeddings. * Partially implement fiber products of closed embeddings. --- .../Schemes/CoveredProjectiveSchemes.jl | 42 +++++++++++++ .../CoveredSchemes/Morphisms/Methods.jl | 1 + .../ProjectiveSchemes/Morphisms/Attributes.jl | 19 +++++- .../Morphisms/Constructors.jl | 43 ++++++++++++- .../ProjectiveSchemes/Morphisms/Methods.jl | 41 ++++++++++--- .../ProjectiveSchemes/Morphisms/Types.jl | 61 ++++++++++++++++++- .../ProjectiveSchemes/Objects/Constructors.jl | 3 + .../ProjectiveSchemes/Objects/Methods.jl | 32 ++++++++++ .../Schemes/ProjectiveSchemes.jl | 33 ++++++++++ 9 files changed, 264 insertions(+), 11 deletions(-) diff --git a/experimental/Schemes/CoveredProjectiveSchemes.jl b/experimental/Schemes/CoveredProjectiveSchemes.jl index c804dc36f868..aecd5354731b 100644 --- a/experimental/Schemes/CoveredProjectiveSchemes.jl +++ b/experimental/Schemes/CoveredProjectiveSchemes.jl @@ -1756,3 +1756,45 @@ end # # +function fiber_product( + i1::CoveredClosedEmbedding, + i2::CoveredClosedEmbedding + ) + X1 = domain(i1) + X2 = domain(i2) + Y = codomain(i1) + Y === codomain(i2) || error("codomains do not coincide") + i1_cov = covering_morphism(i1) + i2_cov = covering_morphism(i2) + codomain(i1_cov) === codomain(i2_cov) || error("case of different coverings in codomain not implemented") + cod_cov = codomain(i1_cov) + #= + cod_ref, ref1, ref2 = common_refinement(codomain(i1_cov), codomain(i2_cov)) + dom_ref1, i1_res = fiber_product(i1, ref1) + dom_ref2, i2_res = fiber_product(i1, ref2) + # etc. etc.... This is roughly the generic code to come. + =# + I1 = image_ideal(i1) + pb_I1 = pullback(i2, I1) + I2 = image_ideal(i2) + pb_I2 = pullback(i1, I2) + + j1 = Oscar.CoveredClosedEmbedding(domain(i2), pb_I1) + Z = domain(j1) + morphism_dict = IdDict{AbsSpec, ClosedEmbedding}() + for U in affine_charts(Z) + V2 = codomain(j1[U]) + W = codomain(i2[V2]) + V1_candidates = maps_with_given_codomain(i1, W) + @assert length(V1_candidates) == 1 "not the correct number of patches found" + V1 = domain(first(V1_candidates)) + x = gens(OO(V1)) + lift_x = [preimage(pullback(i1[V1]), f) for f in x] + pb_x = pullback(i2[V2]).(lift_x) + pb_x = pullback(j1[U]).(pb_x) + morphism_dict[U] = ClosedEmbedding(SpecMor(U, V1, pb_x, check=false), pb_I2(V1), check=false) + end + j2_cov = CoveringMorphism(default_covering(Z), domain(i1_cov), morphism_dict, check=false) + j2 = Oscar.CoveredClosedEmbedding(Z, X1, j2_cov) + return j1, j2 +end diff --git a/src/AlgebraicGeometry/Schemes/CoveredSchemes/Morphisms/Methods.jl b/src/AlgebraicGeometry/Schemes/CoveredSchemes/Morphisms/Methods.jl index a905af3dedb6..6639e88f4096 100644 --- a/src/AlgebraicGeometry/Schemes/CoveredSchemes/Morphisms/Methods.jl +++ b/src/AlgebraicGeometry/Schemes/CoveredSchemes/Morphisms/Methods.jl @@ -158,3 +158,4 @@ function Base.show(io::IO, ::MIME"text/plain", f::AbsCoveredSchemeMorphism) Oscar._show_semi_compact(io, covering_morphism(f)) end end + diff --git a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Morphisms/Attributes.jl b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Morphisms/Attributes.jl index 8a5c71d75c69..5bddd55bee8e 100644 --- a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Morphisms/Attributes.jl +++ b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Morphisms/Attributes.jl @@ -1,5 +1,14 @@ +### generic getters +domain(f::AbsProjectiveSchemeMorphism) = domain(underlying_morphism(f)) +codomain(f::AbsProjectiveSchemeMorphism) = codomain(underlying_morphism(f)) +pullback(f::AbsProjectiveSchemeMorphism) = pullback(underlying_morphism(f)) +base_ring_morphism(f::AbsProjectiveSchemeMorphism) = base_ring_morphism(underlying_morphism(f)) +base_map(f::AbsProjectiveSchemeMorphism) = base_map(underlying_morphism(f)) +map_on_affine_cones(f::AbsProjectiveSchemeMorphism) = map_on_affine_cones(underlying_morphism(f)) -### getters +underlying_morphism(f::AbsProjectiveSchemeMorphism) = error("no underlying morphism for morphisms of type $(typeof(f))") + +### getters for the minimal concrete type domain(phi::ProjectiveSchemeMor) = phi.domain codomain(phi::ProjectiveSchemeMor) = phi.codomain @doc raw""" @@ -158,3 +167,11 @@ function map_on_affine_cones(phi::ProjectiveSchemeMor{<:AbsProjectiveScheme{<:Sp return phi.map_on_affine_cones::SpecOpenMor end + +######################################################################## +# Special implementations for closed embeddings +######################################################################## + +underlying_morphism(f::ProjectiveClosedEmbedding) = f.underlying_morphism +image_ideal(f::ProjectiveClosedEmbedding) = f.ideal_of_image + diff --git a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Morphisms/Constructors.jl b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Morphisms/Constructors.jl index 81c731a65af6..8fbb1d946d02 100644 --- a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Morphisms/Constructors.jl +++ b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Morphisms/Constructors.jl @@ -44,7 +44,7 @@ function ProjectiveSchemeMor( return ProjectiveSchemeMor(X, Y, hom(P, Q, a, check=false)) end -function compose(f::ProjectiveSchemeMor, g::ProjectiveSchemeMor) +function compose(f::AbsProjectiveSchemeMorphism, g::AbsProjectiveSchemeMorphism) return ProjectiveSchemeMor(domain(f), codomain(g), compose(pullback(g), pullback(f))) end @@ -149,3 +149,44 @@ identity_map(P::AbsProjectiveScheme) = ProjectiveSchemeMor(P, P, check=false ) +function sub(P::AbsProjectiveScheme, I::Ideal) + @req base_ring(I) === homogeneous_coordinate_ring(P) "ideal must be defined in the homogeneous coordinate ring of the scheme" + inc = ProjectiveClosedEmbedding(P, I) + set_attribute!(domain(inc), :ambient_space, ambient_space(P)) + return domain(inc), inc +end + +function sub(P::AbsProjectiveScheme, f::RingElem) + I = ideal(homogeneous_coordinate_ring(P), f) + return sub(P, I) +end + +function sub(P::AbsProjectiveScheme, f::Vector{<:RingElem}) + I = ideal(homogeneous_coordinate_ring(P), f) + return sub(P, I) +end + +function compose(f::ProjectiveClosedEmbedding, g::ProjectiveClosedEmbedding) + X = domain(f) + Y = codomain(f) + Y === domain(g) || error("domain and codomain not compatible") + Z = codomain(g) + pb = compose(pullback(g), pullback(f)) + Ig = image_ideal(g) + SY = homogeneous_coordinate_ring(Y) + SZ = homogeneous_coordinate_ring(Z) + If = image_ideal(f) + push_If = ideal(SZ, [preimage(pullback(g), x) for x in gens(If)]) + J = push_If + Ig + return ProjectiveClosedEmbedding(compose(underlying_morphism(f), underlying_morphism(g)), J, check=false) +end + +function ambient_embedding(X::AbsProjectiveScheme) + IP = ambient_space(X) + S = homogeneous_coordinate_ring(IP) + T = homogeneous_coordinate_ring(X) + I = defining_ideal(X) + pb = hom(S, T, gens(T)) + inc_sub = ProjectiveSchemeMor(X, IP, pb, check=false) + return ProjectiveClosedEmbedding(inc_sub, I, check=false) +end diff --git a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Morphisms/Methods.jl b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Morphisms/Methods.jl index 34d34d2f33c5..e9f50bde7561 100644 --- a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Morphisms/Methods.jl +++ b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Morphisms/Methods.jl @@ -1,5 +1,5 @@ -function ==(f::ProjectiveSchemeMor, g::ProjectiveSchemeMor) +function ==(f::AbsProjectiveSchemeMorphism, g::AbsProjectiveSchemeMorphism) domain(f) === domain(g) || return false codomain(f) === codomain(g) || return false for s in gens(homogeneous_coordinate_ring(codomain(f))) @@ -8,15 +8,15 @@ function ==(f::ProjectiveSchemeMor, g::ProjectiveSchemeMor) return true end -function ==(f::ProjectiveSchemeMor{<:AbsProjectiveScheme{<:Union{<:MPolyRing, <:MPolyQuoRing, <:MPolyLocRing, <:MPolyQuoLocRing}}}, - g::ProjectiveSchemeMor{<:AbsProjectiveScheme{<:Union{<:MPolyRing, <:MPolyQuoRing, <:MPolyLocRing, <:MPolyQuoLocRing}}}) +function ==(f::AbsProjectiveSchemeMorphism{<:AbsProjectiveScheme{<:Union{<:MPolyRing, <:MPolyQuoRing, <:MPolyLocRing, <:MPolyQuoLocRing}}}, + g::AbsProjectiveSchemeMorphism{<:AbsProjectiveScheme{<:Union{<:MPolyRing, <:MPolyQuoRing, <:MPolyLocRing, <:MPolyQuoLocRing}}}) domain(f) === domain(g) || return false codomain(f) === codomain(g) || return false return map_on_affine_cones(f) == map_on_affine_cones(g) end @doc raw""" - covered_scheme_morphism(f::ProjectiveSchemeMor) + covered_scheme_morphism(f::AbsProjectiveSchemeMorphism) Given a morphism of `ProjectiveScheme`s ``f : X → Y``, construct and return the same morphism as a `CoveredSchemeMorphism` of the `covered_scheme`s @@ -51,7 +51,7 @@ with default covering 3: [(x//z), (y//z)] ``` """ -@attr function covered_scheme_morphism(f::ProjectiveSchemeMor) +@attr function covered_scheme_morphism(f::AbsProjectiveSchemeMorphism) PX = domain(f) PY = codomain(f) SX = ambient_coordinate_ring(PX) @@ -90,13 +90,38 @@ with default covering return ff end +@attr CoveredClosedEmbedding function covered_scheme_morphism(f::ProjectiveClosedEmbedding) + PX = domain(f) + PY = codomain(f) + SX = homogeneous_coordinate_ring(PX) + SY = homogeneous_coordinate_ring(PY) + pbf = pullback(f) + + X = covered_scheme(PX) + Y = covered_scheme(PY) + + mor_dict = IdDict{AbsSpec, ClosedEmbedding}() + U = affine_charts(X) + # TODO: The code below does not run when we have empty affine charts. Adjust accordingly when cleaning up! + II = IdealSheaf(PY, image_ideal(f)) + for i in 1:ngens(SX) + U_i = U[i] + V_i = affine_charts(Y)[i] + mor_dict[U_i] = ClosedEmbedding(SpecMor(U_i, V_i, gens(OO(U_i)), check=false), II(V_i)) + end + f_cov = CoveringMorphism(default_covering(X), default_covering(Y), mor_dict, check=false) + + result = CoveredClosedEmbedding(X, Y, f_cov, check=false) + return result +end + ############################################################################### # # Printing # ############################################################################### -function Base.show(io::IO, f::ProjectiveSchemeMor) +function Base.show(io::IO, f::AbsProjectiveSchemeMorphism) if get(io, :supercompact, false) print(io, "Morphism") else @@ -105,7 +130,7 @@ function Base.show(io::IO, f::ProjectiveSchemeMor) end end -function Base.show(io::IO, ::MIME"text/plain", f::ProjectiveSchemeMor) +function Base.show(io::IO, ::MIME"text/plain", f::AbsProjectiveSchemeMorphism) io = pretty(io) X = domain(f) Y = codomain(f) @@ -130,7 +155,7 @@ function Base.show(io::IO, ::MIME"text/plain", f::ProjectiveSchemeMor) end end -function _show_semi_compact(io::IO, f::ProjectiveSchemeMor) +function _show_semi_compact(io::IO, f::AbsProjectiveSchemeMorphism) io = pretty(io) print(io, "Morphism of projective schemes") if has_attribute(f, :covered_scheme_morphism) diff --git a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Morphisms/Types.jl b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Morphisms/Types.jl index 8400c0c4c1af..9dec25c8f7d4 100644 --- a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Morphisms/Types.jl +++ b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Morphisms/Types.jl @@ -1,3 +1,18 @@ +######################################################################## +# Abstract type for morphisms of projective schemes for which the +# generic interface is defined. +######################################################################## +abstract type AbsProjectiveSchemeMorphism{ + DomainType, + CodomainType, + SelfType, # The concrete type itself as required by the generic `Map` implementation + BaseMorType + } <: SchemeMor{DomainType, CodomainType, + SelfType, + BaseMorType + } +end + ######################################################################## # Morphisms of projective schemes # ######################################################################## @@ -28,7 +43,7 @@ space over the same ring with the identity on the base. CodomainType<:AbsProjectiveScheme, PullbackType<:Map, BaseMorType - } <: SchemeMor{DomainType, CodomainType, + } <: AbsProjectiveSchemeMorphism{DomainType, CodomainType, ProjectiveSchemeMor, BaseMorType } @@ -106,3 +121,47 @@ space over the same ring with the identity on the base. end end +@attributes mutable struct ProjectiveClosedEmbedding{ + DomainType<:AbsProjectiveScheme, + CodomainType<:AbsProjectiveScheme, + PullbackType<:Map, + BaseMorType, + IdealType<:Ideal + } <: AbsProjectiveSchemeMorphism{DomainType, CodomainType, + ProjectiveClosedEmbedding, + BaseMorType + } + underlying_morphism::ProjectiveSchemeMor{DomainType, CodomainType, PullbackType, Nothing} + ideal_of_image::IdealType + + function ProjectiveClosedEmbedding( + P::DomainType, + I::IdealType, + check::Bool=true + ) where {DomainType<:AbsProjectiveScheme, IdealType<:Ideal} + S = homogeneous_coordinate_ring(P) + @req base_ring(I) === S "ideal must be defined in the homogeneous coordinate ring of the scheme" + T, pr = quo(S, I) + Q = ProjectiveScheme(T) + f = ProjectiveSchemeMor(Q, P, pr, check=false) + return new{typeof(Q), DomainType, typeof(pr), Nothing, IdealType}(f, I) + end + + function ProjectiveClosedEmbedding( + f::ProjectiveSchemeMor, + I::Ideal; + check::Bool=true + ) + Y = codomain(f) + SY = homogeneous_coordinate_ring(Y) + ambient_coordinate_ring(Y) === ambient_coordinate_ring(domain(f)) || error("ambient coordinate rings are not compatible") + base_ring(I) === SY || error("ideal does not belong to the correct ring") + @check begin + pbf = pullback(f) + kernel(pbf) == I || error("ideal does not coincide with the kernel of the pullback") + end + return new{typeof(domain(f)), typeof(Y), typeof(pullback(f)), Nothing, typeof(I)}(f, I) + end +end + + diff --git a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Constructors.jl b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Constructors.jl index bf1f519912c3..9d86861292d3 100644 --- a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Constructors.jl +++ b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Constructors.jl @@ -22,6 +22,7 @@ function subscheme(P::AbsProjectiveScheme, f::RingElem) if isdefined(P, :Y) set_base_scheme!(result, base_scheme(P)) end + set_attribute!(result, :ambient_space, ambient_space(P)) return result end @@ -39,6 +40,7 @@ function subscheme( if isdefined(P, :Y) set_base_scheme!(result, base_scheme(P)) end + set_attribute!(result, :ambient_space, ambient_space(P)) return result end @@ -52,6 +54,7 @@ function subscheme(P::AbsProjectiveScheme, if isdefined(P, :Y) set_base_scheme!(result, base_scheme(P)) end + set_attribute!(result, :ambient_space, ambient_space(P)) return result end diff --git a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Methods.jl b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Methods.jl index 40fd3ea3acdc..b282d61d8be3 100644 --- a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Methods.jl +++ b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Methods.jl @@ -399,3 +399,35 @@ function issubset(X::AbsProjectiveScheme, Y::AbsProjectiveScheme) IYsat = saturation(IX, irrelevant_ideal) return issubset(IYsat, IXsat) end + +function Base.intersect(X::AbsProjectiveScheme, Y::AbsProjectiveScheme) + return intersect([X, Y]) +end + +function Base.intersect(comp::Vector{<:AbsProjectiveScheme}) + @assert length(comp) > 0 "list of schemes must not be empty" + IP = ambient_space(first(comp)) + @assert all(x->ambient_space(x)===IP, comp[2:end]) "schemes must have the same ambient space" + S = homogeneous_coordinate_ring(IP) + I = sum([defining_ideal(x) for x in comp]) + result = subscheme(IP, I) + set_attribute!(result, :ambient_space, IP) + return result +end + +function Base.union(X::AbsProjectiveScheme, Y::AbsProjectiveScheme) + return union([X, Y]) +end + +function Base.union(comp::Vector{<:AbsProjectiveScheme}) + @assert length(comp) > 0 "list of schemes must not be empty" + IP = ambient_space(first(comp)) + @assert all(x->ambient_space(x)===IP, comp[2:end]) "schemes must have the same ambient space" + S = homogeneous_coordinate_ring(IP) + I = intersect([defining_ideal(x) for x in comp]) + result = subscheme(IP, I) + set_attribute!(result, :ambient_space, IP) + return result +end + + diff --git a/test/AlgebraicGeometry/Schemes/ProjectiveSchemes.jl b/test/AlgebraicGeometry/Schemes/ProjectiveSchemes.jl index 493a20baf496..9e2d05374567 100644 --- a/test/AlgebraicGeometry/Schemes/ProjectiveSchemes.jl +++ b/test/AlgebraicGeometry/Schemes/ProjectiveSchemes.jl @@ -312,3 +312,36 @@ end @test issubset(X1, P2) @test issubset(X1, X2) end + +@testset "closed embeddings" begin + IP2 = projective_space(QQ, 2) + S = homogeneous_coordinate_ring(IP2) + (x, y, z) = gens(S) + I = ideal(S, [x^2 + y^2 + z^2]) + X, inc = sub(IP2, I) + X, inc = sub(IP2, gens(I)) + + J = ideal(S, [x+y+z]) + X2, inc2 = sub(IP2, J) + inc_cov = covered_scheme_morphism(inc) + inc2_cov = covered_scheme_morphism(inc2) + j1, j2 = fiber_product(inc_cov, inc2_cov) + @test pushforward(inc_cov)(image_ideal(j2)) == pushforward(inc2_cov)(image_ideal(j1)) + + @test X === domain(inc) + @test IP2 === codomain(inc) + T = homogeneous_coordinate_ring(X) + Y, inc_Y = sub(X, T[1]*T[2] - T[3]^2) + @test domain(inc_Y) === Y + @test codomain(inc_Y) === X + @test image_ideal(inc_Y) == ideal(T, T[1]*T[2] - T[3]^2) + map_on_affine_cones(inc_Y) + inc_comp = compose(inc_Y, inc) + @test inc_comp isa Oscar.ProjectiveClosedEmbedding + phi = hom(homogeneous_coordinate_ring(codomain(inc_comp)), + homogeneous_coordinate_ring(domain(inc_comp)), + pullback(inc_comp).(gens(homogeneous_coordinate_ring(codomain(inc_comp)))) + ) + K = kernel(phi) + @test K == I + ideal(S, S[1]*S[2] - S[3]^2) +end