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
4 changes: 4 additions & 0 deletions docs/doc.main
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@
"AlgebraicGeometry/AlgebraicVarieties/AffineVariety.md",
"AlgebraicGeometry/AlgebraicVarieties/ProjectiveVariety.md",
],
"Rational Points" => [
"AlgebraicGeometry/RationalPoints/Affine.md",
"AlgebraicGeometry/RationalPoints/Projective.md",
],
"Toric Varieties" => [
"AlgebraicGeometry/ToricVarieties/intro.md",
"AlgebraicGeometry/ToricVarieties/NormalToricVarieties.md",
Expand Down
28 changes: 28 additions & 0 deletions docs/src/AlgebraicGeometry/RationalPoints/Affine.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
```@meta
CurrentModule = Oscar
```

```@setup oscar
using Oscar
```

# Affine

```@docs
AbsAffineRationalPoint
AffineRationalPoint
coordinates(p::AffineRationalPoint)
ideal(P::AbsAffineRationalPoint)
scheme(P::AbsAffineRationalPoint)
closed_embedding(P::AbsAffineRationalPoint)
is_smooth(P::AbsAffineRationalPoint)
tangent_space(P::AbsAffineRationalPoint{<:FieldElem})
```

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})
```
19 changes: 19 additions & 0 deletions docs/src/AlgebraicGeometry/RationalPoints/Projective.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
```@meta
CurrentModule = Oscar
```

```@setup oscar
using Oscar
```

# Projective

```@docs
AbsProjectiveRationalPoint
ProjectiveRationalPoint
coordinates(P::ProjectiveRationalPoint)
ideal(P::ProjectiveRationalPoint)
scheme(P::ProjectiveRationalPoint)
normalize!(a::AbsProjectiveRationalPoint{<:FieldElem})
normalize!(a::AbsProjectiveRationalPoint{ZZRingElem})
```
4 changes: 3 additions & 1 deletion docs/src/AlgebraicGeometry/Schemes/AffineSchemes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 4 additions & 0 deletions src/AlgebraicGeometry/AlgebraicGeometry.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +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")
222 changes: 222 additions & 0 deletions src/AlgebraicGeometry/RationalPoint/AffineRationalPoint.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
# implement the AbsRationalPoint interface
parent(p::AffineRationalPoint) = p.parent

coordinate(P::AbsAffineRationalPoint, i::Int) = coordinates(P)[i]
getindex(P::AbsAffineRationalPoint, i::Int) = coordinate(P, i)


@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 ambient scheme.
"""
coordinates(p::AffineRationalPoint) = p.coordinates

function (X::AbsSpec)(coordinates::Vector; check::Bool=true)
k = base_ring(X)
coordinates = k.(coordinates)
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 ", Lowercase(), ambient_scheme(P), Dedent())
print(io, "with coordinates (")
join(io, coordinates(P), ", ")
print(io, ")")
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(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(ambient_scheme(P), h))
end


@doc raw"""
ideal(P::AbsAffineRationalPoint)

Return the maximal ideal associated to `P` in the coordinate ring
of its ambient space.
"""
function ideal(P::AbsAffineRationalPoint)
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)
set_attribute!(I, :is_absolutely_prime=>true)
return I
end

function _in(P::AbsAffineRationalPoint, X::AbsSpec{<:Any,<:MPolyRing})
# X is affine space
return ambient_space(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(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(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(scheme(P), X)
end

function Base.in(P::AbsAffineRationalPoint, X::AbsSpec)
codomain(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

Return the rational point ``P`` viewed as a reduced, affine subscheme
of its ambient affine space.
"""
function scheme(P::AbsAffineRationalPoint)
I = ideal(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 ambient scheme `X`.
"""
function closed_embedding(P::AbsAffineRationalPoint)
I = ideal(P)
X = ambient_scheme(P)
return ClosedEmbedding(X, I)
end


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 codomain(f)(imgs; check=false)
end

function MPolyComplementOfKPointIdeal(P::AbsAffineRationalPoint)
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(codomain(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 ambient scheme ``X``.
"""
is_smooth(P::AbsAffineRationalPoint) = is_smooth_at(codomain(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 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(codomain(P), P)

@doc raw"""
is_du_val_singularity(P::AbsAffineRationalPoint{<:Field})

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(codomain(P), ideal(P))

@doc raw"""
decide_du_val_singularity(P::AbsAffineRationalPoint{<:Field})

Return whether the ambient scheme 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(codomain(P), ideal(P))
return d[1][1],d[1][3]
end
45 changes: 45 additions & 0 deletions src/AlgebraicGeometry/RationalPoint/PointSet.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

@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

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
Loading
Loading