Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rational points of varieties/schemes #2627

Merged
merged 13 commits into from
Aug 11, 2023
1 change: 1 addition & 0 deletions src/AlgebraicGeometry/AlgebraicGeometry.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ include("ToricVarieties/JToric.jl")
include("Surfaces/K3Auto.jl")
include("Surfaces/SurfacesP4.jl")
include("Miscellaneous/basics.jl")
include("RationalPoint/AffineRationalPoint.jl")
171 changes: 171 additions & 0 deletions src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
@doc raw"""
AffineRationalPoint{CoeffType<:RingElem, ParentType<:AbsSpec}

A $k$-rational point ``P`` of an affine scheme ``X``.
simonbrandhorst marked this conversation as resolved.
Show resolved Hide resolved

We refer to ``X`` as the parent of ``P``.

# 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])

simonbrandhorst marked this conversation as resolved.
Show resolved Hide resolved
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)")
simonbrandhorst marked this conversation as resolved.
Show resolved Hide resolved
_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
10 changes: 10 additions & 0 deletions src/AlgebraicGeometry/Schemes/AbstractTypes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

32 changes: 32 additions & 0 deletions test/AlgebraicGeometry/Schemes/AffineRationalPoint.jl
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion test/AlgebraicGeometry/Schemes/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ include("VectorBundles.jl")
include("WeilDivisor.jl")
include("duValSing.jl")
include("RationalMap.jl")

include("AffineRationalPoint.jl")
Loading