Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
""" Projective curves.
EXAMPLES:
We can construct curves in either a projective plane::
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: C = Curve([y*z^2 - x^3], P); C Projective Plane Curve over Rational Field defined by -x^3 + y*z^2
or in higher dimensional projective spaces::
sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: C = Curve([y*w^3 - x^4, z*w^3 - x^4], P); C Projective Curve over Rational Field defined by -x^4 + y*w^3, -x^4 + z*w^3
AUTHORS:
- William Stein (2005-11-13)
- David Joyner (2005-11-13)
- David Kohel (2006-01)
- Moritz Minzlaff (2010-11)
- Grayson Jorgenson (2016-8) """
#***************************************************************************** # Copyright (C) 2005 William Stein <wstein@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ #***************************************************************************** from __future__ import division from __future__ import absolute_import
from sage.categories.fields import Fields from sage.categories.number_fields import NumberFields from sage.categories.homset import Hom, End from sage.interfaces.all import singular from sage.matrix.constructor import matrix from sage.misc.all import add, sage_eval from sage.rings.all import degree_lowest_rational_function from sage.rings.number_field.number_field import NumberField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.qqbar import (number_field_elements_from_algebraics, QQbar) from sage.rings.rational_field import is_RationalField from sage.schemes.affine.affine_space import AffineSpace from sage.schemes.projective.projective_space import ProjectiveSpace, is_ProjectiveSpace
from . import point
from sage.schemes.projective.projective_subscheme import AlgebraicScheme_subscheme_projective from sage.schemes.projective.projective_space import (is_ProjectiveSpace, ProjectiveSpace)
from .curve import Curve_generic
class ProjectiveCurve(Curve_generic, AlgebraicScheme_subscheme_projective):
_point = point.ProjectiveCurvePoint_field
def _repr_type(self): r""" Return a string representation of the type of this curve.
EXAMPLES::
sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: C = Curve([y^3 - z^3 - w^3, z*x^3 - y^4]) sage: C._repr_type() 'Projective' """
def __init__(self, A, X): r""" Initialization function.
EXAMPLES::
sage: P.<x,y,z,w,u> = ProjectiveSpace(GF(7), 4) sage: C = Curve([y*u^2 - x^3, z*u^2 - x^3, w*u^2 - x^3, y^3 - x^3], P); C Projective Curve over Finite Field of size 7 defined by -x^3 + y*u^2, -x^3 + z*u^2, -x^3 + w*u^2, -x^3 + y^3
::
sage: K.<u> = CyclotomicField(11) sage: P.<x,y,z,w> = ProjectiveSpace(K, 3) sage: C = Curve([y*w - u*z^2 - x^2, x*w - 3*u^2*z*w], P); C Projective Curve over Cyclotomic Field of order 11 and degree 10 defined by -x^2 + (-u)*z^2 + y*w, x*w + (-3*u^2)*z*w """ raise TypeError("A (=%s) must be a projective space"%A) raise ValueError("defining equations (=%s) define a scheme of dimension %s != 1"%(X,d))
def affine_patch(self, i, AA=None): r""" Return the i-th affine patch of this projective curve.
INPUT:
- ``i`` -- affine coordinate chart of the projective ambient space of this curve to compute affine patch with respect to.
- ``AA`` -- (default: None) ambient affine space, this is constructed if it is not given.
OUTPUT:
- a curve in affine space.
EXAMPLES::
sage: P.<x,y,z,w> = ProjectiveSpace(CC, 3) sage: C = Curve([y*z - x^2, w^2 - x*y], P) sage: C.affine_patch(0) Affine Curve over Complex Field with 53 bits of precision defined by x0*x1 - 1.00000000000000, x2^2 - x0
::
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: C = Curve(x^3 - x^2*y + y^3 - x^2*z, P) sage: C.affine_patch(1) Affine Plane Curve over Rational Field defined by x0^3 - x0^2*x1 - x0^2 + 1
::
sage: A.<x,y> = AffineSpace(QQ, 2) sage: P.<u,v,w> = ProjectiveSpace(QQ, 2) sage: C = Curve([u^2 - v^2], P) sage: C.affine_patch(1, A).ambient_space() == A True """
def projection(self, P=None, PS=None): r""" Return a projection of this curve into projective space of dimension one less than the dimension of the ambient space of this curve.
This curve must not already be a plane curve. Over finite fields, if this curve contains all points in its ambient space, then an error will be returned.
INPUT:
- ``P`` -- (default: None) a point not on this curve that will be used to define the projection map; this is constructed if not specified.
- ``PS`` -- (default: None) the projective space the projected curve will be defined in. This space must be defined over the same base ring as this curve, and must have dimension one less than that of the ambient space of this curve. This space will be constructed if not specified.
OUTPUT:
- a tuple consisting of two elements: a scheme morphism from this curve into a projective space of dimension one less than that of the ambient space of this curve, and the projective curve that is the image of that morphism.
EXAMPLES::
sage: K.<a> = CyclotomicField(3) sage: P.<x,y,z,w> = ProjectiveSpace(K, 3) sage: C = Curve([y*w - x^2, z*w^2 - a*x^3], P) sage: L.<a,b,c> = ProjectiveSpace(K, 2) sage: proj1 = C.projection(PS=L) sage: proj1 (Scheme morphism: From: Projective Curve over Cyclotomic Field of order 3 and degree 2 defined by -x^2 + y*w, (-a)*x^3 + z*w^2 To: Projective Space of dimension 2 over Cyclotomic Field of order 3 and degree 2 Defn: Defined on coordinates by sending (x : y : z : w) to (x : y : -z + w), Projective Plane Curve over Cyclotomic Field of order 3 and degree 2 defined by a^6 + (-a)*a^3*b^3 - a^4*b*c) sage: proj1[1].ambient_space() is L True sage: proj2 = C.projection() sage: proj2[1].ambient_space() is L False
::
sage: P.<x,y,z,w,a,b,c> = ProjectiveSpace(QQ, 6) sage: C = Curve([y - x, z - a - b, w^2 - c^2, z - x - a, x^2 - w*z], P) sage: C.projection() (Scheme morphism: From: Projective Curve over Rational Field defined by -x + y, z - a - b, w^2 - c^2, -x + z - a, x^2 - z*w To: Projective Space of dimension 5 over Rational Field Defn: Defined on coordinates by sending (x : y : z : w : a : b : c) to (x : y : -z + w : a : b : c), Projective Curve over Rational Field defined by x1 - x4, x0 - x4, x2*x3 + x3^2 + x2*x4 + 2*x3*x4, x2^2 - x3^2 - 2*x3*x4 + x4^2 - x5^2, x2*x4^2 + x3*x4^2 + x4^3 - x3*x5^2 - x4*x5^2, x4^4 - x3^2*x5^2 - 2*x3*x4*x5^2 - x4^2*x5^2)
::
sage: P.<x,y,z,w> = ProjectiveSpace(GF(2), 3) sage: C = P.curve([(x - y)*(x - z)*(x - w)*(y - z)*(y - w), x*y*z*w*(x+y+z+w)]) sage: C.projection() Traceback (most recent call last): ... NotImplementedError: this curve contains all points of its ambient space
::
sage: P.<x,y,z,w,u> = ProjectiveSpace(GF(7), 4) sage: C = P.curve([x^3 - y*z*u, w^2 - u^2 + 2*x*z, 3*x*w - y^2]) sage: L.<a,b,c,d> = ProjectiveSpace(GF(7), 3) sage: C.projection(PS=L) (Scheme morphism: From: Projective Curve over Finite Field of size 7 defined by x^3 - y*z*u, 2*x*z + w^2 - u^2, -y^2 + 3*x*w To: Projective Space of dimension 3 over Finite Field of size 7 Defn: Defined on coordinates by sending (x : y : z : w : u) to (x : y : z : w), Projective Curve over Finite Field of size 7 defined by b^2 - 3*a*d, a^5*b + a*b*c^3*d - 3*b*c^2*d^3, a^6 + a^2*c^3*d - 3*a*c^2*d^3) sage: Q.<a,b,c> = ProjectiveSpace(GF(7), 2) sage: C.projection(PS=Q) Traceback (most recent call last): ... TypeError: (=Projective Space of dimension 2 over Finite Field of size 7) must have dimension (=3)
::
sage: PP.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: C = PP.curve([x^3 - z^2*y, w^2 - z*x]) sage: Q = PP([1,0,1,1]) sage: C.projection(P=Q) (Scheme morphism: From: Projective Curve over Rational Field defined by x^3 - y*z^2, -x*z + w^2 To: Projective Space of dimension 2 over Rational Field Defn: Defined on coordinates by sending (x : y : z : w) to (y : -x + z : -x + w), Projective Plane Curve over Rational Field defined by x0*x1^5 - 6*x0*x1^4*x2 + 14*x0*x1^3*x2^2 - 16*x0*x1^2*x2^3 + 9*x0*x1*x2^4 - 2*x0*x2^5 - x2^6) sage: LL.<a,b,c> = ProjectiveSpace(QQ, 2) sage: Q = PP([0,0,0,1]) sage: C.projection(PS=LL, P=Q) (Scheme morphism: From: Projective Curve over Rational Field defined by x^3 - y*z^2, -x*z + w^2 To: Projective Space of dimension 2 over Rational Field Defn: Defined on coordinates by sending (x : y : z : w) to (x : y : z), Projective Plane Curve over Rational Field defined by a^3 - b*c^2) sage: Q = PP([0,0,1,0]) sage: C.projection(P=Q) Traceback (most recent call last): ... TypeError: (=(0 : 0 : 1 : 0)) must be a point not on this curve
::
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: C = P.curve(y^2 - x^2 + z^2) sage: C.projection() Traceback (most recent call last): ... TypeError: this curve is already a plane curve """ raise TypeError("this curve must be defined over a field") raise TypeError("(=%s) must be a projective space"%PS) raise TypeError("(=%s) must be defined over the same base field as this curve"%PS) # find a point not on the curve if not given # when working over a characteristic 0 field, we can construct a point not on the curve. # we do this by constructing a point on which at least one nonzero element of the defining ideal of # this curve does not vanish # find a nonzero element # find a point on which it doesn't vanish else: # if the base ring is a finite field, iterate over all points in the ambient space and check which # are on this curve else: # make sure the given point is in the ambient space of the curve, but not on the curve except TypeError: raise TypeError("(=%s) must be a point in the ambient space of this curve"%P) # in order to create the change of coordinates map, need to find a coordinate of Q that is nonzero # use this Q to project. Apply a change of coordinates to move Q to (0:...:0:1:0:...:0) # where 1 is in the jth coordinate else: # compute image of psi via elimination # first construct the image of this curve by the change of coordinates. This can be found by composing the # defining polynomials of this curve with the polynomials defining the inverse of the change of coordinates
def plane_projection(self, PP=None): r""" Return a projection of this curve into a projective plane.
INPUT:
- ``PP`` -- (default: None) the projective plane the projected curve will be defined in. This space must be defined over the same base field as this curve, and must have dimension two. This space is constructed if not specified.
OUTPUT:
- a tuple consisting of two elements: a scheme morphism from this curve into a projective plane, and the projective curve that is the image of that morphism.
EXAMPLES::
sage: P.<x,y,z,w,u,v> = ProjectiveSpace(QQ, 5) sage: C = P.curve([x*u - z*v, w - y, w*y - x^2, y^3*u*2*z - w^4*w]) sage: L.<a,b,c> = ProjectiveSpace(QQ, 2) sage: proj1 = C.plane_projection(PP=L) sage: proj1 (Scheme morphism: From: Projective Curve over Rational Field defined by x*u - z*v, -y + w, -x^2 + y*w, -w^5 + 2*y^3*z*u To: Projective Space of dimension 2 over Rational Field Defn: Defined on coordinates by sending (x : y : z : w : u : v) to (x : -z + u : -z + v), Projective Plane Curve over Rational Field defined by a^8 + 6*a^7*b + 4*a^5*b^3 - 4*a^7*c - 2*a^6*b*c - 4*a^5*b^2*c + 2*a^6*c^2) sage: proj1[1].ambient_space() is L True sage: proj2 = C.projection() sage: proj2[1].ambient_space() is L False
::
sage: P.<x,y,z,w,u> = ProjectiveSpace(GF(7), 4) sage: C = P.curve([x^2 - 6*y^2, w*z*u - y^3 + 4*y^2*z, u^2 - x^2]) sage: C.plane_projection() (Scheme morphism: From: Projective Curve over Finite Field of size 7 defined by x^2 + y^2, -y^3 - 3*y^2*z + z*w*u, -x^2 + u^2 To: Projective Space of dimension 2 over Finite Field of size 7 Defn: Defined on coordinates by sending (x : y : z : w : u) to (y : z : -x + w), Projective Plane Curve over Finite Field of size 7 defined by x0^10 - 2*x0^9*x1 + 3*x0^8*x1^2 - 2*x0^7*x1^3 + x0^6*x1^4 + 2*x0^6*x1^2*x2^2 - 2*x0^5*x1^3*x2^2 - x0^4*x1^4*x2^2 + x0^2*x1^4*x2^4)
::
sage: P.<x,y,z> = ProjectiveSpace(GF(17), 2) sage: C = P.curve(x^2 - y*z - z^2) sage: C.plane_projection() Traceback (most recent call last): ... TypeError: this curve is already a plane curve """ else: # compose the scheme morphisms that are created
def arithmetic_genus(self): r""" Return the arithmetic genus of this projective curve.
This is the arithmetic genus `g_a(C)` as defined in [Hartshorne]_. If `P` is the Hilbert polynomial of the defining ideal of this curve, then the arithmetic genus of this curve is `1 - P(0)`. This curve must be irreducible.
OUTPUT: Integer.
EXAMPLES::
sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: C = P.curve([w*z - x^2, w^2 + y^2 + z^2]) sage: C.arithmetic_genus() 1
::
sage: P.<x,y,z,w,t> = ProjectiveSpace(GF(7), 4) sage: C = P.curve([t^3 - x*y*w, x^3 + y^3 + z^3, z - w]) sage: C.arithmetic_genus() 10 """ raise TypeError("this curve must be irreducible")
def is_complete_intersection(self): r""" Return whether this projective curve is or is not a complete intersection.
OUTPUT: Boolean.
EXAMPLES::
sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: C = Curve([x*y - z*w, x^2 - y*w, y^2*w - x*z*w], P) sage: C.is_complete_intersection() False
::
sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: C = Curve([y*w - x^2, z*w^2 - x^3], P) sage: C.is_complete_intersection() True
sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: C = Curve([z^2 - y*w, y*z - x*w, y^2 - x*z], P) sage: C.is_complete_intersection() False """
class ProjectivePlaneCurve(ProjectiveCurve):
_point = point.ProjectivePlaneCurvePoint_field
def __init__(self, A, f): r""" Initialization function.
EXAMPLES::
sage: P.<x,y,z> = ProjectiveSpace(QQbar, 2) sage: C = Curve([y*z - x^2 - QQbar.gen()*z^2], P); C Projective Plane Curve over Algebraic Field defined by -x^2 + y*z + (-I)*z^2
::
sage: P.<x,y,z> = ProjectiveSpace(GF(5^2, 'v'), 2) sage: C = Curve([y^2*z - x*z^2 - z^3], P); C Projective Plane Curve over Finite Field in v of size 5^2 defined by y^2*z - x*z^2 - z^3 """ raise TypeError("Argument A (= %s) must be a projective plane."%A)
def _repr_type(self): r""" Return a string representation of the type of this curve.
EXAMPLES::
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: C = Curve([y*z^3 - 5/7*x^4 + 4*x^3*z - 9*z^4], P) sage: C._repr_type() 'Projective Plane' """
def arithmetic_genus(self): r""" Return the arithmetic genus of this projective curve.
This is the arithmetic genus `g_a(C)` as defined in [Hartshorne]_. For a projective plane curve of degree `d`, this is simply `(d-1)(d-2)/2`. It need *not* equal the geometric genus (the genus of the normalization of the curve). This curve must be irreducible.
OUTPUT: Integer.
EXAMPLES::
sage: x,y,z = PolynomialRing(GF(5), 3, 'xyz').gens() sage: C = Curve(y^2*z^7 - x^9 - x*z^8); C Projective Plane Curve over Finite Field of size 5 defined by -x^9 + y^2*z^7 - x*z^8 sage: C.arithmetic_genus() 28 sage: C.genus() 4
::
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: C = Curve([y^3*x - x^2*y*z - 7*z^4]) sage: C.arithmetic_genus() 3
REFERENCES:
.. [Hartshorne] \R. Hartshorne. Algebraic Geometry. Springer-Verlag, New York, 1977. """ raise TypeError("this curve must be irreducible")
def divisor_of_function(self, r): """ Return the divisor of a function on a curve.
INPUT: r is a rational function on X
OUTPUT:
- ``list`` - The divisor of r represented as a list of coefficients and points. (TODO: This will change to a more structural output in the future.)
EXAMPLES::
sage: FF = FiniteField(5) sage: P2 = ProjectiveSpace(2, FF, names = ['x','y','z']) sage: R = P2.coordinate_ring() sage: x, y, z = R.gens() sage: f = y^2*z^7 - x^9 - x*z^8 sage: C = Curve(f) sage: K = FractionField(R) sage: r = 1/x sage: C.divisor_of_function(r) # todo: not implemented !!!! [[-1, (0, 0, 1)]] sage: r = 1/x^3 sage: C.divisor_of_function(r) # todo: not implemented !!!! [[-3, (0, 0, 1)]] """ F = self.base_ring() f = self.defining_polynomial() x, y, z = f.parent().gens() pnts = self.rational_points() divf = [] for P in pnts: if P[2] != F(0): # What is the '5' in this line and the 'r()' in the next??? lcs = self.local_coordinates(P,5) ldg = degree_lowest_rational_function(r(lcs[0],lcs[1]),z) if ldg[0] != 0: divf.append([ldg[0],P]) return divf
def local_coordinates(self, pt, n): r""" Return local coordinates to precision n at the given point.
Behaviour is flaky - some choices of `n` are worst that others.
INPUT:
- ``pt`` - an F-rational point on X which is not a point of ramification for the projection (x,y) - x.
- ``n`` - the number of terms desired
OUTPUT: x = x0 + t y = y0 + power series in t
EXAMPLES::
sage: FF = FiniteField(5) sage: P2 = ProjectiveSpace(2, FF, names = ['x','y','z']) sage: x, y, z = P2.coordinate_ring().gens() sage: C = Curve(y^2*z^7-x^9-x*z^8) sage: pt = C([2,3,1]) sage: C.local_coordinates(pt,9) # todo: not implemented !!!! [2 + t, 3 + 3*t^2 + t^3 + 3*t^4 + 3*t^6 + 3*t^7 + t^8 + 2*t^9 + 3*t^11 + 3*t^12] """
f = self.defining_polynomial() R = f.parent() F = self.base_ring() p = F.characteristic() x0 = F(pt[0]) y0 = F(pt[1]) astr = ["a"+str(i) for i in range(1,2*n)] x,y = R.gens() R0 = PolynomialRing(F,2*n+2,names = [str(x),str(y),"t"]+astr) vars0 = R0.gens() t = vars0[2] yt = y0*t**0 + add([vars0[i]*t**(i-2) for i in range(3,2*n+2)]) xt = x0+t ft = f(xt,yt) S = singular S.eval('ring s = '+str(p)+','+str(R0.gens())+',lp;') S.eval('poly f = '+str(ft)) cmd = 'matrix c = coeffs ('+str(ft)+',t)' S.eval(cmd) N = int(S.eval('size(c)')) b = ["c["+str(i)+",1]," for i in range(2, N//2 - 4)] b = ''.join(b) b = b[:len(b)-1] #to cut off the trailing comma cmd = 'ideal I = '+b S.eval(cmd) c = S.eval('slimgb(I)') d = c.split("=") d = d[1:] d[len(d)-1] += "\n" e = [x[:x.index("\n")] for x in d] vals = [] for x in e: for y in vars0: if str(y) in x: if len(x.replace(str(y),"")) != 0: i = x.find("-") if i>0: vals.append([eval(x[1:i]),x[:i],F(eval(x[i+1:]))]) i = x.find("+") if i>0: vals.append([eval(x[1:i]),x[:i],-F(eval(x[i+1:]))]) else: vals.append([eval(str(y)[1:]),str(y),F(0)]) vals.sort() k = len(vals) v = [x0+t,y0+add([vals[i][2]*t**(i+1) for i in range(k)])] return v
def plot(self, *args, **kwds): """ Plot the real points of an affine patch of this projective plane curve.
INPUT:
- ``self`` - an affine plane curve
- ``patch`` - (optional) the affine patch to be plotted; if not specified, the patch corresponding to the last projective coordinate being nonzero
- ``*args`` - optional tuples (variable, minimum, maximum) for plotting dimensions
- ``**kwds`` - optional keyword arguments passed on to ``implicit_plot``
EXAMPLES:
A cuspidal curve::
sage: R.<x, y, z> = QQ[] sage: C = Curve(x^3 - y^2*z) sage: C.plot() Graphics object consisting of 1 graphics primitive
The other affine patches of the same curve::
sage: C.plot(patch=0) Graphics object consisting of 1 graphics primitive sage: C.plot(patch=1) Graphics object consisting of 1 graphics primitive
An elliptic curve::
sage: E = EllipticCurve('101a') sage: C = Curve(E) sage: C.plot() Graphics object consisting of 1 graphics primitive sage: C.plot(patch=0) Graphics object consisting of 1 graphics primitive sage: C.plot(patch=1) Graphics object consisting of 1 graphics primitive
A hyperelliptic curve::
sage: P.<x> = QQ[] sage: f = 4*x^5 - 30*x^3 + 45*x - 22 sage: C = HyperellipticCurve(f) sage: C.plot() Graphics object consisting of 1 graphics primitive sage: C.plot(patch=0) Graphics object consisting of 1 graphics primitive sage: C.plot(patch=1) Graphics object consisting of 1 graphics primitive """ # if user hasn't specified a favourite affine patch, take the # one avoiding "infinity", i.e. the one corresponding to the # last projective coordinate being nonzero
def is_singular(self, P=None): r""" Return whether this curve is singular or not, or if a point ``P`` is provided, whether ``P`` is a singular point of this curve.
INPUT:
- ``P`` -- (default: None) a point on this curve.
OUTPUT:
- Boolean. If no point ``P`` is provided, returns True of False depending on whether this curve is singular or not. If a point ``P`` is provided, returns True or False depending on whether ``P`` is or is not a singular point of this curve.
EXAMPLES:
Over `\QQ`::
sage: F = QQ sage: P2.<X,Y,Z> = ProjectiveSpace(F,2) sage: C = Curve(X^3-Y^2*Z) sage: C.is_singular() True
Over a finite field::
sage: F = GF(19) sage: P2.<X,Y,Z> = ProjectiveSpace(F,2) sage: C = Curve(X^3+Y^3+Z^3) sage: C.is_singular() False sage: D = Curve(X^4-X*Z^3) sage: D.is_singular() True sage: E = Curve(X^5+19*Y^5+Z^5) sage: E.is_singular() True sage: E = Curve(X^5+9*Y^5+Z^5) sage: E.is_singular() False
Over `\CC`::
sage: F = CC sage: P2.<X,Y,Z> = ProjectiveSpace(F,2) sage: C = Curve(X) sage: C.is_singular() False sage: D = Curve(Y^2*Z-X^3) sage: D.is_singular() True sage: E = Curve(Y^2*Z-X^3+Z^3) sage: E.is_singular() False
Showing that :trac:`12187` is fixed::
sage: F.<X,Y,Z> = GF(2)[] sage: G = Curve(X^2+Y*Z) sage: G.is_singular() False
::
sage: P.<x,y,z> = ProjectiveSpace(CC, 2) sage: C = Curve([y^4 - x^3*z], P) sage: Q = P([0,0,1]) sage: C.is_singular() True """ else:
def degree(self): r""" Return the degree of this projective curve.
For a plane curve, this is just the degree of its defining polynomial.
OUTPUT: integer.
EXAMPLES::
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: C = P.curve([y^7 - x^2*z^5 + 7*z^7]) sage: C.degree() 7 """
def tangents(self, P, factor=True): r""" Return the tangents of this projective plane curve at the point ``P``.
These are found by homogenizing the tangents of an affine patch of this curve containing ``P``. The point ``P`` must be a point on this curve.
INPUT:
- ``P`` -- a point on this curve.
- ``factor`` -- (default: True) whether to attempt computing the polynomials of the individual tangent lines over the base field of this curve, or to just return the polynomial corresponding to the union of the tangent lines (which requires fewer computations).
OUTPUT:
- a list of polynomials in the coordinate ring of the ambient space of this curve.
EXAMPLES::
sage: set_verbose(-1) sage: P.<x,y,z> = ProjectiveSpace(QQbar, 2) sage: C = Curve([x^3*y + 2*x^2*y^2 + x*y^3 + x^3*z + 7*x^2*y*z + 14*x*y^2*z + 9*y^3*z], P) sage: Q = P([0,0,1]) sage: C.tangents(Q) [x + 4.147899035704788?*y, x + (1.426050482147607? + 0.3689894074818041?*I)*y, x + (1.426050482147607? - 0.3689894074818041?*I)*y] sage: C.tangents(Q, factor=False) [6*x^3 + 42*x^2*y + 84*x*y^2 + 54*y^3]
::
sage: P.<x,y,z> = ProjectiveSpace(QQ,2) sage: C = P.curve([x^2*y^3*z^4 - y^6*z^3 - 4*x^2*y^4*z^3 - 4*x^4*y^2*z^3 + 3*y^7*z^2 +\ 10*x^2*y^5*z^2 + 9*x^4*y^3*z^2 + 5*x^6*y*z^2 - 3*y^8*z - 9*x^2*y^6*z - 11*x^4*y^4*z -\ 7*x^6*y^2*z - 2*x^8*z + y^9 + 2*x^2*y^7 + 3*x^4*y^5 + 4*x^6*y^3 + 2*x^8*y]) sage: Q = P([0,1,1]) sage: C.tangents(Q) [-y + z, 3*x^2 - y^2 + 2*y*z - z^2]
::
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: C = P.curve([z^3*x + y^4 - x^2*z^2]) sage: Q = P([1,1,1]) sage: C.tangents(Q) Traceback (most recent call last): ... TypeError: (=(1 : 1 : 1)) is not a point on (=Projective Plane Curve over Rational Field defined by y^4 - x^2*z^2 + x*z^3) """ # Check whether P is a point on this curve
# Find an affine chart of the ambient space of self that contains P
def is_ordinary_singularity(self, P): r""" Return whether the singular point ``P`` of this projective plane curve is an ordinary singularity.
The point ``P`` is an ordinary singularity of this curve if it is a singular point, and if the tangents of this curve at ``P`` are distinct.
INPUT:
- ``P`` -- a point on this curve.
OUTPUT:
- Boolean. True or False depending on whether ``P`` is or is not an ordinary singularity of this curve, respectively. An error is raised if ``P`` is not a singular point of this curve.
EXAMPLES::
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: C = Curve([y^2*z^3 - x^5], P) sage: Q = P([0,0,1]) sage: C.is_ordinary_singularity(Q) False
::
sage: R.<a> = QQ[] sage: K.<b> = NumberField(a^2 - 3) sage: P.<x,y,z> = ProjectiveSpace(K, 2) sage: C = P.curve([x^2*y^3*z^4 - y^6*z^3 - 4*x^2*y^4*z^3 - 4*x^4*y^2*z^3 + 3*y^7*z^2 + 10*x^2*y^5*z^2\ + 9*x^4*y^3*z^2 + 5*x^6*y*z^2 - 3*y^8*z - 9*x^2*y^6*z - 11*x^4*y^4*z - 7*x^6*y^2*z - 2*x^8*z + y^9 +\ 2*x^2*y^7 + 3*x^4*y^5 + 4*x^6*y^3 + 2*x^8*y]) sage: Q = P([0,1,1]) sage: C.is_ordinary_singularity(Q) True
::
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: C = P.curve([z^5 - y^5 + x^5 + x*y^2*z^2]) sage: Q = P([0,1,1]) sage: C.is_ordinary_singularity(Q) Traceback (most recent call last): ... TypeError: (=(0 : 1 : 1)) is not a singular point of (=Projective Plane Curve over Rational Field defined by x^5 - y^5 + x*y^2*z^2 + z^5) """
# Find an affine chart of the ambient space of self that contains P
def quadratic_transform(self): r""" Return a birational map from this curve to the proper transform of this curve with respect to the standard Cremona transformation.
The standard Cremona transformation is the birational automorphism of `\mathbb{P}^{2}` defined `(x : y : z)\mapsto (yz : xz : xy)`.
OUTPUT:
- a scheme morphism representing the restriction of the standard Cremona transformation from this curve to the proper transform.
EXAMPLES::
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: C = Curve(x^3*y - z^4 - z^2*x^2, P) sage: C.quadratic_transform() Scheme morphism: From: Projective Plane Curve over Rational Field defined by x^3*y - x^2*z^2 - z^4 To: Projective Plane Curve over Rational Field defined by -x^3*y - x*y*z^2 + z^4 Defn: Defined on coordinates by sending (x : y : z) to (y*z : x*z : x*y)
::
sage: P.<x,y,z> = ProjectiveSpace(GF(17), 2) sage: C = P.curve([y^7*z^2 - 16*x^9 + x*y*z^7 + 2*z^9]) sage: C.quadratic_transform() Scheme morphism: From: Projective Plane Curve over Finite Field of size 17 defined by x^9 + y^7*z^2 + x*y*z^7 + 2*z^9 To: Projective Plane Curve over Finite Field of size 17 defined by 2*x^9*y^7 + x^8*y^6*z^2 + x^9*z^7 + y^7*z^9 Defn: Defined on coordinates by sending (x : y : z) to (y*z : x*z : x*y) """ # remove the component of the curve corresponding to the exceptional divisor
def excellent_position(self, Q): r""" Return a transformation of this curve into one in excellent position with respect to the point ``Q``.
Here excellent position is defined as in [Fulton89]_. A curve `C` of degree `d` containing the point `(0 : 0 : 1)` with multiplicity `r` is said to be in excellent position if none of the coordinate lines are tangent to `C` at any of the fundamental points `(1 : 0 : 0)`, `(0 : 1 : 0)`, and `(0 : 0 : 1)`, and if the two coordinate lines containing `(0 : 0 : 1)` intersect `C` transversally in `d - r` distinct non-fundamental points, and if the other coordinate line intersects `C` transversally at `d` distinct, non-fundamental points.
INPUT:
- ``Q`` -- a point on this curve.
OUTPUT:
- a scheme morphism from this curve to a curve in excellent position that is a restriction of a change of coordinates map of the projective plane.
EXAMPLES::
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: C = Curve([x*y - z^2], P) sage: Q = P([1,1,1]) sage: C.excellent_position(Q) Scheme morphism: From: Projective Plane Curve over Rational Field defined by x*y - z^2 To: Projective Plane Curve over Rational Field defined by -x^2 - 3*x*y - 4*y^2 - x*z - 3*y*z Defn: Defined on coordinates by sending (x : y : z) to (-x + 1/2*y + 1/2*z : -1/2*y + 1/2*z : x + 1/2*y - 1/2*z)
::
sage: R.<a> = QQ[] sage: K.<b> = NumberField(a^2 - 3) sage: P.<x,y,z> = ProjectiveSpace(K, 2) sage: C = P.curve([z^2*y^3*x^4 - y^6*x^3 - 4*z^2*y^4*x^3 - 4*z^4*y^2*x^3 + 3*y^7*x^2 + 10*z^2*y^5*x^2\ + 9*z^4*y^3*x^2 + 5*z^6*y*x^2 - 3*y^8*x - 9*z^2*y^6*x - 11*z^4*y^4*x - 7*z^6*y^2*x - 2*z^8*x + y^9 +\ 2*z^2*y^7 + 3*z^4*y^5 + 4*z^6*y^3 + 2*z^8*y]) sage: Q = P([1,0,0]) sage: C.excellent_position(Q) Scheme morphism: From: Projective Plane Curve over Number Field in b with defining polynomial a^2 - 3 defined by -x^3*y^6 + 3*x^2*y^7 - 3*x*y^8 + y^9 + x^4*y^3*z^2 - 4*x^3*y^4*z^2 + 10*x^2*y^5*z^2 - 9*x*y^6*z^2 + 2*y^7*z^2 - 4*x^3*y^2*z^4 + 9*x^2*y^3*z^4 - 11*x*y^4*z^4 + 3*y^5*z^4 + 5*x^2*y*z^6 - 7*x*y^2*z^6 + 4*y^3*z^6 - 2*x*z^8 + 2*y*z^8 To: Projective Plane Curve over Number Field in b with defining polynomial a^2 - 3 defined by 900*x^9 - 7410*x^8*y + 29282*x^7*y^2 - 69710*x^6*y^3 + 110818*x^5*y^4 - 123178*x^4*y^5 + 96550*x^3*y^6 - 52570*x^2*y^7 + 18194*x*y^8 - 3388*y^9 - 1550*x^8*z + 9892*x^7*y*z - 30756*x^6*y^2*z + 58692*x^5*y^3*z - 75600*x^4*y^4*z + 67916*x^3*y^5*z - 42364*x^2*y^6*z + 16844*x*y^7*z - 3586*y^8*z + 786*x^7*z^2 - 3958*x^6*y*z^2 + 9746*x^5*y^2*z^2 - 14694*x^4*y^3*z^2 + 15174*x^3*y^4*z^2 - 10802*x^2*y^5*z^2 + 5014*x*y^6*z^2 - 1266*y^7*z^2 - 144*x^6*z^3 + 512*x^5*y*z^3 - 912*x^4*y^2*z^3 + 1024*x^3*y^3*z^3 - 816*x^2*y^4*z^3 + 512*x*y^5*z^3 - 176*y^6*z^3 + 8*x^5*z^4 - 8*x^4*y*z^4 - 16*x^3*y^2*z^4 + 16*x^2*y^3*z^4 + 8*x*y^4*z^4 - 8*y^5*z^4 Defn: Defined on coordinates by sending (x : y : z) to (1/4*y + 1/2*z : -1/4*y + 1/2*z : x + 1/4*y - 1/2*z)
::
sage: set_verbose(-1) sage: a = QQbar(sqrt(2)) sage: P.<x,y,z> = ProjectiveSpace(QQbar, 2) sage: C = Curve([(-1/4*a)*x^3 + (-3/4*a)*x^2*y + (-3/4*a)*x*y^2 + (-1/4*a)*y^3 - 2*x*y*z], P) sage: Q = P([0,0,1]) sage: C.excellent_position(Q) Scheme morphism: From: Projective Plane Curve over Algebraic Field defined by (-0.3535533905932738?)*x^3 + (-1.060660171779822?)*x^2*y + (-1.060660171779822?)*x*y^2 + (-0.3535533905932738?)*y^3 + (-2)*x*y*z To: Projective Plane Curve over Algebraic Field defined by (-2.828427124746190?)*x^3 + (-2)*x^2*y + 2*y^3 + (-2)*x^2*z + 2*y^2*z Defn: Defined on coordinates by sending (x : y : z) to (1/2*x + 1/2*y : (-1/2)*x + 1/2*y : 1/2*x + (-1/2)*y + z)
REFERENCES:
.. [Fulton89] \W. Fulton. Algebraic curves: an introduction to algebraic geometry. Addison-Wesley, Redwood City CA (1989). """ # check that Q is on this curve except TypeError: raise TypeError("(=%s) must be a point on this curve"%Q) # first move Q to (0 : 0 : 1), (1 : 0 : 0), or (0 : 1 : 0) # this makes it easier to construct the main transformation # choose points forming a triangle with one vertex at P to map to the coordinate triangle # find points to map to (1 : 0 : 0) and (0 : 1 : 0), not on the curve Py = baseC(Py) continue # by construction, P, Px, Py are linearly independent so the following matrix is invertible # M defines a change of coordinates sending (1 : 0 : 0) to Py, (0 : 1 : 0) to Px, (0 : 0 : 1) to P; the # inverse of the transformation we want, used to create the new defining polynomial # check tangents at (0 : 0 : 1) continue # check that the other intersections of C with the exceptional lines are correct # this is a homogeneous polynomial in the other two variables # and so should factor completely into homogeneous linear factors # each corresponding to an intersection point where the jth coord is 0. # check if there are enough roots, up to multiplicity (that is, that PP.gens()[j] # doesn't divide the defining polynomial of C) need_continue = True break # if j != 2, then there should be d - r multiplicity 1 roots, # besides the root corresponding to (0 : 0 : 1) # if j == 2, then all roots should have multiplicity 1 # since (0 : 0 : 1) has multiplicity r, divide out by the highest # shared power of the corresponding variable before doing the resultant computations npoly.dict().items()])) else: npoly.dict().items()])) # check the degree again need_continue = True break # check that npoly isn't a constant now else: t = t + 1 need_continue = True break # check that intersections with the line PP.gens()[j] are transverse. # at a simple point P of the curve, the tangent at that point is # given by F_x(P)*x + F_y(P)*y + F_z(P)*z where F is the defining polynomial # of the curve # maybe a stricter check than necessary need_continue = True break # coords for map
def ordinary_model(self): r""" Return a birational map from this curve to a plane curve with only ordinary singularities.
Currently only implemented over number fields. If not all of the coordinates of the non-ordinary singularities of this curve are contained in its base field, then the domain and codomain of the map returned will be defined over an extension. This curve must be irreducible.
OUTPUT:
- a scheme morphism from this curve to a curve with only ordinary singularities that defines a birational map between the two curves.
EXAMPLES::
sage: set_verbose(-1) sage: K = QuadraticField(3) sage: P.<x,y,z> = ProjectiveSpace(K, 2) sage: C = Curve([x^5 - K.0*y*z^4], P) sage: C.ordinary_model() Scheme morphism: From: Projective Plane Curve over Number Field in a with defining polynomial x^2 - 3 defined by x^5 + (-a)*y*z^4 To: Projective Plane Curve over Number Field in a with defining polynomial x^2 - 3 defined by (-a)*x^5*y + (-4*a)*x^4*y^2 + (-6*a)*x^3*y^3 + (-4*a)*x^2*y^4 + (-a)*x*y^5 + (-a - 1)*x^5*z + (-4*a + 5)*x^4*y*z + (-6*a - 10)*x^3*y^2*z + (-4*a + 10)*x^2*y^3*z + (-a - 5)*x*y^4*z + y^5*z Defn: Defined on coordinates by sending (x : y : z) to (-1/4*x^2 - 1/2*x*y + 1/2*x*z + 1/2*y*z - 1/4*z^2 : 1/4*x^2 + 1/2*x*y + 1/2*y*z - 1/4*z^2 : -1/4*x^2 + 1/4*z^2)
::
sage: set_verbose(-1) sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: C = Curve([y^2*z^2 - x^4 - x^3*z], P) sage: D = C.ordinary_model(); D # long time (2 seconds) Scheme morphism: From: Projective Plane Curve over Rational Field defined by -x^4 - x^3*z + y^2*z^2 To: Projective Plane Curve over Rational Field defined by 4*x^6*y^3 - 24*x^5*y^4 + 36*x^4*y^5 + 8*x^6*y^2*z - 40*x^5*y^3*z + 24*x^4*y^4*z + 72*x^3*y^5*z - 4*x^6*y*z^2 + 8*x^5*y^2*z^2 - 56*x^4*y^3*z^2 + 104*x^3*y^4*z^2 + 44*x^2*y^5*z^2 + 8*x^6*z^3 - 16*x^5*y*z^3 - 24*x^4*y^2*z^3 + 40*x^3*y^3*z^3 + 48*x^2*y^4*z^3 + 8*x*y^5*z^3 - 8*x^5*z^4 + 36*x^4*y*z^4 - 56*x^3*y^2*z^4 + 20*x^2*y^3*z^4 + 40*x*y^4*z^4 - 16*y^5*z^4 Defn: Defined on coordinates by sending (x : y : z) to (-3/64*x^4 + 9/64*x^2*y^2 - 3/32*x*y^3 - 1/16*x^3*z - 1/8*x^2*y*z + 1/4*x*y^2*z - 1/16*y^3*z - 1/8*x*y*z^2 + 1/16*y^2*z^2 : -1/64*x^4 + 3/64*x^2*y^2 - 1/32*x*y^3 + 1/16*x*y^2*z - 1/16*y^3*z + 1/16*y^2*z^2 : 3/64*x^4 - 3/32*x^3*y + 3/64*x^2*y^2 + 1/16*x^3*z - 3/16*x^2*y*z + 1/8*x*y^2*z - 1/8*x*y*z^2 + 1/16*y^2*z^2) sage: all([D.codomain().is_ordinary_singularity(Q) for Q in D.codomain().singular_points()]) # long time True
::
sage: set_verbose(-1) sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: C = Curve([(x^2 + y^2 - y*z - 2*z^2)*(y*z - x^2 + 2*z^2)*z + y^5], P) sage: C.ordinary_model() # long time (5 seconds) Scheme morphism: From: Projective Plane Curve over Number Field in a with defining polynomial y^2 - 2 defined by y^5 - x^4*z - x^2*y^2*z + 2*x^2*y*z^2 + y^3*z^2 + 4*x^2*z^3 + y^2*z^3 - 4*y*z^4 - 4*z^5 To: Projective Plane Curve over Number Field in a with defining polynomial y^2 - 2 defined by (-29*a + 1)*x^8*y^6 + (10*a + 158)*x^7*y^7 + (-109*a - 31)*x^6*y^8 + (-80*a - 198)*x^8*y^5*z + (531*a + 272)*x^7*y^6*z + (170*a - 718)*x^6*y^7*z + (19*a - 636)*x^5*y^8*z + (-200*a - 628)*x^8*y^4*z^2 + (1557*a - 114)*x^7*y^5*z^2 + (2197*a - 2449)*x^6*y^6*z^2 + (1223*a - 3800)*x^5*y^7*z^2 + (343*a - 1329)*x^4*y^8*z^2 + (-323*a - 809)*x^8*y^3*z^3 + (1630*a - 631)*x^7*y^4*z^3 + (4190*a - 3126)*x^6*y^5*z^3 + (3904*a - 7110)*x^5*y^6*z^3 + (1789*a - 5161)*x^4*y^7*z^3 + (330*a - 1083)*x^3*y^8*z^3 + (-259*a - 524)*x^8*y^2*z^4 + (720*a - 605)*x^7*y^3*z^4 + (3082*a - 2011)*x^6*y^4*z^4 + (4548*a - 5462)*x^5*y^5*z^4 + (2958*a - 6611)*x^4*y^6*z^4 + (994*a - 2931)*x^3*y^7*z^4 + (117*a - 416)*x^2*y^8*z^4 + (-108*a - 184)*x^8*y*z^5 + (169*a - 168)*x^7*y^2*z^5 + (831*a - 835)*x^6*y^3*z^5 + (2225*a - 1725)*x^5*y^4*z^5 + (1970*a - 3316)*x^4*y^5*z^5 + (952*a - 2442)*x^3*y^6*z^5 + (217*a - 725)*x^2*y^7*z^5 + (16*a - 77)*x*y^8*z^5 + (-23*a - 35)*x^8*z^6 + (43*a + 24)*x^7*y*z^6 + (21*a - 198)*x^6*y^2*z^6 + (377*a - 179)*x^5*y^3*z^6 + (458*a - 537)*x^4*y^4*z^6 + (288*a - 624)*x^3*y^5*z^6 + (100*a - 299)*x^2*y^6*z^6 + (16*a - 67)*x*y^7*z^6 - 5*y^8*z^6 Defn: Defined on coordinates by sending (x : y : z) to ((-5/128*a - 5/128)*x^4 + (-5/32*a + 5/32)*x^3*y + (-1/16*a + 3/32)*x^2*y^2 + (1/16*a - 1/16)*x*y^3 + (1/32*a - 1/32)*y^4 - 1/32*x^3*z + (3/16*a - 5/8)*x^2*y*z + (1/8*a - 5/16)*x*y^2*z + (1/8*a + 5/32)*x^2*z^2 + (-3/16*a + 5/16)*x*y*z^2 + (-3/16*a - 1/16)*y^2*z^2 + 1/16*x*z^3 + (1/4*a + 1/4)*y*z^3 + (-3/32*a - 5/32)*z^4 : (-5/128*a - 5/128)*x^4 + (5/32*a)*x^3*y + (3/32*a + 3/32)*x^2*y^2 + (-1/16*a)*x*y^3 + (-1/32*a - 1/32)*y^4 - 1/32*x^3*z + (-11/32*a)*x^2*y*z + (1/8*a + 5/16)*x*y^2*z + (3/16*a + 1/4)*y^3*z + (1/8*a + 5/32)*x^2*z^2 + (-1/16*a - 3/8)*x*y*z^2 + (-3/8*a - 9/16)*y^2*z^2 + 1/16*x*z^3 + (5/16*a + 1/2)*y*z^3 + (-3/32*a - 5/32)*z^4 : (1/64*a + 3/128)*x^4 + (-1/32*a - 1/32)*x^3*y + (3/32*a - 9/32)*x^2*y^2 + (1/16*a - 3/16)*x*y^3 - 1/32*y^4 + (3/32*a + 1/8)*x^2*y*z + (-1/8*a + 1/8)*x*y^2*z + (-1/16*a)*y^3*z + (-1/16*a - 3/32)*x^2*z^2 + (1/16*a + 1/16)*x*y*z^2 + (3/16*a + 3/16)*y^2*z^2 + (-3/16*a - 1/4)*y*z^3 + (1/16*a + 3/32)*z^4) """ # helper function for extending the base field else: if is_RationalField(F): return F.embeddings(K)[0] else: # make sure the defining polynomial variable names are the same for K, N N = NumberField(K.defining_polynomial().parent()(F.defining_polynomial()), str(K.gen())) return N.composite_fields(K, both_maps=True)[0][1]*F.embeddings(N)[0] raise NotImplementedError("the base ring of this curve must be a number field") raise TypeError("this curve must be irreducible") # extend the base field if necessary to find all singular points pts.pop(i) # transform the old points # find image if it is a point the composition map is defined on pts.pop(i) if not PP(list(temp_pt)) in [PP(list(tpt)) for tpt in pts]: pts.append(temp_pt) # add points from the intersection of C and the line z # make sure the conversion happens in the right order # avoid duplicates if not PP(list(pt)) in [PP(list(tpt)) for tpt in pts]: pts.append(pt)
def is_transverse(self, C, P): r""" Return whether the intersection of this curve with the curve ``C`` at the point ``P`` is transverse.
The intersection at ``P`` is transverse if ``P`` is a nonsingular point of both curves, and if the tangents of the curves at ``P`` are distinct.
INPUT:
- ``C`` -- a curve in the ambient space of this curve.
- ``P`` -- a point in the intersection of both curves.
OUTPUT: Boolean.
EXAMPLES::
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: C = Curve([x^2 - y^2], P) sage: D = Curve([x - y], P) sage: Q = P([1,1,0]) sage: C.is_transverse(D, Q) False
::
sage: K = QuadraticField(-1) sage: P.<x,y,z> = ProjectiveSpace(K, 2) sage: C = Curve([y^2*z - K.0*x^3], P) sage: D = Curve([z*x + y^2], P) sage: Q = P([0,0,1]) sage: C.is_transverse(D, Q) False
::
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: C = Curve([x^2 - 2*y^2 - 2*z^2], P) sage: D = Curve([y - z], P) sage: Q = P([2,1,1]) sage: C.is_transverse(D, Q) True """ raise TypeError("(=%s) must be a point in the intersection of (=%s) and this curve"%(P,C))
# there is only one tangent at a nonsingular point of a plane curve
def fundamental_group(self): r""" Return a presentation of the fundamental group of the complement of ``self``.
.. NOTE::
The curve must be defined over the rationals or a number field with an embedding over `\QQbar`.
EXAMPLES::
sage: P.<x,y,z> = ProjectiveSpace(QQ,2) sage: C = P.curve(x^2*z-y^3) sage: C.fundamental_group() # optional - sirocco Finitely presented group < x0 | x0^3 >
In the case of number fields, they need to have an embedding into the algebraic field::
sage: a = QQ[x](x^2+5).roots(QQbar)[0][0] sage: a -2.236067977499790?*I sage: F = NumberField(a.minpoly(), 'a', embedding=a) sage: P.<x,y,z> = ProjectiveSpace(F, 2) sage: F.inject_variables() Defining a sage: C = P.curve(x^2 + a * y^2) sage: C.fundamental_group() # optional - sirocco Finitely presented group < x0 | >
.. WARNING::
This functionality requires the sirocco package to be installed. """ from sage.schemes.curves.zariski_vankampen import fundamental_group F = self.base_ring() from sage.rings.qqbar import QQbar if QQbar.coerce_map_from(F) is None: raise NotImplementedError("the base field must have an embedding" " to the algebraic field") f = self.affine_patch(2).defining_polynomial() if f.degree() == self.degree(): return fundamental_group(f, projective=True) else: #in this case, the line at infinity is part of the curve, so the complement lies in the affine patch return fundamental_group(f, projective=False)
def rational_parameterization(self): r""" Return a rational parameterization of this curve.
This curve must have rational coefficients and be absolutely irreducible (i.e. irreducible over the algebraic closure of the rational field). The curve must also be rational (have geometric genus zero).
The rational parameterization may have coefficients in a quadratic extension of the rational field.
OUTPUT:
- a birational map between `\mathbb{P}^{1}` and this curve, given as a scheme morphism.
EXAMPLES::
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: C = Curve([y^2*z - x^3], P) sage: C.rational_parameterization() Scheme morphism: From: Projective Space of dimension 1 over Rational Field To: Projective Plane Curve over Rational Field defined by -x^3 + y^2*z Defn: Defined on coordinates by sending (s : t) to (s^2*t : s^3 : t^3)
::
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: C = Curve([x^3 - 4*y*z^2 + x*z^2 - x*y*z], P) sage: C.rational_parameterization() Scheme morphism: From: Projective Space of dimension 1 over Rational Field To: Projective Plane Curve over Rational Field defined by x^3 - x*y*z + x*z^2 - 4*y*z^2 Defn: Defined on coordinates by sending (s : t) to (4*s^2*t + s*t^2 : s^2*t + t^3 : 4*s^3 + s^2*t)
::
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: C = Curve([x^2 + y^2 + z^2], P) sage: C.rational_parameterization() Scheme morphism: From: Projective Space of dimension 1 over Number Field in a with defining polynomial a^2 + 1 To: Projective Plane Curve over Number Field in a with defining polynomial a^2 + 1 defined by x^2 + y^2 + z^2 Defn: Defined on coordinates by sending (s : t) to ((-a)*s^2 + (-a)*t^2 : s^2 - t^2 : 2*s*t) """ raise TypeError("this curve must have geometric genus zero") raise TypeError("this curve must be defined over the rational field")
def riemann_surface(self,**kwargs): r"""Return the complex riemann surface determined by this curve
OUTPUT:
- RiemannSurface object
EXAMPLES::
sage: R.<x,y,z>=QQ[] sage: C=Curve(x^3+3*y^3+5*z^3) sage: C.riemann_surface() Riemann surface defined by polynomial f = x0^3 + 3*x1^3 + 5 = 0, with 53 bits of precision
"""
class ProjectivePlaneCurve_finite_field(ProjectivePlaneCurve):
_point = point.ProjectivePlaneCurvePoint_finite_field
def rational_points_iterator(self): r""" Return a generator object for the rational points on this curve.
INPUT:
- ``self`` -- a projective curve
OUTPUT:
A generator of all the rational points on the curve defined over its base field.
EXAMPLES::
sage: F = GF(37) sage: P2.<X,Y,Z> = ProjectiveSpace(F,2) sage: C = Curve(X^7+Y*X*Z^5*55+Y^7*12) sage: len(list(C.rational_points_iterator())) 37
::
sage: F = GF(2) sage: P2.<X,Y,Z> = ProjectiveSpace(F,2) sage: C = Curve(X*Y*Z) sage: a = C.rational_points_iterator() sage: next(a) (1 : 0 : 0) sage: next(a) (0 : 1 : 0) sage: next(a) (1 : 1 : 0) sage: next(a) (0 : 0 : 1) sage: next(a) (1 : 0 : 1) sage: next(a) (0 : 1 : 1) sage: next(a) Traceback (most recent call last): ... StopIteration
::
sage: F = GF(3^2,'a') sage: P2.<X,Y,Z> = ProjectiveSpace(F,2) sage: C = Curve(X^3+5*Y^2*Z-33*X*Y*X) sage: b = C.rational_points_iterator() sage: next(b) (0 : 1 : 0) sage: next(b) (0 : 0 : 1) sage: next(b) (2*a + 2 : a : 1) sage: next(b) (2 : a + 1 : 1) sage: next(b) (a + 1 : 2*a + 1 : 1) sage: next(b) (1 : 2 : 1) sage: next(b) (2*a + 2 : 2*a : 1) sage: next(b) (2 : 2*a + 2 : 1) sage: next(b) (a + 1 : a + 2 : 1) sage: next(b) (1 : 1 : 1) sage: next(b) Traceback (most recent call last): ... StopIteration
"""
# the point with Z = 0 = Y
# points with Z = 0, Y = 1 else:
# points with Z = 1 else:
def rational_points(self, algorithm="enum", sort=True): r""" Return the rational points on this curve computed via enumeration.
INPUT:
- ``algorithm`` (string, default: 'enum') -- the algorithm to use. Currently this is ignored.
- ``sort`` (boolean, default ``True``) -- whether the output points should be sorted. If False, the order of the output is non-deterministic.
OUTPUT:
A list of all the rational points on the curve defined over its base field, possibly sorted.
.. note::
This is a slow Python-level implementation.
EXAMPLES::
sage: F = GF(7) sage: P2.<X,Y,Z> = ProjectiveSpace(F,2) sage: C = Curve(X^3+Y^3-Z^3) sage: C.rational_points() [(0 : 1 : 1), (0 : 2 : 1), (0 : 4 : 1), (1 : 0 : 1), (2 : 0 : 1), (3 : 1 : 0), (4 : 0 : 1), (5 : 1 : 0), (6 : 1 : 0)]
::
sage: F = GF(1237) sage: P2.<X,Y,Z> = ProjectiveSpace(F,2) sage: C = Curve(X^7+7*Y^6*Z+Z^4*X^2*Y*89) sage: len(C.rational_points()) 1237
::
sage: F = GF(2^6,'a') sage: P2.<X,Y,Z> = ProjectiveSpace(F,2) sage: C = Curve(X^5+11*X*Y*Z^3 + X^2*Y^3 - 13*Y^2*Z^3) sage: len(C.rational_points()) 104
::
sage: R.<x,y,z> = GF(2)[] sage: f = x^3*y + y^3*z + x*z^3 sage: C = Curve(f); pts = C.rational_points() sage: pts [(0 : 0 : 1), (0 : 1 : 0), (1 : 0 : 0)]
"""
class ProjectivePlaneCurve_prime_finite_field(ProjectivePlaneCurve_finite_field): def _points_via_singular(self, sort=True): r""" Return all rational points on this curve, computed using Singular's Brill-Noether implementation.
INPUT:
- ``sort`` - bool (default: True), if True return the point list sorted. If False, returns the points in the order computed by Singular.
EXAMPLES::
sage: x, y, z = PolynomialRing(GF(5), 3, 'xyz').gens() sage: f = y^2*z^7 - x^9 - x*z^8 sage: C = Curve(f); C Projective Plane Curve over Finite Field of size 5 defined by -x^9 + y^2*z^7 - x*z^8 sage: C._points_via_singular() [(0 : 0 : 1), (0 : 1 : 0), (2 : 2 : 1), (2 : 3 : 1), (3 : 1 : 1), (3 : 4 : 1)] sage: C._points_via_singular(sort=False) #random [(0 : 1 : 0), (3 : 1 : 1), (3 : 4 : 1), (2 : 2 : 1), (0 : 0 : 1), (2 : 3 : 1)]
.. note::
The Brill-Noether package does not always work (i.e., the 'bn' algorithm. When it fails a RuntimeError exception is raised. """ except (TypeError, RuntimeError) as s: raise RuntimeError(str(s) + "\n\n ** Unable to use the\ Brill-Noether Singular package to\ compute all points (see above).")
# We use sage_flattened_str_list since iterating through # the entire list through the sage/singular interface directly # would involve hundreds of calls to singular, and timing issues with # the expect interface could crop up. Also, this is vastly # faster (and more robust). for i in range(len(v)//3)] # singular always dehomogenizes with respect to the last variable # so if this variable divides the curve equation, we need to add # points at infinity # remove multiple points
def riemann_roch_basis(self, D): r""" Return a basis for the Riemann-Roch space corresponding to `D`.
This uses Singular's Brill-Noether implementation.
INPUT:
- ``D`` - a divisor
OUTPUT:
A list of function field elements that form a basis of the Riemann-Roch space
EXAMPLES::
sage: R.<x,y,z> = GF(2)[] sage: f = x^3*y + y^3*z + x*z^3 sage: C = Curve(f); pts = C.rational_points() sage: D = C.divisor([ (4, pts[0]), (4, pts[2]) ]) sage: C.riemann_roch_basis(D) [x/y, 1, z/y, z^2/y^2, z/x, z^2/(x*y)]
::
sage: R.<x,y,z> = GF(5)[] sage: f = x^7 + y^7 + z^7 sage: C = Curve(f); pts = C.rational_points() sage: D = C.divisor([ (3, pts[0]), (-1,pts[1]), (10, pts[5]) ]) sage: C.riemann_roch_basis(D) [(-x - 2*y)/(-2*x - 2*y), (-x + z)/(x + y)]
.. NOTE::
Currently this only works over prime field and divisors supported on rational points. """ except (TypeError, RuntimeError) as s: raise RuntimeError(str(s) + "\n\n ** Unable to use the Brill-Noether Singular package to compute all points (see above).") # retrieve list of all computed closed points (possibly of degree >1) # the entire list through the sage/singular interface directly # would involve hundreds of calls to singular, and timing issues with # the expect interface could crop up. Also, this is vastly # faster (and more robust). # retrieve coordinates of rational points # build correct representation of D for singular else: # call singular's brill noether routine and return
def rational_points(self, algorithm="enum", sort=True): r""" INPUT:
- ``algorithm`` - string:
- ``'enum'`` - straightforward enumeration
- ``'bn'`` - via Singular's brnoeth package.
EXAMPLES::
sage: x, y, z = PolynomialRing(GF(5), 3, 'xyz').gens() sage: f = y^2*z^7 - x^9 - x*z^8 sage: C = Curve(f); C Projective Plane Curve over Finite Field of size 5 defined by -x^9 + y^2*z^7 - x*z^8 sage: C.rational_points() [(0 : 0 : 1), (0 : 1 : 0), (2 : 2 : 1), (2 : 3 : 1), (3 : 1 : 1), (3 : 4 : 1)] sage: C = Curve(x - y + z) sage: C.rational_points() [(0 : 1 : 1), (1 : 1 : 0), (1 : 2 : 1), (2 : 3 : 1), (3 : 4 : 1), (4 : 0 : 1)] sage: C = Curve(x*z+z^2) sage: C.rational_points('all') [(0 : 1 : 0), (1 : 0 : 0), (1 : 1 : 0), (2 : 1 : 0), (3 : 1 : 0), (4 : 0 : 1), (4 : 1 : 0), (4 : 1 : 1), (4 : 2 : 1), (4 : 3 : 1), (4 : 4 : 1)]
.. note::
The Brill-Noether package does not always work (i.e., the 'bn' algorithm. When it fails a RuntimeError exception is raised. """
algorithm="enum", sort=sort)
raise RuntimeError("Bug in rational_points -- different\ algorithms give different answers for\ curve %s!"%self)
else:
raise ValueError("No algorithm '%s' known"%algorithm)
def Hasse_bounds(q, genus=1): r""" Return the Hasse-Weil bounds for the cardinality of a nonsingular curve defined over `\GF{q}` of given ``genus``.
INPUT:
- ``q`` (int) -- a prime power
- ``genus`` (int, default 1) -- a non-negative integer,
OUTPUT:
(tuple) The Hasse bounds (lb,ub) for the cardinality of a curve of genus ``genus`` defined over `\GF{q}`.
EXAMPLES::
sage: Hasse_bounds(2) (1, 5) sage: Hasse_bounds(next_prime(10^30)) (999999999999998000000000000058, 1000000000000002000000000000058) """ else: rq = (4*(genus**2)*q).isqrt()
# Fix pickles from changing class names and plane_curves folder name from sage.structure.sage_object import register_unpickle_override register_unpickle_override('sage.schemes.plane_curves.projective_curve', 'ProjectiveCurve_generic', ProjectivePlaneCurve) |