From 3b7c695037bc5db1aa02f26e329f554c1698ab24 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Sat, 5 Aug 2023 18:32:31 +0200 Subject: [PATCH 01/13] affine rational points --- .../RationalPoint/AffineRationalPoint.jl | 169 ++++++++++++++++++ .../Schemes/AffineRationalPoint.jl | 32 ++++ 2 files changed, 201 insertions(+) create mode 100644 src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl create mode 100644 test/AlgebraicGeometry/Schemes/AffineRationalPoint.jl diff --git a/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl b/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl new file mode 100644 index 000000000000..23cb6151d1d1 --- /dev/null +++ b/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl @@ -0,0 +1,169 @@ +@doc raw""" + AffineRationalPoint{CoeffType<:RingElem, ParentType<:AbsSpec} + +A $k$-rational point on an affine scheme ``X`` called its parent. + +# Examples +```jldoctest +julia> A2 = affine_space(GF(2), [:x, :y]); +Rational point + of Affine 2-space over GF(2) with coordinates [x, y] + with coordinates (1, 0) + +julia> A2([1, 0]) + +julia> (x, y) = coordinates(A2); + +julia> X = algebraic_set(x*y); + +julia> X([1,0]) +Rational point + of V(x*y) + with coordinates (1, 0) + +``` +""" +struct AffineRationalPoint{S<:RingElem, T<:AbsSpec} <: AbsAffineRationalPoint{S, T} + # not mutable since this should be efficient + coordinates::Vector{S} + parent::T + function AffineRationalPoint(parent::T, coordinates::Vector{S}; check::Bool=true) where {S <: RingElem, T<:AbsSpec} + r = new{S, T}(coordinates, parent) + @check begin + n = dim(ambient_space(parent)) + k = base_ring(parent) + n == length(coordinates) || error("$(coordinates) must have length $(n)") + _in(r, parent)|| error("$(coordinates) does not lie in $(parent)") + end + return r + end +end + +@doc raw""" + parent(p::AffineRationalPoint) -> AbsSpec + +Return the parent ``X`` of the rational point ``p \in X``. +""" +parent(p::AffineRationalPoint) = p.parent + +@doc raw""" + coordinates(p::AffineRationalPoint{S,T}) -> Vector{S} + +Return the coordinates of the rational point `p`. +""" +coordinates(p::AffineRationalPoint) = p.coordinates + +function (X::AbsSpec)(coordinates::Vector; check::Bool=true) + k = base_ring(X) + coordinates = k.(coordinates) + return AffineRationalPoint(X, coordinates, check=check) +end + +function Base.show(io::IO, ::MIME"text/plain", P::AbsAffineRationalPoint) + io = pretty(io) + println(io, "Rational point") + print(io, Indent()) + println(io, "of ", parent(P)) + print(io, "with coordinates (") + join(io, coordinates(P), ", ") + print(io, ")", Dedent()) +end + +function Base.show(io::IO, P::AbsAffineRationalPoint) + print(io,"(") + join(io, coordinates(P), ", ") + print(io,")") +end + +function ==(P::AbsAffineRationalPoint{S,T}, Q::AbsAffineRationalPoint{S,U}) where {S,T,U} + ambient_space(parent(P)) == ambient_space(parent(Q)) || return false + return coordinates(P) == coordinates(Q) +end + + +function Base.hash(P::AbsAffineRationalPoint, h::UInt) + return xor(hash(coordinates(P), h), hash(parent(P), h)) +end + +base_ring(P::AbsAffineRationalPoint) = base_ring(parent(P)) +coefficient_ring(P::AbsAffineRationalPoint) = base_ring(parent(P)) +coordinate(P::AbsAffineRationalPoint, i::Int) = coordinates(P)[i] +getindex(P::AbsAffineRationalPoint, i::Int) = coordinate(P, i) + +@doc raw""" + ideal(P::AbsAffineRationalPoint) + +Return the maximal ideal associated to `P` in the coordinate ring of its parent. +""" +function ideal(P::AbsAffineRationalPoint) + R = ambient_coordinate_ring(parent(P)) + V = ambient_coordinates(parent(P)) + return ideal(R, [V[i] - coordinate(P, i) for i in 1:length(V)]) +end + +function _in(P::AbsAffineRationalPoint, X::AbsSpec{<:Any,<:MPolyRing}) + # X is affine space + return ambient_space(parent(P)) == X +end + +function _in(P::AbsAffineRationalPoint, X::AbsSpec{<:Any,<:MPolyQuoRing}) + ambient_space(parent(P)) == ambient_space(X) || return false + c = coordinates(P) + for f in gens(ambient_closure_ideal(X)) + iszero(evaluate(f, c)) || return false + end + return true +end + +function _in(P::AbsAffineRationalPoint, X::AbsAffineAlgebraicSet{<:Any,<:MPolyQuoRing}) + # we can do this without computing the vanishing ideal of X + ambient_space(parent(P)) == ambient_space(X) || return false + c = coordinates(P) + for f in gens(fat_ideal(X)) + iszero(evaluate(f, c)) || return false + end + return true +end + +function _in(P::AbsAffineRationalPoint, X::AbsSpec) + # slow fallback for affine opens + # this should be improved + return issubset(affine_scheme(P), X) +end + +function Base.in(P::AbsAffineRationalPoint, X::AbsAffineAlgebraicSet) + parent(P) === X && return true + return _in(P, X) +end + +@doc raw""" + scheme(P::AbsAffineRationalPoint) -> AbsSpec + +Return the rational point ``P`` viewed as a reduced, affine subscheme +of its ambient affine space. +""" +function scheme(P::AbsAffineRationalPoint) + I = saturated_ideal(ideal(P)) + R = ambient_coordinate_ring(parent(P)) + return Spec(R, I) +end + +@doc raw""" + closed_embedding(P::AbsAffineRationalPoint) -> ClosedEmbedding + +Return the closed embedding of `P` into its parent scheme `X`. +""" +function closed_embedding(P::AbsAffineRationalPoint) + I = ideal(P) + X = parent(P) + return ClosedEmbedding(X, I) +end + +function (f::AbsSpecMor)(P::AbsAffineRationalPoint) + @req domain(f) == parent(P) "$(P) not in domain" + x = coordinates(codomain(f)) + g = pullback(f) + p = coordinates(P) + imgs = [evaluate(lift(g(y)),p) for y in x] + return AffineRationalPoint(codomain(f), imgs, check=false) +end diff --git a/test/AlgebraicGeometry/Schemes/AffineRationalPoint.jl b/test/AlgebraicGeometry/Schemes/AffineRationalPoint.jl new file mode 100644 index 000000000000..65d4854148e9 --- /dev/null +++ b/test/AlgebraicGeometry/Schemes/AffineRationalPoint.jl @@ -0,0 +1,32 @@ +@testset "affine rational points" begin + A2 = affine_space(GF(2), [:x, :y]); + (x, y) = coordinates(A2); + X = algebraic_set(x*y); + + pX = X([1,0]) + pA = A2([1,0]) + @test pX == pA + + A2a = affine_space(GF(2), [:x, :y]); + @test A2a([1,0]) == pA + + @test pX in X + @test pA in X + @test parent(pX)===X + + @test is_prime(ideal(pX)) + @test px[1] == 1 + @test px[2] == 0 + + @test ideal(pa) == ideal(px) + + # parametrize a cuspidal cubic rational curve + A2 = affine_space(QQ, [:x, :y]) + (x,y) = coordinates(A2) + At = affine_space(QQ, [:t]) + (t,) = coordinates(At) + C = algebraic_set(x^3-y^2) + f = SpecMor(At, C, [t^2,t^3]) + @test f(At([1,])) == C([1,1]) + @test f(At([2,])) == C([4,8]) +end From d623e9953d96050fd24d168dae27e251649ee2cf Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Sat, 5 Aug 2023 18:34:10 +0200 Subject: [PATCH 02/13] abstract types for rational points --- src/AlgebraicGeometry/Schemes/AbstractTypes.jl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/AlgebraicGeometry/Schemes/AbstractTypes.jl b/src/AlgebraicGeometry/Schemes/AbstractTypes.jl index b1655e2e8438..a2ac1c19bede 100644 --- a/src/AlgebraicGeometry/Schemes/AbstractTypes.jl +++ b/src/AlgebraicGeometry/Schemes/AbstractTypes.jl @@ -100,3 +100,13 @@ A geometrically integral scheme of dimension 2 of finite type over a field represented in terms of a covering. """ abstract type AbsCoveredSurface{BaseField<:Field} <: AbsCoveredVariety{BaseField} end + +################################################################################ +# +# Abstract types for rational points +# +################################################################################ +abstract type AbsAffineRationalPoint{RingElemType, ParentType} end + +abstract type AbsProjectiveRationalPoint{RingElemType, ParentType} end + From 94e30be405ba60e7fd9afa5fc48d5fea0e08c204 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Sat, 5 Aug 2023 18:36:40 +0200 Subject: [PATCH 03/13] include statements --- src/AlgebraicGeometry/AlgebraicGeometry.jl | 1 + test/AlgebraicGeometry/Schemes/runtests.jl | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/AlgebraicGeometry/AlgebraicGeometry.jl b/src/AlgebraicGeometry/AlgebraicGeometry.jl index 7ec2982fdf61..0089e1d8eb1f 100644 --- a/src/AlgebraicGeometry/AlgebraicGeometry.jl +++ b/src/AlgebraicGeometry/AlgebraicGeometry.jl @@ -3,3 +3,4 @@ include("ToricVarieties/JToric.jl") include("Surfaces/K3Auto.jl") include("Surfaces/SurfacesP4.jl") include("Miscellaneous/basics.jl") +include("RationalPoint/AffineRationalPoint.jl") diff --git a/test/AlgebraicGeometry/Schemes/runtests.jl b/test/AlgebraicGeometry/Schemes/runtests.jl index 2b079e73048d..b2b029f83ed0 100644 --- a/test/AlgebraicGeometry/Schemes/runtests.jl +++ b/test/AlgebraicGeometry/Schemes/runtests.jl @@ -26,4 +26,4 @@ include("VectorBundles.jl") include("WeilDivisor.jl") include("duValSing.jl") include("RationalMap.jl") - +include("AffineRationalPoint.jl") From c18b7d8dd98fda9dcd2017d76270d14e5f1397a8 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Sat, 5 Aug 2023 19:14:48 +0200 Subject: [PATCH 04/13] clarify docstring --- src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl b/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl index 23cb6151d1d1..f2df0bde38e8 100644 --- a/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl +++ b/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl @@ -1,8 +1,10 @@ @doc raw""" AffineRationalPoint{CoeffType<:RingElem, ParentType<:AbsSpec} -A $k$-rational point on an affine scheme ``X`` called its parent. - +A $k$-rational point ``P`` of an affine scheme ``X``. + +We refer to ``X`` as the parent of ``P``. + # Examples ```jldoctest julia> A2 = affine_space(GF(2), [:x, :y]); From ead4db4e9b0097e7d45bb69f5e253979ec63ce2e Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Mon, 7 Aug 2023 11:43:26 +0200 Subject: [PATCH 05/13] documentation, tangent space and du val singularities for points --- docs/doc.main | 3 + .../RationalPoints/RationalPoints.md | 29 +++++ .../Schemes/AffineSchemes.md | 4 +- .../RationalPoint/AffineRationalPoint.jl | 119 ++++++++++++++++-- .../AffineSchemes/Objects/Attributes.jl | 2 + src/exports.jl | 2 + .../Schemes/AffineRationalPoint.jl | 26 +++- 7 files changed, 168 insertions(+), 17 deletions(-) create mode 100644 docs/src/AlgebraicGeometry/RationalPoints/RationalPoints.md diff --git a/docs/doc.main b/docs/doc.main index 8e99b64c3918..21a005a6eea3 100644 --- a/docs/doc.main +++ b/docs/doc.main @@ -173,6 +173,9 @@ "AlgebraicGeometry/AlgebraicVarieties/AffineVariety.md", "AlgebraicGeometry/AlgebraicVarieties/ProjectiveVariety.md", ], + "Rational Points" => [ + "AlgebraicGeometry/RationalPoints/RationalPoints.md", + ], "Toric Varieties" => [ "AlgebraicGeometry/ToricVarieties/intro.md", "AlgebraicGeometry/ToricVarieties/NormalToricVarieties.md", diff --git a/docs/src/AlgebraicGeometry/RationalPoints/RationalPoints.md b/docs/src/AlgebraicGeometry/RationalPoints/RationalPoints.md new file mode 100644 index 000000000000..a2d2f10fdf03 --- /dev/null +++ b/docs/src/AlgebraicGeometry/RationalPoints/RationalPoints.md @@ -0,0 +1,29 @@ +```@meta +CurrentModule = Oscar +``` + +```@setup oscar +using Oscar +``` + +# Affine + +```@docs +AbsAffineRationalPoint +AffineRationalPoint +parent(p::AffineRationalPoint) +coordinates(p::AffineRationalPoint) +ideal(P::AbsAffineRationalPoint) +scheme(P::AbsAffineRationalPoint) +closed_embedding(P::AbsAffineRationalPoint) +is_smooth(P::AbsAffineRationalPoint) +tangent_space(P::AbsAffineRationalPoint{<:Field}) +``` + +Some experimental methods are available too. +Note that their interface is likely to change in the future. + +```@docs +is_du_val_singularity(P::AbsAffineRationalPoint{<:FieldElem}) +decide_du_val_singularity(P::AbsAffineRationalPoint{<:FieldElem,<:Any}) +``` diff --git a/docs/src/AlgebraicGeometry/Schemes/AffineSchemes.md b/docs/src/AlgebraicGeometry/Schemes/AffineSchemes.md index 817987e002bf..d9b691894353 100644 --- a/docs/src/AlgebraicGeometry/Schemes/AffineSchemes.md +++ b/docs/src/AlgebraicGeometry/Schemes/AffineSchemes.md @@ -105,7 +105,9 @@ issubset(X::AbsSpec, Y::AbsSpec) ## Methods - +```@docs +tangent_space(X::AbsSpec{<:Field}, P::AbsAffineRationalPoint) +``` ### Comparison Two schemes ``X`` and ``Y`` can be compared if their ambient affine spaces are equal. diff --git a/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl b/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl index f2df0bde38e8..12376332e9c8 100644 --- a/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl +++ b/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl @@ -1,24 +1,20 @@ @doc raw""" AffineRationalPoint{CoeffType<:RingElem, ParentType<:AbsSpec} -A $k$-rational point ``P`` of an affine scheme ``X``. +A rational point represented in terms of a vector of coordinates. -We refer to ``X`` as the parent of ``P``. +Two rational points are considered equal if their parents have the same ambient +space and their coordinates agree. # Examples ```jldoctest julia> A2 = affine_space(GF(2), [:x, :y]); -Rational point - of Affine 2-space over GF(2) with coordinates [x, y] - with coordinates (1, 0) - -julia> A2([1, 0]) julia> (x, y) = coordinates(A2); julia> X = algebraic_set(x*y); -julia> X([1,0]) +julia> X([1, 0]) Rational point of V(x*y) with coordinates (1, 0) @@ -34,6 +30,8 @@ struct AffineRationalPoint{S<:RingElem, T<:AbsSpec} <: AbsAffineRationalPoint{S, @check begin n = dim(ambient_space(parent)) k = base_ring(parent) + + all(Oscar.parent(i)===k for i in coordinates) || error("coordinates do not lie in the base ring") n == length(coordinates) || error("$(coordinates) must have length $(n)") _in(r, parent)|| error("$(coordinates) does not lie in $(parent)") end @@ -52,6 +50,8 @@ parent(p::AffineRationalPoint) = p.parent coordinates(p::AffineRationalPoint{S,T}) -> Vector{S} Return the coordinates of the rational point `p`. + +The coordinates are with respect to the ambient space of its parent. """ coordinates(p::AffineRationalPoint) = p.coordinates @@ -95,12 +95,17 @@ getindex(P::AbsAffineRationalPoint, i::Int) = coordinate(P, i) @doc raw""" ideal(P::AbsAffineRationalPoint) -Return the maximal ideal associated to `P` in the coordinate ring of its parent. +Return the maximal ideal associated to `P` in the ambient coordinate ring +of its parent. """ function ideal(P::AbsAffineRationalPoint) R = ambient_coordinate_ring(parent(P)) V = ambient_coordinates(parent(P)) - return ideal(R, [V[i] - coordinate(P, i) for i in 1:length(V)]) + I = ideal(R, [V[i] - coordinate(P, i) for i in 1:length(V)]) + set_attribute!(I, :is_prime=>true) + set_attribute!(I, :is_maximal=>true) + set_attribute!(I, :is_absolutely_prime=>true) + return I end function _in(P::AbsAffineRationalPoint, X::AbsSpec{<:Any,<:MPolyRing}) @@ -108,6 +113,10 @@ function _in(P::AbsAffineRationalPoint, X::AbsSpec{<:Any,<:MPolyRing}) return ambient_space(parent(P)) == X end +function evaluate(f::MPolyRingElem, P::AbsAffineRationalPoint) + return evaluate(f, coordinates(P)) +end + function _in(P::AbsAffineRationalPoint, X::AbsSpec{<:Any,<:MPolyQuoRing}) ambient_space(parent(P)) == ambient_space(X) || return false c = coordinates(P) @@ -130,14 +139,18 @@ end function _in(P::AbsAffineRationalPoint, X::AbsSpec) # slow fallback for affine opens # this should be improved - return issubset(affine_scheme(P), X) + return issubset(scheme(P), X) end -function Base.in(P::AbsAffineRationalPoint, X::AbsAffineAlgebraicSet) +function Base.in(P::AbsAffineRationalPoint, X::AbsSpec) parent(P) === X && return true return _in(P, X) end +function Base.in(P::AbsAffineRationalPoint, X::AbsCoveredScheme) + return any(any(P in U for U in C) for C in coverings(X)) +end + @doc raw""" scheme(P::AbsAffineRationalPoint) -> AbsSpec @@ -145,7 +158,7 @@ Return the rational point ``P`` viewed as a reduced, affine subscheme of its ambient affine space. """ function scheme(P::AbsAffineRationalPoint) - I = saturated_ideal(ideal(P)) + I = ideal(P) R = ambient_coordinate_ring(parent(P)) return Spec(R, I) end @@ -169,3 +182,83 @@ function (f::AbsSpecMor)(P::AbsAffineRationalPoint) imgs = [evaluate(lift(g(y)),p) for y in x] return AffineRationalPoint(codomain(f), imgs, check=false) end + +function MPolyComplementOfKPointIdeal(P::AbsAffineRationalPoint) + R = ambient_coordinate_ring(parent(P)) + return MPolyComplementOfKPointIdeal(R, coordinates(P)) +end + +function is_smooth_at(X::AbsSpec{<:Field}, P::AbsAffineRationalPoint) + @req P in X "not a point on X" + U = MPolyComplementOfKPointIdeal(P) + R = OO(parent(P)) + XU = Spec(localization(R, U)[1]) + return is_smooth(XU) +end + +@doc raw""" + is_smooth(P::AbsAffineRationalPoint) + +Return whether ``P`` is a smooth point of its parent ``X``. +""" +is_smooth(P::AbsAffineRationalPoint) = is_smooth_at(parent(P),P) + + +@doc raw""" + tangent_space(X::AbsSpec{<:Field}, P::AbsAffineRationalPoint) -> AlgebraicSet + +Return the Zariski tangent space of `X` at its rational point `P`. + +See also [`tangent_space(P::AbsAffineRationalPoint{<:Field})`](@ref) +""" +function tangent_space(X::AbsSpec{<:Field}, P::AbsAffineRationalPoint) + @req P in X "the point needs to lie on the algebraic set" + J = jacobi_matrix(gens(ambient_closure_ideal(X))) + v = coordinates(P) + JP = map_entries(x->evaluate(x, v), J) + V = ambient_coordinates(X) + R = ambient_coordinate_ring(X) + T = elem_type(R)[ sum([(V[i]-v[i])*JP[i,j] for i in 1:nrows(JP)], init=zero(R)) for j in 1:ncols(JP)] + return algebraic_set(ideal(R,T), is_radical=true, check=false) +end + +@doc raw""" + tangent_space(P::AbsAffineRationalPoint{<:FieldElem}) -> AlgebraicSet + +Return the Zariski tangent space of the parent of `P` at its point `P`. + +See also [`tangent_space(X::AbsSpec{<:Field}, P::AbsAffineRationalPoint)`](@ref) +""" +tangent_space(P::AbsAffineRationalPoint{<:FieldElem}) = tangent_space(parent(P), P) + +@doc raw""" + is_du_val_singularity(P::AbsAffineRationalPoint{<:Field}) + +Return if the parent of `P` has hat most a Du Val singularity at `P`. + +Note that this includes the case that ``P`` is a smooth point. +""" +is_du_val_singularity(P::AbsAffineRationalPoint{<:FieldElem}) = is_du_val_singularity(parent(P), ideal(P)) + +@doc raw""" + decide_du_val_singularity(P::AbsAffineRationalPoint{<:Field}) + +Return if the parent of `P` has a Du Val singularity at `P`. + +# Examples +```jldoctest +julia> A3 = affine_space(QQ, [:x, :y, :z]); + +julia> (x, y, z) = ambient_coordinates(A3); + +julia> X = subscheme(A3, ideal([x^2+y^2-z^2])); + +julia> Oscar.decide_du_val_singularity(X([0,0,0])) +(true, (:A, 1)) + +``` +""" +function decide_du_val_singularity(P::AbsAffineRationalPoint{<:FieldElem,<:Any}) + d = decide_du_val_singularity(parent(P), ideal(P)) + return d[1][1],d[1][3] +end diff --git a/src/AlgebraicGeometry/Schemes/AffineSchemes/Objects/Attributes.jl b/src/AlgebraicGeometry/Schemes/AffineSchemes/Objects/Attributes.jl index ce2544d3b2e7..12e7654bf298 100644 --- a/src/AlgebraicGeometry/Schemes/AffineSchemes/Objects/Attributes.jl +++ b/src/AlgebraicGeometry/Schemes/AffineSchemes/Objects/Attributes.jl @@ -384,6 +384,8 @@ julia> dim(Y) # one dimension comes from ZZ and two from x1 and x2 3 ``` """ +dim(X::AbsSpec) + @attr function dim(X::AbsSpec{<:Ring, <:MPolyQuoLocRing}) return dim(saturated_ideal(modulus(OO(X)))) end diff --git a/src/exports.jl b/src/exports.jl index 7f430f60f0cf..e4be554dd0b4 100644 --- a/src/exports.jl +++ b/src/exports.jl @@ -6,6 +6,7 @@ export @permutation_group export @tropical export ANTIC export AbsAffineAlgebraicSet +export AbsAffineRationalPoint export AbsAffineCurve export AbsAffineVariety export AbsCoveredCurve @@ -1300,6 +1301,7 @@ export symplectic_components export symplectic_group export syz export syzygy_generators +export tangent_space export tail export tensor_product export terms diff --git a/test/AlgebraicGeometry/Schemes/AffineRationalPoint.jl b/test/AlgebraicGeometry/Schemes/AffineRationalPoint.jl index 65d4854148e9..91a196bc3078 100644 --- a/test/AlgebraicGeometry/Schemes/AffineRationalPoint.jl +++ b/test/AlgebraicGeometry/Schemes/AffineRationalPoint.jl @@ -15,10 +15,10 @@ @test parent(pX)===X @test is_prime(ideal(pX)) - @test px[1] == 1 - @test px[2] == 0 + @test pX[1] == 1 + @test pX[2] == 0 - @test ideal(pa) == ideal(px) + @test ideal(pA) == ideal(pX) # parametrize a cuspidal cubic rational curve A2 = affine_space(QQ, [:x, :y]) @@ -29,4 +29,24 @@ f = SpecMor(At, C, [t^2,t^3]) @test f(At([1,])) == C([1,1]) @test f(At([2,])) == C([4,8]) + @test tangent_space(C,C([0,0])) == algebraic_set(0*x) + @test !is_smooth(C([0,0])) + D = algebraic_set(x^2-y) + @test is_smooth(D([0,0])) + @test tangent_space(D,D([0,0])) == algebraic_set(y) + + # disjoint union of a line and a point, smooth + E = algebraic_set(ideal([x*(y-1),y^2-y])) + @test is_smooth(E([0,0])) + @test is_smooth(E([0,1])) + + # union of two lines meeting in 0 + F = algebraic_set(ideal([x*y])) + @test !is_smooth(F([0,0])) + @test is_smooth(F([0,1])) + + P2cov = covered_scheme(projective_space(QQ,2)) + pt = sc[1][1]([1,0]) + @test pt in P2cov + end From 4e8dd4d52240f4a0cdf3befc803081ad7a903545 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Mon, 7 Aug 2023 11:45:12 +0200 Subject: [PATCH 06/13] docu for the AbsAffineRationalPoint --- src/AlgebraicGeometry/Schemes/AbstractTypes.jl | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/AlgebraicGeometry/Schemes/AbstractTypes.jl b/src/AlgebraicGeometry/Schemes/AbstractTypes.jl index a2ac1c19bede..35891644fe2d 100644 --- a/src/AlgebraicGeometry/Schemes/AbstractTypes.jl +++ b/src/AlgebraicGeometry/Schemes/AbstractTypes.jl @@ -106,6 +106,17 @@ abstract type AbsCoveredSurface{BaseField<:Field} <: AbsCoveredVariety{BaseField # Abstract types for rational points # ################################################################################ +@doc raw""" + AbsAffineRationalPoint{CoefficientType, ParentType} + +A rational point ``P`` of an affine scheme ``X``. +We refer to ``X`` as the parent of ``P``. + +Let ``X \subseteq \mathbb{A}^n_k`` be an algebraic set or more generally a subscheme +defined by the ideal ``I = (f_1, \dots f_r) \subseteq k[x_1,\dots x_n]``. +A rational point ``p`` of ``X`` is a tuple ``p = (p_1, \dots , p_n) \in k^n`` such that +``f_1(p) = \dots = f_n(p) = 0``. +""" abstract type AbsAffineRationalPoint{RingElemType, ParentType} end abstract type AbsProjectiveRationalPoint{RingElemType, ParentType} end From 6fef1f2939b4b8ac1e4ff5c9c28bacfff38cefbd Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Tue, 8 Aug 2023 12:30:18 +0200 Subject: [PATCH 07/13] fix test and docs --- docs/src/AlgebraicGeometry/RationalPoints/RationalPoints.md | 2 +- src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl | 5 +++-- test/AlgebraicGeometry/Schemes/AffineRationalPoint.jl | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/src/AlgebraicGeometry/RationalPoints/RationalPoints.md b/docs/src/AlgebraicGeometry/RationalPoints/RationalPoints.md index a2d2f10fdf03..92c778597118 100644 --- a/docs/src/AlgebraicGeometry/RationalPoints/RationalPoints.md +++ b/docs/src/AlgebraicGeometry/RationalPoints/RationalPoints.md @@ -17,7 +17,7 @@ ideal(P::AbsAffineRationalPoint) scheme(P::AbsAffineRationalPoint) closed_embedding(P::AbsAffineRationalPoint) is_smooth(P::AbsAffineRationalPoint) -tangent_space(P::AbsAffineRationalPoint{<:Field}) +tangent_space(P::AbsAffineRationalPoint{<:FieldElem}) ``` Some experimental methods are available too. diff --git a/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl b/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl index 12376332e9c8..4571f4b6a3d6 100644 --- a/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl +++ b/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl @@ -25,6 +25,7 @@ struct AffineRationalPoint{S<:RingElem, T<:AbsSpec} <: AbsAffineRationalPoint{S, # not mutable since this should be efficient coordinates::Vector{S} parent::T + function AffineRationalPoint(parent::T, coordinates::Vector{S}; check::Bool=true) where {S <: RingElem, T<:AbsSpec} r = new{S, T}(coordinates, parent) @check begin @@ -234,7 +235,7 @@ tangent_space(P::AbsAffineRationalPoint{<:FieldElem}) = tangent_space(parent(P), @doc raw""" is_du_val_singularity(P::AbsAffineRationalPoint{<:Field}) -Return if the parent of `P` has hat most a Du Val singularity at `P`. +Return whether the parent of `P` has hat most a Du Val singularity at `P`. Note that this includes the case that ``P`` is a smooth point. """ @@ -243,7 +244,7 @@ is_du_val_singularity(P::AbsAffineRationalPoint{<:FieldElem}) = is_du_val_singul @doc raw""" decide_du_val_singularity(P::AbsAffineRationalPoint{<:Field}) -Return if the parent of `P` has a Du Val singularity at `P`. +Return whether the parent of `P` has a Du Val singularity at `P`. # Examples ```jldoctest diff --git a/test/AlgebraicGeometry/Schemes/AffineRationalPoint.jl b/test/AlgebraicGeometry/Schemes/AffineRationalPoint.jl index 91a196bc3078..1a9e432e4868 100644 --- a/test/AlgebraicGeometry/Schemes/AffineRationalPoint.jl +++ b/test/AlgebraicGeometry/Schemes/AffineRationalPoint.jl @@ -46,7 +46,7 @@ @test is_smooth(F([0,1])) P2cov = covered_scheme(projective_space(QQ,2)) - pt = sc[1][1]([1,0]) + pt = P2cov[1][1]([1,0]) @test pt in P2cov end From 8f5731c46674720c3b98e749d945043d9ee8874d Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Wed, 9 Aug 2023 09:49:40 +0200 Subject: [PATCH 08/13] projective points and docu --- docs/doc.main | 3 +- .../{RationalPoints.md => Affine.md} | 0 .../RationalPoints/Projective.md | 20 ++ src/AlgebraicGeometry/AlgebraicGeometry.jl | 1 + .../RationalPoint/AffineRationalPoint.jl | 2 +- .../RationalPoint/ProjectiveRationalPoint.jl | 252 ++++++++++++++++++ .../Schemes/AbstractTypes.jl | 13 + .../ProjectiveSchemes/Objects/Attributes.jl | 9 + .../ProjectiveSchemes/Objects/Methods.jl | 26 ++ .../Schemes/ProjectiveSchemes.jl | 12 + test/AlgebraicGeometry/Schemes/runtests.jl | 1 + 11 files changed, 337 insertions(+), 2 deletions(-) rename docs/src/AlgebraicGeometry/RationalPoints/{RationalPoints.md => Affine.md} (100%) create mode 100644 docs/src/AlgebraicGeometry/RationalPoints/Projective.md create mode 100644 src/AlgebraicGeometry/RationalPoint/ProjectiveRationalPoint.jl diff --git a/docs/doc.main b/docs/doc.main index 21a005a6eea3..f171ecef7c3e 100644 --- a/docs/doc.main +++ b/docs/doc.main @@ -174,7 +174,8 @@ "AlgebraicGeometry/AlgebraicVarieties/ProjectiveVariety.md", ], "Rational Points" => [ - "AlgebraicGeometry/RationalPoints/RationalPoints.md", + "AlgebraicGeometry/RationalPoints/Affine.md", + "AlgebraicGeometry/RationalPoints/Projective.md", ], "Toric Varieties" => [ "AlgebraicGeometry/ToricVarieties/intro.md", diff --git a/docs/src/AlgebraicGeometry/RationalPoints/RationalPoints.md b/docs/src/AlgebraicGeometry/RationalPoints/Affine.md similarity index 100% rename from docs/src/AlgebraicGeometry/RationalPoints/RationalPoints.md rename to docs/src/AlgebraicGeometry/RationalPoints/Affine.md diff --git a/docs/src/AlgebraicGeometry/RationalPoints/Projective.md b/docs/src/AlgebraicGeometry/RationalPoints/Projective.md new file mode 100644 index 000000000000..a9a7f5aa8826 --- /dev/null +++ b/docs/src/AlgebraicGeometry/RationalPoints/Projective.md @@ -0,0 +1,20 @@ +```@meta +CurrentModule = Oscar +``` + +```@setup oscar +using Oscar +``` + +# Projective + +```@docs +AbsProjectiveRationalPoint +ProjectiveRationalPoint +parent(P::ProjectiveRationalPoint) +coordinates(P::ProjectiveRationalPoint) +ideal(P::ProjectiveRationalPoint) +scheme(P::ProjectiveRationalPoint) +normalize!(a::AbsProjectiveRationalPoint{<:FieldElem}) +normalize!(a::AbsProjectiveRationalPoint{ZZRingElem}) +``` diff --git a/src/AlgebraicGeometry/AlgebraicGeometry.jl b/src/AlgebraicGeometry/AlgebraicGeometry.jl index 0089e1d8eb1f..ac049ece3922 100644 --- a/src/AlgebraicGeometry/AlgebraicGeometry.jl +++ b/src/AlgebraicGeometry/AlgebraicGeometry.jl @@ -4,3 +4,4 @@ include("Surfaces/K3Auto.jl") include("Surfaces/SurfacesP4.jl") include("Miscellaneous/basics.jl") include("RationalPoint/AffineRationalPoint.jl") +include("RationalPoint/ProjectiveRationalPoint.jl") diff --git a/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl b/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl index 4571f4b6a3d6..f022c2f2245d 100644 --- a/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl +++ b/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl @@ -235,7 +235,7 @@ tangent_space(P::AbsAffineRationalPoint{<:FieldElem}) = tangent_space(parent(P), @doc raw""" is_du_val_singularity(P::AbsAffineRationalPoint{<:Field}) -Return whether the parent of `P` has hat most a Du Val singularity at `P`. +Return whether the parent of `P` has at most a Du Val singularity at `P`. Note that this includes the case that ``P`` is a smooth point. """ diff --git a/src/AlgebraicGeometry/RationalPoint/ProjectiveRationalPoint.jl b/src/AlgebraicGeometry/RationalPoint/ProjectiveRationalPoint.jl new file mode 100644 index 000000000000..e746350180d0 --- /dev/null +++ b/src/AlgebraicGeometry/RationalPoint/ProjectiveRationalPoint.jl @@ -0,0 +1,252 @@ +@doc raw""" + ProjectiveRationalPoint{CoeffType<:RingElem, ParentType<:AbsProjectiveScheme} + +Type for rational points in projective varieties. + +# Examples +```jldoctest +julia> P2 = projective_space(QQ, 2) + +julia> P2([4, 0 , 2//3]) +``` +""" +struct ProjectiveRationalPoint{S<:RingElem, T<:AbsProjectiveScheme} <: AbsProjectiveRationalPoint{S, T} + # not mutable since this should be efficient + coordinates::Vector{S} + parent::T + + function ProjectiveRationalPoint(parent::T, coordinates::Vector{S}; check::Bool=true) where {S <: RingElem, T<:AbsProjectiveScheme} + r = new{S, T}(coordinates, parent) + @check begin + n = relative_ambient_dimension(parent) + 1 + k = base_ring(parent) + all(Oscar.parent(i)===k for i in coordinates) || error("coordinates do not lie in the base ring") + n == length(coordinates) || error("$(coordinates) must have length $(n)") + _is_projective(coordinates) || error("not a point in projective space") + _in(r, parent)|| error("$(coordinates) does not lie in $(parent)") + end + return r + end +end + +@doc raw""" + parent(p::AbsProjectiveRationalPoint) -> AbsProjectiveScheme + +Return the parent ``X`` of the rational point ``p \in X``. +""" +parent(p::AbsProjectiveRationalPoint) + +@doc raw""" + coordinates(p::AbsProjectiveRationalPoint{S,T}) -> Vector{S} + +Return the homogeneous coordinates of the rational point `p`. +""" +coordinates(p::ProjectiveRationalPoint) + +################################################################################ +# +# AbsProjectivePoint Interface +# +################################################################################ + +parent(p::ProjectiveRationalPoint) = p.parent +coordinates(p::AbsProjectiveRationalPoint) = p.coordinates + +################################################################################ + +homogeneous_coordinates(p::AbsProjectiveRationalPoint) = coordinates(p) + +function (X::AbsProjectiveScheme)(coordinates::Vector; check::Bool=true) + k = base_ring(X) + coordinates = k.(coordinates) + return ProjectiveRationalPoint(X, coordinates, check=check) +end + +function Base.show(io::IO, ::MIME"text/plain", P::AbsProjectiveRationalPoint) + io = pretty(io) + println(io, "Projective rational point") + print(io, Indent()) + println(io, "of ", parent(P)) + print(io, "with coordinates (") + join(io, coordinates(P), " : ") + print(io, ")", Dedent()) +end + +function Base.show(io::IO, P::AbsProjectiveRationalPoint) + print(io,"(") + join(io, coordinates(P), " : ") + print(io,")") +end + +base_ring(P::AbsProjectiveRationalPoint) = base_ring(parent(P)) +coefficient_ring(P::AbsProjectiveRationalPoint) = base_ring(parent(P)) +coordinate(P::AbsProjectiveRationalPoint, i::Int) = coordinates(P)[i] +Base.getindex(P::AbsProjectiveRationalPoint, i::Int) = coordinate(P, i) +Base.setindex!(a::AbsProjectiveRationalPoint, v, i::Int) = coordinates(a)[i] = v + +@doc raw""" + ideal(P::AbsProjectiveRationalPoint) + +Return the homogeneous ideal associated to `P` +in the homogeneous coordinate ring of its parent. +""" +function ideal(P::AbsProjectiveRationalPoint) + R = ambient_coordinate_ring(parent(P)) + V = gens(R) + w = weights(parent(P)) + n = length(V) + m = elem_type(R)[] + # first non-zero coordinate + i = 1 + while iszero(P[i]) + i = i+1 + end + for j in i+1:n + push!(m, P[i]^w[j]*V[j]^w[i] - P[j]^w[i]*V[i]^w[j]) + end + return ideal(R, m) +end + +function _in(P::AbsProjectiveRationalPoint, X::AbsProjectiveScheme{<:Any,<:MPolyDecRing{<:Any,<:MPolyRing}}) + # X is projective space + return ambient_space(parent(P)) == X +end + +function _in(P::AbsProjectiveRationalPoint, X::AbsProjectiveScheme{<:Any,<:MPolyQuoRing{<:MPolyDecRingElem}}) + ambient_space(parent(P)) == ambient_space(X) || return false + c = coordinates(P) + for f in gens(defining_ideal(X)) + iszero(evaluate(f, c)) || return false + end + return true +end + +# We can do this without computing the vanishing ideal of X +function _in(P::AbsProjectiveRationalPoint, X::AbsProjectiveAlgebraicSet{<:Any,<:MPolyQuoRing{<:MPolyDecRingElem}}) + ambient_space(parent(P)) == ambient_space(X) || return false + c = coordinates(P) + for f in gens(fat_ideal(X)) + iszero(evaluate(f, c)) || return false + end + return true +end + +function Base.in(P::AbsProjectiveRationalPoint, X::AbsProjectiveScheme) + parent(P) === X && return true + return _in(P, X) +end + +@doc raw""" + scheme(P::AbsProjectiveRationalPoint) -> AbsProjectiveScheme + +Return the rational point ``P`` viewed as a reduced, projective subscheme +of its ambient projective space. +""" +function scheme(P::AbsProjectiveRationalPoint) + I = ideal(P) + R = ambient_coordinate_ring(parent(P)) + return ProjectiveScheme(R, I) +end + +function (f::ProjectiveSchemeMor)(P::AbsProjectiveRationalPoint) + @req domain(f) == parent(P) "$(P) not in domain" + x = homogeneous_coordinates(codomain(f)) + g = pullback(f) + p = coordinates(P) + imgs = [evaluate(lift(g(y)),p) for y in x] + return ProjectiveRationalPoint(codomain(f), imgs, check=false) +end + +function is_smooth_at(X::AbsProjectiveScheme{<:Field}, P::AbsProjectiveRationalPoint) + @req P in X "not a point on X" + error("not implemented") +end + +is_smooth(P::AbsProjectiveRationalPoint) = is_smooth_at(parent(P),P) + +function _is_projective(a::Vector{T}) where {T <: AbstractAlgebra.FieldElem} + return !all(iszero, a) +end + +function _is_projective(a::Vector{T}) where {T} + error("not implemented") +end + +function _is_projective(a::Vector{ZZRingElem}) + all(iszero, a) && return false + return isone(gcd(a)) +end + +Nemo.parent_type(::AbsProjectiveRationalPoint{S,T}) where {S,T} = T + +function ==(a::AbsProjectiveRationalPoint{S, T}, b::AbsProjectiveRationalPoint{S, U}) where {S<:Union{FieldElem,ZZRingElem},T, U} + ambient_space(parent(a)) == ambient_space(parent(b)) || return false + n = length(coordinates(a)) + i = 1 + w = weights(parent(a)) + while iszero(a[i]) + iszero(b[i]) || return false + i += 1 + end + iszero(b[i]) && return false + ca = a[i] + cb = b[i] + i += 1 + while i <= n + ca^w[i] * b[i] == cb^w[i] * a[i] || return false + i += 1 + end + return true +end + +@doc raw""" + normalize!(a::AbsProjectiveRationalPoint{<:FieldElem}) + +Normalize `a` such that its first non-zero coordinate is one. +""" +function normalize!(a::AbsProjectiveRationalPoint{<:FieldElem}) + i = 1 + while iszero(a[i]) + i += 1 + end + ca = inv(a[i]) + a[i] = one(base_ring(parent(a))) + w = weights(parent(a)) + any(x->!isone(x), w) && error("cannot normalize with weights") + i += 1 + while i <= l + a[i] = ca^w[i]*a[i] + i += 1 + end + return a +end + +@doc raw""" + normalize!(a::AbsProjectiveRationalPoint{ZZRingElem}) + +Normalize `a` such that its first non-zero coordinate is positive. +""" +function normalize!(a::AbsProjectiveRationalPoint{ZZRingElem}) + #projective elements are primitive, ie. the gcd is 1 + #they can be changed only by units, so we can normalize... + i = 1 + while iszero(a[i]) + i += 1 + end + w = weights(parent(a)) + any(x->!isone(x), w) && error("cannot normalize with weights") + ca = sign(a[i]) + while i <= dim(parent(a)) + a[i] = ca*a[i] #TODO: weights + i += 1 + end + return a +end + +function Base.hash(a::AbsProjectiveRationalPoint, u::UInt=UInt(123432)) + if isweighted(parent(a)) + return u + end + normalize!(a) + return hash(a.v, u) +end diff --git a/src/AlgebraicGeometry/Schemes/AbstractTypes.jl b/src/AlgebraicGeometry/Schemes/AbstractTypes.jl index 35891644fe2d..10525aa7971f 100644 --- a/src/AlgebraicGeometry/Schemes/AbstractTypes.jl +++ b/src/AlgebraicGeometry/Schemes/AbstractTypes.jl @@ -119,5 +119,18 @@ A rational point ``p`` of ``X`` is a tuple ``p = (p_1, \dots , p_n) \in k^n`` su """ abstract type AbsAffineRationalPoint{RingElemType, ParentType} end +@doc raw""" + AbsProjectiveRationalPoint + +A rational point ``P`` of a projective scheme ``X``. +We refer to ``X`` as the parent of ``P``. + +Let ``k`` be a field. A rational point is an element of ``\mathbb{P}^n(k) = k^{n+1} \setminus \{0\} / k^*`` where +two vectors ``v,w`` in ``k^{n+1} \setminus \{0\}`` are identified if ``v = \alpha w`` for a non-zero scalar ``\alpha \in k^*``. + +Let ``X \subseteq \mathbb{P}^n_k`` be an algebraic set or more generally a closed subscheme defined by the homogeneous ideal ``I = (f_1, \dots f_r)``. Then a rational point of ``X`` is ``p \in \mathbb{P}^n(k)`` such that ``f_1(p) = \dots = f_n(p) = 0``. + +This type includes points in weighted projective space. +""" abstract type AbsProjectiveRationalPoint{RingElemType, ParentType} end diff --git a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Attributes.jl b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Attributes.jl index 0ba71f288ca8..9f361348de7c 100644 --- a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Attributes.jl +++ b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Attributes.jl @@ -158,6 +158,15 @@ function homogeneous_coordinates(X::AbsProjectiveScheme) return gens(homogeneous_coordinate_ring(X)) end + +function weights(X::AbsProjectiveScheme) + S = homogeneous_coordinate_ring(ambient_space(X)) + A = grading_group(S) + elementary_divisors(A)==[0] || error("not ZZ graded") + return [degree(i)[1] for i in gens(S)] +end + + ############################################################################## # Converter to covered scheme ############################################################################## diff --git a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Methods.jl b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Methods.jl index ab319e516977..8ddd725fe9a2 100644 --- a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Methods.jl +++ b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Methods.jl @@ -372,4 +372,30 @@ function getindex(X::AbsProjectiveScheme, U::AbsSpec) return nothing, 0 end +# comparison of projective spaces +function ==(X::AbsProjectiveScheme{<:Any,<:MPolyDecRing}, Y::AbsProjectiveScheme{<:Any,<:MPolyDecRing}) + return homogeneous_coordinate_ring(X) === homogeneous_coordinate_ring(Y) +end + +# comparison of subschemes of projective space +function ==(X::AbsProjectiveScheme, Y::AbsProjectiveScheme) + ambient_space(X) == ambient_space(Y) || return false + IX = defining_ideal(X) + IY = defining_ideal(Y) + R = homogeneous_coordinate_ring(ambient_space(X)) + irrelevant_ideal = ideal(R,gens(R)) + IXsat = saturation(IX, irrelevant_ideal) + IYsat = saturation(IX, irrelevant_ideal) + return IXsat == IYsat +end +function issubset(X::AbsProjectiveScheme, Y::AbsProjectiveScheme) + ambient_space(X) == ambient_space(Y) || return false + IX = defining_ideal(X) + IY = defining_ideal(Y) + R = homogeneous_coordinate_ring(ambient_space(X)) + irrelevant_ideal = ideal(R,gens(R)) + IXsat = saturation(IX, irrelevant_ideal) + IYsat = saturation(IX, irrelevant_ideal) + return issubset(IYsat, IXsat) +end diff --git a/test/AlgebraicGeometry/Schemes/ProjectiveSchemes.jl b/test/AlgebraicGeometry/Schemes/ProjectiveSchemes.jl index b34afc4fe8a4..c984a4b5147d 100644 --- a/test/AlgebraicGeometry/Schemes/ProjectiveSchemes.jl +++ b/test/AlgebraicGeometry/Schemes/ProjectiveSchemes.jl @@ -300,3 +300,15 @@ end X = covered_scheme(P) @test all(U->(OO(U) isa MPolyRing), affine_charts(X)) end + +@test "equality of projective schemes" begin + P2 = projective_space(GF(17), 2) + (x0,x1,x2) = homogeneous_coordinates(P2) + R = homogeneous_coordinate_ring(P2) + X1 = subscheme(P2, ideal(R, [x0*x1])) + X2 = subscheme(P2, ideal(R, [x0^2*x1,x0*x1^2,x0*x1*x2])) + X3 = subscheme(P2, ideal(R,[x0])) + @test X1 == X2 + @test issubset(X1, P2) + @test issubset(X1, X2) +end diff --git a/test/AlgebraicGeometry/Schemes/runtests.jl b/test/AlgebraicGeometry/Schemes/runtests.jl index b2b029f83ed0..a029f0d58a8b 100644 --- a/test/AlgebraicGeometry/Schemes/runtests.jl +++ b/test/AlgebraicGeometry/Schemes/runtests.jl @@ -27,3 +27,4 @@ include("WeilDivisor.jl") include("duValSing.jl") include("RationalMap.jl") include("AffineRationalPoint.jl") +include("ProjectiveRationalPoint.jl") From 48336bc59f1a5186f5cde1490d4f77aaed19c5cc Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Wed, 9 Aug 2023 12:58:51 +0200 Subject: [PATCH 09/13] introduce RationalPointSets --- src/AlgebraicGeometry/AlgebraicGeometry.jl | 2 + .../RationalPoint/AffineRationalPoint.jl | 115 ++++++------------ .../RationalPoint/PointSet.jl | 39 ++++++ .../RationalPoint/ProjectiveRationalPoint.jl | 86 ++++--------- src/AlgebraicGeometry/RationalPoint/Types.jl | 78 ++++++++++++ .../Schemes/AbstractTypes.jl | 29 ++++- src/AlgebraicGeometry/Schemes/Types.jl | 3 + .../Schemes/AffineRationalPoint.jl | 21 +++- .../Schemes/ProjectiveRationalPoint.jl | 24 ++++ 9 files changed, 254 insertions(+), 143 deletions(-) create mode 100644 src/AlgebraicGeometry/RationalPoint/PointSet.jl create mode 100644 src/AlgebraicGeometry/RationalPoint/Types.jl create mode 100644 test/AlgebraicGeometry/Schemes/ProjectiveRationalPoint.jl diff --git a/src/AlgebraicGeometry/AlgebraicGeometry.jl b/src/AlgebraicGeometry/AlgebraicGeometry.jl index ac049ece3922..24d020bfb231 100644 --- a/src/AlgebraicGeometry/AlgebraicGeometry.jl +++ b/src/AlgebraicGeometry/AlgebraicGeometry.jl @@ -3,5 +3,7 @@ include("ToricVarieties/JToric.jl") include("Surfaces/K3Auto.jl") include("Surfaces/SurfacesP4.jl") include("Miscellaneous/basics.jl") +include("RationalPoint/Types.jl") +include("RationalPoint/PointSet.jl") include("RationalPoint/AffineRationalPoint.jl") include("RationalPoint/ProjectiveRationalPoint.jl") diff --git a/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl b/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl index f022c2f2245d..b58bd0890e5d 100644 --- a/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl +++ b/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl @@ -1,72 +1,30 @@ -@doc raw""" - AffineRationalPoint{CoeffType<:RingElem, ParentType<:AbsSpec} - -A rational point represented in terms of a vector of coordinates. - -Two rational points are considered equal if their parents have the same ambient -space and their coordinates agree. - -# Examples -```jldoctest -julia> A2 = affine_space(GF(2), [:x, :y]); - -julia> (x, y) = coordinates(A2); - -julia> X = algebraic_set(x*y); - -julia> X([1, 0]) -Rational point - of V(x*y) - with coordinates (1, 0) - -``` -""" -struct AffineRationalPoint{S<:RingElem, T<:AbsSpec} <: AbsAffineRationalPoint{S, T} - # not mutable since this should be efficient - coordinates::Vector{S} - parent::T - - function AffineRationalPoint(parent::T, coordinates::Vector{S}; check::Bool=true) where {S <: RingElem, T<:AbsSpec} - r = new{S, T}(coordinates, parent) - @check begin - n = dim(ambient_space(parent)) - k = base_ring(parent) - - all(Oscar.parent(i)===k for i in coordinates) || error("coordinates do not lie in the base ring") - n == length(coordinates) || error("$(coordinates) must have length $(n)") - _in(r, parent)|| error("$(coordinates) does not lie in $(parent)") - end - return r - end -end +# implement the AbsRationalPoint interface +parent(p::AffineRationalPoint) = p.parent -@doc raw""" - parent(p::AffineRationalPoint) -> AbsSpec +coordinate(P::AbsAffineRationalPoint, i::Int) = coordinates(P)[i] +getindex(P::AbsAffineRationalPoint, i::Int) = coordinate(P, i) -Return the parent ``X`` of the rational point ``p \in X``. -""" -parent(p::AffineRationalPoint) = p.parent @doc raw""" coordinates(p::AffineRationalPoint{S,T}) -> Vector{S} Return the coordinates of the rational point `p`. -The coordinates are with respect to the ambient space of its parent. +The coordinates are with respect to the ambient space of its ambient scheme. """ coordinates(p::AffineRationalPoint) = p.coordinates function (X::AbsSpec)(coordinates::Vector; check::Bool=true) k = base_ring(X) coordinates = k.(coordinates) - return AffineRationalPoint(X, coordinates, check=check) + return AffineRationalPoint(rational_point_set(X), coordinates, check=check) end function Base.show(io::IO, ::MIME"text/plain", P::AbsAffineRationalPoint) io = pretty(io) println(io, "Rational point") print(io, Indent()) - println(io, "of ", parent(P)) + println(io, "of ", Lowercase(), ambient_scheme(P)) print(io, "with coordinates (") join(io, coordinates(P), ", ") print(io, ")", Dedent()) @@ -79,29 +37,25 @@ function Base.show(io::IO, P::AbsAffineRationalPoint) end function ==(P::AbsAffineRationalPoint{S,T}, Q::AbsAffineRationalPoint{S,U}) where {S,T,U} - ambient_space(parent(P)) == ambient_space(parent(Q)) || return false + ambient_space(P) == ambient_space(Q) || return false return coordinates(P) == coordinates(Q) end function Base.hash(P::AbsAffineRationalPoint, h::UInt) - return xor(hash(coordinates(P), h), hash(parent(P), h)) + return xor(hash(coordinates(P), h), hash(ambient_scheme(P), h)) end -base_ring(P::AbsAffineRationalPoint) = base_ring(parent(P)) -coefficient_ring(P::AbsAffineRationalPoint) = base_ring(parent(P)) -coordinate(P::AbsAffineRationalPoint, i::Int) = coordinates(P)[i] -getindex(P::AbsAffineRationalPoint, i::Int) = coordinate(P, i) @doc raw""" ideal(P::AbsAffineRationalPoint) -Return the maximal ideal associated to `P` in the ambient coordinate ring -of its parent. +Return the maximal ideal associated to `P` in the coordinate ring +of its ambient space. """ function ideal(P::AbsAffineRationalPoint) - R = ambient_coordinate_ring(parent(P)) - V = ambient_coordinates(parent(P)) + R = OO(ambient_space(P)) + V = coordinates(ambient_space(P)) I = ideal(R, [V[i] - coordinate(P, i) for i in 1:length(V)]) set_attribute!(I, :is_prime=>true) set_attribute!(I, :is_maximal=>true) @@ -111,7 +65,7 @@ end function _in(P::AbsAffineRationalPoint, X::AbsSpec{<:Any,<:MPolyRing}) # X is affine space - return ambient_space(parent(P)) == X + return ambient_space(P) == X end function evaluate(f::MPolyRingElem, P::AbsAffineRationalPoint) @@ -119,7 +73,7 @@ function evaluate(f::MPolyRingElem, P::AbsAffineRationalPoint) end function _in(P::AbsAffineRationalPoint, X::AbsSpec{<:Any,<:MPolyQuoRing}) - ambient_space(parent(P)) == ambient_space(X) || return false + ambient_space(P) == ambient_space(X) || return false c = coordinates(P) for f in gens(ambient_closure_ideal(X)) iszero(evaluate(f, c)) || return false @@ -129,7 +83,7 @@ end function _in(P::AbsAffineRationalPoint, X::AbsAffineAlgebraicSet{<:Any,<:MPolyQuoRing}) # we can do this without computing the vanishing ideal of X - ambient_space(parent(P)) == ambient_space(X) || return false + ambient_space(P) == ambient_space(X) || return false c = coordinates(P) for f in gens(fat_ideal(X)) iszero(evaluate(f, c)) || return false @@ -144,7 +98,7 @@ function _in(P::AbsAffineRationalPoint, X::AbsSpec) end function Base.in(P::AbsAffineRationalPoint, X::AbsSpec) - parent(P) === X && return true + codomain(P) === X && return true return _in(P, X) end @@ -160,39 +114,42 @@ of its ambient affine space. """ function scheme(P::AbsAffineRationalPoint) I = ideal(P) - R = ambient_coordinate_ring(parent(P)) + R = OO(ambient_space(P)) return Spec(R, I) end @doc raw""" closed_embedding(P::AbsAffineRationalPoint) -> ClosedEmbedding -Return the closed embedding of `P` into its parent scheme `X`. +Return the closed embedding of `P` into its ambient scheme `X`. """ function closed_embedding(P::AbsAffineRationalPoint) I = ideal(P) - X = parent(P) + X = ambient_scheme(P) return ClosedEmbedding(X, I) end -function (f::AbsSpecMor)(P::AbsAffineRationalPoint) - @req domain(f) == parent(P) "$(P) not in domain" + +function (f::AbsSpecMor{<:AbsSpec{S},<:AbsSpec{S},<:Any,<:Any,Nothing})(P::AbsAffineRationalPoint) where {S} + # The Nothing type parameter assures that the base morphism is trivial. + @req domain(f) == codomain(P) "$(P) not in domain" + @req base_ring(domain(f)) == base_ring(codomain(f)) "schemes must be defined over the same base ring. Try to map the point as an ideal instead" x = coordinates(codomain(f)) g = pullback(f) p = coordinates(P) imgs = [evaluate(lift(g(y)),p) for y in x] - return AffineRationalPoint(codomain(f), imgs, check=false) + return codomain(f)(imgs; check=false) end function MPolyComplementOfKPointIdeal(P::AbsAffineRationalPoint) - R = ambient_coordinate_ring(parent(P)) + R = OO(ambient_space(P)) return MPolyComplementOfKPointIdeal(R, coordinates(P)) end function is_smooth_at(X::AbsSpec{<:Field}, P::AbsAffineRationalPoint) @req P in X "not a point on X" U = MPolyComplementOfKPointIdeal(P) - R = OO(parent(P)) + R = OO(codomain(P)) XU = Spec(localization(R, U)[1]) return is_smooth(XU) end @@ -200,9 +157,9 @@ end @doc raw""" is_smooth(P::AbsAffineRationalPoint) -Return whether ``P`` is a smooth point of its parent ``X``. +Return whether ``P`` is a smooth point of its ambient scheme ``X``. """ -is_smooth(P::AbsAffineRationalPoint) = is_smooth_at(parent(P),P) +is_smooth(P::AbsAffineRationalPoint) = is_smooth_at(codomain(P),P) @doc raw""" @@ -226,25 +183,25 @@ end @doc raw""" tangent_space(P::AbsAffineRationalPoint{<:FieldElem}) -> AlgebraicSet -Return the Zariski tangent space of the parent of `P` at its point `P`. +Return the Zariski tangent space of the ambient scheme of `P` at its point `P`. See also [`tangent_space(X::AbsSpec{<:Field}, P::AbsAffineRationalPoint)`](@ref) """ -tangent_space(P::AbsAffineRationalPoint{<:FieldElem}) = tangent_space(parent(P), P) +tangent_space(P::AbsAffineRationalPoint{<:FieldElem}) = tangent_space(codomain(P), P) @doc raw""" is_du_val_singularity(P::AbsAffineRationalPoint{<:Field}) -Return whether the parent of `P` has at most a Du Val singularity at `P`. +Return whether the ambient scheme of `P` has at most a Du Val singularity at `P`. Note that this includes the case that ``P`` is a smooth point. """ -is_du_val_singularity(P::AbsAffineRationalPoint{<:FieldElem}) = is_du_val_singularity(parent(P), ideal(P)) +is_du_val_singularity(P::AbsAffineRationalPoint{<:FieldElem}) = is_du_val_singularity(codomain(P), ideal(P)) @doc raw""" decide_du_val_singularity(P::AbsAffineRationalPoint{<:Field}) -Return whether the parent of `P` has a Du Val singularity at `P`. +Return whether the ambient scheme of `P` has a Du Val singularity at `P`. # Examples ```jldoctest @@ -260,6 +217,6 @@ julia> Oscar.decide_du_val_singularity(X([0,0,0])) ``` """ function decide_du_val_singularity(P::AbsAffineRationalPoint{<:FieldElem,<:Any}) - d = decide_du_val_singularity(parent(P), ideal(P)) + d = decide_du_val_singularity(codomain(P), ideal(P)) return d[1][1],d[1][3] end diff --git a/src/AlgebraicGeometry/RationalPoint/PointSet.jl b/src/AlgebraicGeometry/RationalPoint/PointSet.jl new file mode 100644 index 000000000000..219646378f84 --- /dev/null +++ b/src/AlgebraicGeometry/RationalPoint/PointSet.jl @@ -0,0 +1,39 @@ +@attr RationalPointSet{typeof(base_scheme(X)), S} function rational_point_set(X::S) where {S} + return RationalPointSet(base_scheme(X), X) +end + +domain(X::RationalPointSet) = X.domain +codomain(X::RationalPointSet) = X.codomain +coefficient_ring(X::RationalPointSet) = OO(domain(X)) + + +function Base.show(io::IO,::MIME"text/plain", X::RationalPointSet) + io = pretty(io) + println(io, "Set of rational points") + println(io, Indent(), "over " , Lowercase(), domain(X), Dedent()) + print(io, Indent(), "of " , Lowercase(), codomain(X)) +end + +function Base.show(io::IO, X::RationalPointSet) + io = pretty(io) + print(io, "Set of rational points ") + print(io, "over " , Lowercase(), domain(X)) + print(io, "of " , Lowercase(), codomain(X)) +end + + +function (S::RationalPointSet{<:Any,<:AbsSpec})(c::Vector; check::Bool=true) + k = coefficient_ring(S) + c = k.(c) + return AffineRationalPoint(S, c; check=check) +end + +function (S::RationalPointSet{<:Any,<:AbsProjectiveScheme})(c::Vector; check::Bool=true) + k = coefficient_ring(S) + c = S.(c) + return ProjectiveRationalPoint(S, c; check=check) +end + +function (S::AbsRationalPointSet)(p::AbsRationalPoint) + return S(coordinates(p)) +end diff --git a/src/AlgebraicGeometry/RationalPoint/ProjectiveRationalPoint.jl b/src/AlgebraicGeometry/RationalPoint/ProjectiveRationalPoint.jl index e746350180d0..f22efb7f4667 100644 --- a/src/AlgebraicGeometry/RationalPoint/ProjectiveRationalPoint.jl +++ b/src/AlgebraicGeometry/RationalPoint/ProjectiveRationalPoint.jl @@ -1,47 +1,10 @@ -@doc raw""" - ProjectiveRationalPoint{CoeffType<:RingElem, ParentType<:AbsProjectiveScheme} - -Type for rational points in projective varieties. - -# Examples -```jldoctest -julia> P2 = projective_space(QQ, 2) - -julia> P2([4, 0 , 2//3]) -``` -""" -struct ProjectiveRationalPoint{S<:RingElem, T<:AbsProjectiveScheme} <: AbsProjectiveRationalPoint{S, T} - # not mutable since this should be efficient - coordinates::Vector{S} - parent::T - - function ProjectiveRationalPoint(parent::T, coordinates::Vector{S}; check::Bool=true) where {S <: RingElem, T<:AbsProjectiveScheme} - r = new{S, T}(coordinates, parent) - @check begin - n = relative_ambient_dimension(parent) + 1 - k = base_ring(parent) - all(Oscar.parent(i)===k for i in coordinates) || error("coordinates do not lie in the base ring") - n == length(coordinates) || error("$(coordinates) must have length $(n)") - _is_projective(coordinates) || error("not a point in projective space") - _in(r, parent)|| error("$(coordinates) does not lie in $(parent)") - end - return r - end -end - -@doc raw""" - parent(p::AbsProjectiveRationalPoint) -> AbsProjectiveScheme - -Return the parent ``X`` of the rational point ``p \in X``. -""" -parent(p::AbsProjectiveRationalPoint) @doc raw""" coordinates(p::AbsProjectiveRationalPoint{S,T}) -> Vector{S} Return the homogeneous coordinates of the rational point `p`. """ -coordinates(p::ProjectiveRationalPoint) +coordinates(p::AbsProjectiveRationalPoint) ################################################################################ # @@ -50,7 +13,7 @@ coordinates(p::ProjectiveRationalPoint) ################################################################################ parent(p::ProjectiveRationalPoint) = p.parent -coordinates(p::AbsProjectiveRationalPoint) = p.coordinates +coordinates(p::ProjectiveRationalPoint) = p.coordinates ################################################################################ @@ -59,14 +22,14 @@ homogeneous_coordinates(p::AbsProjectiveRationalPoint) = coordinates(p) function (X::AbsProjectiveScheme)(coordinates::Vector; check::Bool=true) k = base_ring(X) coordinates = k.(coordinates) - return ProjectiveRationalPoint(X, coordinates, check=check) + return ProjectiveRationalPoint(rational_point_set(X), coordinates; check=check) end function Base.show(io::IO, ::MIME"text/plain", P::AbsProjectiveRationalPoint) io = pretty(io) println(io, "Projective rational point") print(io, Indent()) - println(io, "of ", parent(P)) + println(io, "of ", codomain(P)) print(io, "with coordinates (") join(io, coordinates(P), " : ") print(io, ")", Dedent()) @@ -78,8 +41,8 @@ function Base.show(io::IO, P::AbsProjectiveRationalPoint) print(io,")") end -base_ring(P::AbsProjectiveRationalPoint) = base_ring(parent(P)) -coefficient_ring(P::AbsProjectiveRationalPoint) = base_ring(parent(P)) +base_ring(P::AbsProjectiveRationalPoint) = base_ring(codomain(P)) +coefficient_ring(P::AbsProjectiveRationalPoint) = base_ring(codomain(P)) coordinate(P::AbsProjectiveRationalPoint, i::Int) = coordinates(P)[i] Base.getindex(P::AbsProjectiveRationalPoint, i::Int) = coordinate(P, i) Base.setindex!(a::AbsProjectiveRationalPoint, v, i::Int) = coordinates(a)[i] = v @@ -88,12 +51,12 @@ Base.setindex!(a::AbsProjectiveRationalPoint, v, i::Int) = coordinates(a)[i] = v ideal(P::AbsProjectiveRationalPoint) Return the homogeneous ideal associated to `P` -in the homogeneous coordinate ring of its parent. +in the homogeneous coordinate ring of its ambient space. """ function ideal(P::AbsProjectiveRationalPoint) - R = ambient_coordinate_ring(parent(P)) + R = ambient_coordinate_ring(codomain(P)) V = gens(R) - w = weights(parent(P)) + w = weights(codomain(P)) n = length(V) m = elem_type(R)[] # first non-zero coordinate @@ -109,11 +72,11 @@ end function _in(P::AbsProjectiveRationalPoint, X::AbsProjectiveScheme{<:Any,<:MPolyDecRing{<:Any,<:MPolyRing}}) # X is projective space - return ambient_space(parent(P)) == X + return ambient_space(P) == X end function _in(P::AbsProjectiveRationalPoint, X::AbsProjectiveScheme{<:Any,<:MPolyQuoRing{<:MPolyDecRingElem}}) - ambient_space(parent(P)) == ambient_space(X) || return false + ambient_space(P) == ambient_space(X) || return false c = coordinates(P) for f in gens(defining_ideal(X)) iszero(evaluate(f, c)) || return false @@ -123,7 +86,7 @@ end # We can do this without computing the vanishing ideal of X function _in(P::AbsProjectiveRationalPoint, X::AbsProjectiveAlgebraicSet{<:Any,<:MPolyQuoRing{<:MPolyDecRingElem}}) - ambient_space(parent(P)) == ambient_space(X) || return false + ambient_space(P) == ambient_space(X) || return false c = coordinates(P) for f in gens(fat_ideal(X)) iszero(evaluate(f, c)) || return false @@ -132,7 +95,7 @@ function _in(P::AbsProjectiveRationalPoint, X::AbsProjectiveAlgebraicSet{<:Any,< end function Base.in(P::AbsProjectiveRationalPoint, X::AbsProjectiveScheme) - parent(P) === X && return true + codomain(P) === X && return true return _in(P, X) end @@ -144,12 +107,13 @@ of its ambient projective space. """ function scheme(P::AbsProjectiveRationalPoint) I = ideal(P) - R = ambient_coordinate_ring(parent(P)) + R = ambient_coordinate_ring(codomain(P)) return ProjectiveScheme(R, I) end -function (f::ProjectiveSchemeMor)(P::AbsProjectiveRationalPoint) - @req domain(f) == parent(P) "$(P) not in domain" +function (f::ProjectiveSchemeMor{<:Any,<:Any,<:Any,Nothing})(P::AbsProjectiveRationalPoint) + @req domain(f) == codomain(P) "$(P) not in domain" + @req base_ring(domain(f)) == base_ring(codomain(f)) "schemes must be defined over the same base ring" x = homogeneous_coordinates(codomain(f)) g = pullback(f) p = coordinates(P) @@ -162,7 +126,7 @@ function is_smooth_at(X::AbsProjectiveScheme{<:Field}, P::AbsProjectiveRationalP error("not implemented") end -is_smooth(P::AbsProjectiveRationalPoint) = is_smooth_at(parent(P),P) +is_smooth(P::AbsProjectiveRationalPoint) = is_smooth_at(codomain(P),P) function _is_projective(a::Vector{T}) where {T <: AbstractAlgebra.FieldElem} return !all(iszero, a) @@ -180,10 +144,10 @@ end Nemo.parent_type(::AbsProjectiveRationalPoint{S,T}) where {S,T} = T function ==(a::AbsProjectiveRationalPoint{S, T}, b::AbsProjectiveRationalPoint{S, U}) where {S<:Union{FieldElem,ZZRingElem},T, U} - ambient_space(parent(a)) == ambient_space(parent(b)) || return false + ambient_space(a) == ambient_space(b) || return false n = length(coordinates(a)) i = 1 - w = weights(parent(a)) + w = weights(codomain(a)) while iszero(a[i]) iszero(b[i]) || return false i += 1 @@ -210,8 +174,8 @@ function normalize!(a::AbsProjectiveRationalPoint{<:FieldElem}) i += 1 end ca = inv(a[i]) - a[i] = one(base_ring(parent(a))) - w = weights(parent(a)) + a[i] = one(coefficient_ring(a)) + w = weights(codomain(a)) any(x->!isone(x), w) && error("cannot normalize with weights") i += 1 while i <= l @@ -233,10 +197,10 @@ function normalize!(a::AbsProjectiveRationalPoint{ZZRingElem}) while iszero(a[i]) i += 1 end - w = weights(parent(a)) + w = weights(codomain(a)) any(x->!isone(x), w) && error("cannot normalize with weights") ca = sign(a[i]) - while i <= dim(parent(a)) + while i <= dim(codomain(a)) a[i] = ca*a[i] #TODO: weights i += 1 end @@ -244,7 +208,7 @@ function normalize!(a::AbsProjectiveRationalPoint{ZZRingElem}) end function Base.hash(a::AbsProjectiveRationalPoint, u::UInt=UInt(123432)) - if isweighted(parent(a)) + if isweighted(codomain(a)) return u end normalize!(a) diff --git a/src/AlgebraicGeometry/RationalPoint/Types.jl b/src/AlgebraicGeometry/RationalPoint/Types.jl new file mode 100644 index 000000000000..4f47f9eff36d --- /dev/null +++ b/src/AlgebraicGeometry/RationalPoint/Types.jl @@ -0,0 +1,78 @@ +struct RationalPointSet{P<:AbsSpec, T<:Scheme} <: AbsRationalPointSet{P,T} + domain::P + codomain::T +end + + +@doc raw""" + AffineRationalPoint{CoeffType<:RingElem, ParentType<:RationalPointSet} + +A rational point represented in terms of a vector of coordinates. + +# Examples +```jldoctest +julia> A2 = affine_space(GF(2), [:x, :y]); + +julia> (x, y) = coordinates(A2); + +julia> X = algebraic_set(x*y); + +julia> X([1, 0]) +Rational point + of V(x*y) + with coordinates (1, 0) + +``` +""" +struct AffineRationalPoint{S<:RingElem, T<:RationalPointSet} <: AbsAffineRationalPoint{S, T} + # not mutable since this should be efficient + coordinates::Vector{S} + parent::T + + function AffineRationalPoint(parent::T, coordinates::Vector{S}; check::Bool=true) where {S <: RingElem, T<:AbsRationalPointSet} + r = new{S, T}(coordinates, parent) + @check begin + X = codomain(parent) + n = ngens(OO(ambient_space(X))) + k = coefficient_ring(parent) + + all(Oscar.parent(i)===k for i in coordinates) || error("coordinates do not lie in the base ring") + n == length(coordinates) || error("$(coordinates) must have length $(n)") + _in(r, X)|| error("$(coordinates) does not lie in $(parent)") + end + return r + end +end + + +@doc raw""" + ProjectiveRationalPoint{CoeffType<:RingElem, ParentType<:AbsProjectiveScheme} + +Type for rational points in projective varieties. + +# Examples +```jldoctest +julia> P2 = projective_space(QQ, 2) + +julia> P2([4, 0 , 2//3]) +``` +""" +struct ProjectiveRationalPoint{S<:RingElem, T<:AbsRationalPointSet} <: AbsProjectiveRationalPoint{S, T} + # not mutable since this should be efficient + coordinates::Vector{S} + parent::T + + function ProjectiveRationalPoint(parent::T, coordinates::Vector{S}; check::Bool=true) where {S <: RingElem, T<:AbsRationalPointSet} + r = new{S, T}(coordinates, parent) + @check begin + X = codomain(parent) + n = relative_ambient_dimension(X) + 1 + k = coefficient_ring(parent) + all(Oscar.parent(i)===k for i in coordinates) || error("coordinates do not lie in the base ring") + n == length(coordinates) || error("$(coordinates) must have length $(n)") + _is_projective(coordinates) || error("not a point in projective space") + _in(r, X)|| error("$(coordinates) does not lie in $(parent)") + end + return r + end +end diff --git a/src/AlgebraicGeometry/Schemes/AbstractTypes.jl b/src/AlgebraicGeometry/Schemes/AbstractTypes.jl index 10525aa7971f..233a4b425a01 100644 --- a/src/AlgebraicGeometry/Schemes/AbstractTypes.jl +++ b/src/AlgebraicGeometry/Schemes/AbstractTypes.jl @@ -106,6 +106,29 @@ abstract type AbsCoveredSurface{BaseField<:Field} <: AbsCoveredVariety{BaseField # Abstract types for rational points # ################################################################################ + +@doc raw""" + AbsRationalPointSet{P<:AbsSpec,T<:Scheme} + +Abstract type for the set of rational points of a scheme. + +Let ``k`` be a ring, ``L`` a ``k`-algebra and ``X`` a scheme over ``k``. The set ``X(L)`` of ``L``-rational points of ``X`` is defined as the set of homomorphisms over ``Spec k`` from ``Spec L`` to ``X``, i.e. as ``X(L) = Hom_{Spec k}(Spec L, X)``. + +We refer to ``L`` as the `coefficient_ring`, to +``Spec L`` as the `domain` and to ``X`` as the `codomain` of this +homset. For traditional reasons we keep the name +`ambient_scheme` for the codomain. +""" +abstract type AbsRationalPointSet{P<:AbsSpec,T<:Scheme} end + +abstract type AbsRationalPoint{RingElemType, ParentType} end + +domain(p::AbsRationalPoint) = domain(parent(p)) +codomain(p::AbsRationalPoint) = codomain(parent(p)) +ambient_scheme(p::AbsRationalPoint) = codomain(p) +ambient_space(p::AbsRationalPoint) = ambient_space(ambient_scheme(p)) +coefficient_ring(P::AbsRationalPoint) = coefficient_ring(parent(P)) + @doc raw""" AbsAffineRationalPoint{CoefficientType, ParentType} @@ -117,7 +140,7 @@ defined by the ideal ``I = (f_1, \dots f_r) \subseteq k[x_1,\dots x_n]``. A rational point ``p`` of ``X`` is a tuple ``p = (p_1, \dots , p_n) \in k^n`` such that ``f_1(p) = \dots = f_n(p) = 0``. """ -abstract type AbsAffineRationalPoint{RingElemType, ParentType} end +abstract type AbsAffineRationalPoint{RingElemType, ParentType} <: AbsRationalPoint{RingElemType, ParentType} end @doc raw""" AbsProjectiveRationalPoint @@ -132,5 +155,7 @@ Let ``X \subseteq \mathbb{P}^n_k`` be an algebraic set or more generally a close This type includes points in weighted projective space. """ -abstract type AbsProjectiveRationalPoint{RingElemType, ParentType} end +abstract type AbsProjectiveRationalPoint{RingElemType, ParentType} <: AbsRationalPoint{RingElemType, ParentType} end + +abstract type AbsCoveredRationalPoint{RingElemType, ParentType} <: AbsRationalPoint{RingElemType, ParentType} end diff --git a/src/AlgebraicGeometry/Schemes/Types.jl b/src/AlgebraicGeometry/Schemes/Types.jl index 73659e72b102..935ee6f548e2 100644 --- a/src/AlgebraicGeometry/Schemes/Types.jl +++ b/src/AlgebraicGeometry/Schemes/Types.jl @@ -8,6 +8,9 @@ A scheme over a ring ``𝕜`` of type `BaseRingType`. """ abstract type Scheme{BaseRingType} end +@attr Spec{S,S} function base_scheme(X::Scheme{S}) where {S<:Ring} + return Spec(base_ring(X)) +end ### Abstract type for morphisms of arbitrary schemes ################## @doc raw""" diff --git a/test/AlgebraicGeometry/Schemes/AffineRationalPoint.jl b/test/AlgebraicGeometry/Schemes/AffineRationalPoint.jl index 1a9e432e4868..c9eed59d8d17 100644 --- a/test/AlgebraicGeometry/Schemes/AffineRationalPoint.jl +++ b/test/AlgebraicGeometry/Schemes/AffineRationalPoint.jl @@ -12,7 +12,8 @@ @test pX in X @test pA in X - @test parent(pX)===X + @test codomain(pX)===X + @test ambient_scheme(pX)===X @test is_prime(ideal(pX)) @test pX[1] == 1 @@ -49,4 +50,22 @@ pt = P2cov[1][1]([1,0]) @test pt in P2cov + k = GF(2) + L = GF(2,2) + A2 = affine_space(k ,2) + A2k = Oscar.RationalPointSet(Spec(k), A2) + A2L = Oscar.RationalPointSet(Spec(L), A2) + pk = A2k([1,1]) + pL = A2L(pk) # conversion + @test !(pk == pL) # no automatic coercion -> consistent with hom interpretation since the domains differ + + # reduction mod p + k = ZZ + L = GF(2,2) + A2 = affine_space(k ,2) + A2k = Oscar.RationalPointSet(Spec(k), A2) + A2L = Oscar.RationalPointSet(Spec(L), A2) + pk = A2k([1,1]) + pL = A2L(pk) # conversion + @test !(pk == pL) # no automatic coercion -> consistent with hom interpretation since the domains differ end diff --git a/test/AlgebraicGeometry/Schemes/ProjectiveRationalPoint.jl b/test/AlgebraicGeometry/Schemes/ProjectiveRationalPoint.jl new file mode 100644 index 000000000000..3280d4ad1bb8 --- /dev/null +++ b/test/AlgebraicGeometry/Schemes/ProjectiveRationalPoint.jl @@ -0,0 +1,24 @@ +@testset "Projective rational points" begin + P2 = projective_space(QQ, 2) + + @test P2([0,1,0]) == P2([0,2,0]) + @test P2([0,1,2]) == P2([0,2,4]) + (s0, s1, s2) = homogeneous_coordinates(P2) + X = subscheme(P2, s2*s1-s0^2) + + @test_throws ErrorException P2([0,0,0]) + @test_throws ErrorException X([1,2,1]) + + ideal(X([1,1,1])) == ideal(P2([1,1,1])) + A = algebraic_set(X) + @test A([1,1,1]) == X([1,1,1]) + + @test issubset(scheme(A([1,1,1])), A) + + + P2Z = projective_space(ZZ, 2) + @test_throws ErrorException P2Z([2,2,2]) + @test P2([0,1,2]) == P2([0,-1,-2]) + + +end From 02923d3cf7a171558491c06322a55842d13b7a7f Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Wed, 9 Aug 2023 13:07:59 +0200 Subject: [PATCH 10/13] fix docu --- docs/src/AlgebraicGeometry/RationalPoints/Affine.md | 1 - docs/src/AlgebraicGeometry/RationalPoints/Projective.md | 1 - src/AlgebraicGeometry/RationalPoint/PointSet.jl | 8 +++++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/src/AlgebraicGeometry/RationalPoints/Affine.md b/docs/src/AlgebraicGeometry/RationalPoints/Affine.md index 92c778597118..7d880545f07a 100644 --- a/docs/src/AlgebraicGeometry/RationalPoints/Affine.md +++ b/docs/src/AlgebraicGeometry/RationalPoints/Affine.md @@ -11,7 +11,6 @@ using Oscar ```@docs AbsAffineRationalPoint AffineRationalPoint -parent(p::AffineRationalPoint) coordinates(p::AffineRationalPoint) ideal(P::AbsAffineRationalPoint) scheme(P::AbsAffineRationalPoint) diff --git a/docs/src/AlgebraicGeometry/RationalPoints/Projective.md b/docs/src/AlgebraicGeometry/RationalPoints/Projective.md index a9a7f5aa8826..5464dbb46bf2 100644 --- a/docs/src/AlgebraicGeometry/RationalPoints/Projective.md +++ b/docs/src/AlgebraicGeometry/RationalPoints/Projective.md @@ -11,7 +11,6 @@ using Oscar ```@docs AbsProjectiveRationalPoint ProjectiveRationalPoint -parent(P::ProjectiveRationalPoint) coordinates(P::ProjectiveRationalPoint) ideal(P::ProjectiveRationalPoint) scheme(P::ProjectiveRationalPoint) diff --git a/src/AlgebraicGeometry/RationalPoint/PointSet.jl b/src/AlgebraicGeometry/RationalPoint/PointSet.jl index 219646378f84..78e76702b366 100644 --- a/src/AlgebraicGeometry/RationalPoint/PointSet.jl +++ b/src/AlgebraicGeometry/RationalPoint/PointSet.jl @@ -1,4 +1,10 @@ -@attr RationalPointSet{typeof(base_scheme(X)), S} function rational_point_set(X::S) where {S} + +@doc """raw + rational_point_set(X::Scheme) -> RationalPointSet + +For a scheme over ``k`` return its set of ``k``-rational points. +""" +@attr RationalPointSet{typeof(base_scheme(X)), S} function rational_point_set(X::S) where {S<:Scheme} return RationalPointSet(base_scheme(X), X) end From 522705140e47177f24bcdab5d6bb8c60603bdefe Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Wed, 9 Aug 2023 14:50:35 +0200 Subject: [PATCH 11/13] fix a test --- test/AlgebraicGeometry/Schemes/ProjectiveSchemes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/AlgebraicGeometry/Schemes/ProjectiveSchemes.jl b/test/AlgebraicGeometry/Schemes/ProjectiveSchemes.jl index c984a4b5147d..493a20baf496 100644 --- a/test/AlgebraicGeometry/Schemes/ProjectiveSchemes.jl +++ b/test/AlgebraicGeometry/Schemes/ProjectiveSchemes.jl @@ -301,7 +301,7 @@ end @test all(U->(OO(U) isa MPolyRing), affine_charts(X)) end -@test "equality of projective schemes" begin +@testset "equality of projective schemes" begin P2 = projective_space(GF(17), 2) (x0,x1,x2) = homogeneous_coordinates(P2) R = homogeneous_coordinate_ring(P2) From 0e2a725ee39ceea5e96235388d5047fbe625cb2f Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Thu, 10 Aug 2023 15:37:29 +0200 Subject: [PATCH 12/13] fix a typo in comparison of projective schemes --- .../Schemes/ProjectiveSchemes/Objects/Methods.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Methods.jl b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Methods.jl index 8ddd725fe9a2..3ea50c38cdfa 100644 --- a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Methods.jl +++ b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Methods.jl @@ -385,7 +385,7 @@ function ==(X::AbsProjectiveScheme, Y::AbsProjectiveScheme) R = homogeneous_coordinate_ring(ambient_space(X)) irrelevant_ideal = ideal(R,gens(R)) IXsat = saturation(IX, irrelevant_ideal) - IYsat = saturation(IX, irrelevant_ideal) + IYsat = saturation(IY, irrelevant_ideal) return IXsat == IYsat end From 4e6d62082fe03065af3dd010907327bc121b6975 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Fri, 11 Aug 2023 09:07:38 +0200 Subject: [PATCH 13/13] fix printing and doctest --- .../RationalPoint/AffineRationalPoint.jl | 4 ++-- .../RationalPoint/ProjectiveRationalPoint.jl | 4 ++-- src/AlgebraicGeometry/RationalPoint/Types.jl | 8 ++++++-- .../Schemes/AffineAlgebraicSet/Objects/Methods.jl | 2 +- .../Schemes/ProjectiveAlgebraicSet/Objects/Methods.jl | 2 +- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl b/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl index b58bd0890e5d..4da7f2d51cf3 100644 --- a/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl +++ b/src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl @@ -24,10 +24,10 @@ function Base.show(io::IO, ::MIME"text/plain", P::AbsAffineRationalPoint) io = pretty(io) println(io, "Rational point") print(io, Indent()) - println(io, "of ", Lowercase(), ambient_scheme(P)) + println(io, "of ", Lowercase(), ambient_scheme(P), Dedent()) print(io, "with coordinates (") join(io, coordinates(P), ", ") - print(io, ")", Dedent()) + print(io, ")") end function Base.show(io::IO, P::AbsAffineRationalPoint) diff --git a/src/AlgebraicGeometry/RationalPoint/ProjectiveRationalPoint.jl b/src/AlgebraicGeometry/RationalPoint/ProjectiveRationalPoint.jl index f22efb7f4667..a155fd5eb23b 100644 --- a/src/AlgebraicGeometry/RationalPoint/ProjectiveRationalPoint.jl +++ b/src/AlgebraicGeometry/RationalPoint/ProjectiveRationalPoint.jl @@ -29,10 +29,10 @@ function Base.show(io::IO, ::MIME"text/plain", P::AbsProjectiveRationalPoint) io = pretty(io) println(io, "Projective rational point") print(io, Indent()) - println(io, "of ", codomain(P)) + println(io, "of ", codomain(P), Dedent()) print(io, "with coordinates (") join(io, coordinates(P), " : ") - print(io, ")", Dedent()) + print(io, ")") end function Base.show(io::IO, P::AbsProjectiveRationalPoint) diff --git a/src/AlgebraicGeometry/RationalPoint/Types.jl b/src/AlgebraicGeometry/RationalPoint/Types.jl index 4f47f9eff36d..622d12d893c1 100644 --- a/src/AlgebraicGeometry/RationalPoint/Types.jl +++ b/src/AlgebraicGeometry/RationalPoint/Types.jl @@ -20,7 +20,7 @@ julia> X = algebraic_set(x*y); julia> X([1, 0]) Rational point of V(x*y) - with coordinates (1, 0) +with coordinates (1, 0) ``` """ @@ -52,9 +52,13 @@ Type for rational points in projective varieties. # Examples ```jldoctest -julia> P2 = projective_space(QQ, 2) +julia> P2 = projective_space(QQ, 2); julia> P2([4, 0 , 2//3]) +Projective rational point + of Projective 2-space over QQ with coordinates [s0, s1, s2] +with coordinates (4 : 0 : 2//3) + ``` """ struct ProjectiveRationalPoint{S<:RingElem, T<:AbsRationalPointSet} <: AbsProjectiveRationalPoint{S, T} diff --git a/src/AlgebraicGeometry/Schemes/AffineAlgebraicSet/Objects/Methods.jl b/src/AlgebraicGeometry/Schemes/AffineAlgebraicSet/Objects/Methods.jl index 4e31fa94624d..f569702991f3 100644 --- a/src/AlgebraicGeometry/Schemes/AffineAlgebraicSet/Objects/Methods.jl +++ b/src/AlgebraicGeometry/Schemes/AffineAlgebraicSet/Objects/Methods.jl @@ -41,7 +41,7 @@ function Base.show(io::IO, X::AffineAlgebraicSet{<:Field,<:MPolyQuoRing}) else I = fat_ideal(X) end - print(io, "V(") + print(io, LowercaseOff(), "V(") join(io, gens(I), ", ") print(io,")") end diff --git a/src/AlgebraicGeometry/Schemes/ProjectiveAlgebraicSet/Objects/Methods.jl b/src/AlgebraicGeometry/Schemes/ProjectiveAlgebraicSet/Objects/Methods.jl index 71d924fca511..214f3dd789f8 100644 --- a/src/AlgebraicGeometry/Schemes/ProjectiveAlgebraicSet/Objects/Methods.jl +++ b/src/AlgebraicGeometry/Schemes/ProjectiveAlgebraicSet/Objects/Methods.jl @@ -19,7 +19,7 @@ function Base.show(io::IO, X::AbsProjectiveAlgebraicSet{<:Field, <:MPolyQuoRing} elseif get_attribute(X, :is_empty, false) print(io, "Empty projective algebraic set") else - print(io, "V(") + print(io, LowercaseOff(), "V(") if isdefined(X, :Xred) I = vanishing_ideal(X) else