def AffineSpace(n, R=None, names='x'): r""" Return affine space of dimension `n` over the ring `R`. EXAMPLES: The dimension and ring can be given in either order. :: sage: AffineSpace(3, QQ, 'x') Affine Space of dimension 3 over Rational Field sage: AffineSpace(5, QQ, 'x') Affine Space of dimension 5 over Rational Field sage: A = AffineSpace(2, QQ, names='XY'); A Affine Space of dimension 2 over Rational Field sage: A.coordinate_ring() Multivariate Polynomial Ring in X, Y over Rational Field Use the divide operator for base extension. :: sage: AffineSpace(5, names='x')/GF(17) Affine Space of dimension 5 over Finite Field of size 17 The default base ring is `\ZZ`. :: sage: AffineSpace(5, names='x') Affine Space of dimension 5 over Integer Ring There is also an affine space associated to each polynomial ring. :: sage: R = GF(7)['x,y,z'] sage: A = AffineSpace(R); A Affine Space of dimension 3 over Finite Field of size 7 sage: A.coordinate_ring() is R True """ if is_MPolynomialRing(n) and R is None: R = n A = AffineSpace(R.ngens(), R.base_ring(), R.variable_names()) A._coordinate_ring = R return A if isinstance(R, (int, long, Integer)): n, R = R, n if R is None: R = ZZ # default is the integers if names is None: if n == 0: names = '' else: raise TypeError, "You must specify the variables names of the coordinate ring." return AffineSpace_generic(n, R, names)
def Curve(F): """ Return the plane or space curve defined by `F`, where `F` can be either a multivariate polynomial, a list or tuple of polynomials, or an algebraic scheme. If `F` is in two variables the curve is affine, and if it is homogenous in `3` variables, then the curve is projective. EXAMPLE: A projective plane curve :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve(x^3 + y^3 + z^3); C Projective Curve over Rational Field defined by x^3 + y^3 + z^3 sage: C.genus() 1 EXAMPLE: Affine plane curves :: sage: x,y = GF(7)['x,y'].gens() sage: C = Curve(y^2 + x^3 + x^10); C Affine Curve over Finite Field of size 7 defined by x^10 + x^3 + y^2 sage: C.genus() 0 sage: x, y = QQ['x,y'].gens() sage: Curve(x^3 + y^3 + 1) Affine Curve over Rational Field defined by x^3 + y^3 + 1 EXAMPLE: A projective space curve :: sage: x,y,z,w = QQ['x,y,z,w'].gens() sage: C = Curve([x^3 + y^3 - z^3 - w^3, x^5 - y*z^4]); C Projective Space Curve over Rational Field defined by x^3 + y^3 - z^3 - w^3, x^5 - y*z^4 sage: C.genus() 13 EXAMPLE: An affine space curve :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve([y^2 + x^3 + x^10 + z^7, x^2 + y^2]); C Affine Space Curve over Rational Field defined by x^10 + z^7 + x^3 + y^2, x^2 + y^2 sage: C.genus() 47 EXAMPLE: We can also make non-reduced non-irreducible curves. :: sage: x,y,z = QQ['x,y,z'].gens() sage: Curve((x-y)*(x+y)) Projective Conic Curve over Rational Field defined by x^2 - y^2 sage: Curve((x-y)^2*(x+y)^2) Projective Curve over Rational Field defined by x^4 - 2*x^2*y^2 + y^4 EXAMPLE: A union of curves is a curve. :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve(x^3 + y^3 + z^3) sage: D = Curve(x^4 + y^4 + z^4) sage: C.union(D) Projective Curve over Rational Field defined by x^7 + x^4*y^3 + x^3*y^4 + y^7 + x^4*z^3 + y^4*z^3 + x^3*z^4 + y^3*z^4 + z^7 The intersection is not a curve, though it is a scheme. :: sage: X = C.intersection(D); X Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: x^3 + y^3 + z^3, x^4 + y^4 + z^4 Note that the intersection has dimension `0`. :: sage: X.dimension() 0 sage: I = X.defining_ideal(); I Ideal (x^3 + y^3 + z^3, x^4 + y^4 + z^4) of Multivariate Polynomial Ring in x, y, z over Rational Field EXAMPLE: In three variables, the defining equation must be homogeneous. If the parent polynomial ring is in three variables, then the defining ideal must be homogeneous. :: sage: x,y,z = QQ['x,y,z'].gens() sage: Curve(x^2+y^2) Projective Conic Curve over Rational Field defined by x^2 + y^2 sage: Curve(x^2+y^2+z) Traceback (most recent call last): ... TypeError: x^2 + y^2 + z is not a homogeneous polynomial! The defining polynomial must always be nonzero:: sage: P1.<x,y> = ProjectiveSpace(1,GF(5)) sage: Curve(0*x) Traceback (most recent call last): ... ValueError: defining polynomial of curve must be nonzero """ if is_AlgebraicScheme(F): return Curve(F.defining_polynomials()) if isinstance(F, (list, tuple)): if len(F) == 1: return Curve(F[0]) F = Sequence(F) P = F.universe() if not is_MPolynomialRing(P): raise TypeError, "universe of F must be a multivariate polynomial ring" for f in F: if not f.is_homogeneous(): A = AffineSpace(P.ngens(), P.base_ring()) A._coordinate_ring = P return AffineSpaceCurve_generic(A, F) A = ProjectiveSpace(P.ngens()-1, P.base_ring()) A._coordinate_ring = P return ProjectiveSpaceCurve_generic(A, F) if not is_MPolynomial(F): raise TypeError, "F (=%s) must be a multivariate polynomial"%F P = F.parent() k = F.base_ring() if F.parent().ngens() == 2: if F == 0: raise ValueError, "defining polynomial of curve must be nonzero" A2 = AffineSpace(2, P.base_ring()) A2._coordinate_ring = P if is_FiniteField(k): if k.is_prime_field(): return AffineCurve_prime_finite_field(A2, F) else: return AffineCurve_finite_field(A2, F) else: return AffineCurve_generic(A2, F) elif F.parent().ngens() == 3: if F == 0: raise ValueError, "defining polynomial of curve must be nonzero" P2 = ProjectiveSpace(2, P.base_ring()) P2._coordinate_ring = P if F.total_degree() == 2 and k.is_field(): return Conic(F) if is_FiniteField(k): if k.is_prime_field(): return ProjectiveCurve_prime_finite_field(P2, F) else: return ProjectiveCurve_finite_field(P2, F) else: return ProjectiveCurve_generic(P2, F) else: raise TypeError, "Number of variables of F (=%s) must be 2 or 3"%F
def ProjectiveSpace(n, R=None, names='x'): r""" Return projective space of dimension `n` over the ring `R`. EXAMPLES: The dimension and ring can be given in either order. :: sage: ProjectiveSpace(3, QQ) Projective Space of dimension 3 over Rational Field sage: ProjectiveSpace(5, QQ) Projective Space of dimension 5 over Rational Field sage: P = ProjectiveSpace(2, QQ, names='XYZ'); P Projective Space of dimension 2 over Rational Field sage: P.coordinate_ring() Multivariate Polynomial Ring in X, Y, Z over Rational Field The divide operator does base extension. :: sage: ProjectiveSpace(5)/GF(17) Projective Space of dimension 5 over Finite Field of size 17 The default base ring is `\ZZ`. :: sage: ProjectiveSpace(5) Projective Space of dimension 5 over Integer Ring There is also an projective space associated each polynomial ring. :: sage: R = GF(7)['x,y,z'] sage: P = ProjectiveSpace(R); P Projective Space of dimension 2 over Finite Field of size 7 sage: P.coordinate_ring() Multivariate Polynomial Ring in x, y, z over Finite Field of size 7 sage: P.coordinate_ring() is R True :: sage: ProjectiveSpace(3, Zp(5), 'y') Projective Space of dimension 3 over 5-adic Ring with capped relative precision 20 :: sage: ProjectiveSpace(2,QQ,'x,y,z') Projective Space of dimension 2 over Rational Field :: sage: PS.<x,y>=ProjectiveSpace(1,CC) sage: PS Projective Space of dimension 1 over Complex Field with 53 bits of precision Projective spaces are not cached, i.e., there can be several with the same base ring and dimension (to facilitate gluing constructions). """ if is_MPolynomialRing(n) and R is None: A = ProjectiveSpace(n.ngens() - 1, n.base_ring()) A._coordinate_ring = n return A if isinstance(R, (int, long, Integer)): n, R = R, n if R is None: R = ZZ # default is the integers if R in _Fields: if is_FiniteField(R): return ProjectiveSpace_finite_field(n, R, names) if is_RationalField(R): return ProjectiveSpace_rational_field(n, R, names) else: return ProjectiveSpace_field(n, R, names) elif is_CommutativeRing(R): return ProjectiveSpace_ring(n, R, names) else: raise TypeError, "R (=%s) must be a commutative ring" % R
def chord_and_tangent(F, P): """ Use the chord and tangent method to get another point on a cubic. INPUT: - ``F`` -- a homogeneous cubic in three variables with rational coefficients, as a polynomial ring element, defining a smooth plane cubic curve. - ``P`` -- a 3-tuple `(x,y,z)` defining a projective point on the curve `F=0`. OUTPUT: Another point satisfying the equation ``F``. EXAMPLES:: sage: R.<x,y,z> = QQ[] sage: from sage.schemes.elliptic_curves.constructor import chord_and_tangent sage: F = x^3+y^3+60*z^3 sage: chord_and_tangent(F, [1,-1,0]) [1, -1, 0] sage: F = x^3+7*y^3+64*z^3 sage: p0 = [2,2,-1] sage: p1 = chord_and_tangent(F, p0); p1 [5, -3, 1] sage: p2 = chord_and_tangent(F, p1); p2 [1265, -183, -314] TESTS:: sage: F(p2) 0 sage: map(type, p2) [<type 'sage.rings.rational.Rational'>, <type 'sage.rings.rational.Rational'>, <type 'sage.rings.rational.Rational'>] """ # check the input R = F.parent() if not rings.is_MPolynomialRing(R): raise TypeError('equation must be a polynomial') if R.ngens() != 3: raise TypeError('%s is not a polynomial in three variables'%F) if not F.is_homogeneous(): raise TypeError('%s is not a homogeneous polynomial'%F) x, y, z = R.gens() if len(P) != 3: raise TypeError('%s is not a projective point'%P) K = R.base_ring() try: P = [K(c) for c in P] except TypeError: raise TypeError('cannot coerce %s into %s'%(P,K)) if F(P) != 0: raise ValueError('%s is not a point on %s'%(P,F)) # find the tangent to F in P dx = K(F.derivative(x)(P)) dy = K(F.derivative(y)(P)) dz = K(F.derivative(z)(P)) # if dF/dy(P) = 0, change variables so that dF/dy != 0 if dy == 0: if dx != 0: g = F.substitute({x:y, y:x}) Q = [P[1], P[0], P[2]] R = chord_and_tangent(g, Q) return [R[1], R[0], R[2]] elif dz != 0: g = F.substitute({y:z, z:y}) Q = [P[0], P[2], P[1]] R = chord_and_tangent(g, Q) return [R[0], R[2], R[1]] else: raise ValueError('%s is singular at %s'%(F, P)) # t will be our choice of parmeter of the tangent plane # dxP*(x-P[0]) + dyP*(y-P[1]) + dzP*(z-P[2]) # through the point P t = rings.PolynomialRing(K, 't').gen(0) Ft = F(dy*t+P[0], (-dx-dz)*t+P[1], dy*t+P[2]) # Ft has a double zero at t=0 by construction, which we now remove Ft = Ft // t**2 # first case: the third point is at t=infinity if Ft.is_constant(): return projective_point([dy, -dx-dz, dy]) # second case: the third point is at finite t else: assert Ft.degree() == 1 t0 = Ft.roots()[0][0] return projective_point([dy*t0+P[0], (-dx-dz)*t0+P[1], dy*t0+P[2]])
def EllipticCurve_from_cubic(F, P, morphism=True): r""" Construct an elliptic curve from a ternary cubic with a rational point. If you just want the Weierstrass form and are not interested in the morphism then it is easier to use :func:`~sage.schemes.elliptic_curves.jacobian.Jacobian` instead. This will construct the same elliptic curve but you don't have to supply the point ``P``. INPUT: - ``F`` -- a homogeneous cubic in three variables with rational coefficients, as a polynomial ring element, defining a smooth plane cubic curve. - ``P`` -- a 3-tuple `(x,y,z)` defining a projective point on the curve `F=0`. Need not be a flex, but see caveat on output. - ``morphism`` -- boolean (default: ``True``). Whether to return the morphism or just the elliptic curve. OUTPUT: An elliptic curve in long Weierstrass form isomorphic to the curve `F=0`. If ``morphism=True`` is passed, then a birational equivalence between F and the Weierstrass curve is returned. If the point happens to be a flex, then this is an isomorphism. EXAMPLES: First we find that the Fermat cubic is isomorphic to the curve with Cremona label 27a1:: sage: R.<x,y,z> = QQ[] sage: cubic = x^3+y^3+z^3 sage: P = [1,-1,0] sage: E = EllipticCurve_from_cubic(cubic, P, morphism=False); E Elliptic Curve defined by y^2 + 2*x*y + 1/3*y = x^3 - x^2 - 1/3*x - 1/27 over Rational Field sage: E.cremona_label() '27a1' sage: EllipticCurve_from_cubic(cubic, [0,1,-1], morphism=False).cremona_label() '27a1' sage: EllipticCurve_from_cubic(cubic, [1,0,-1], morphism=False).cremona_label() '27a1' Next we find the minimal model and conductor of the Jacobian of the Selmer curve:: sage: R.<a,b,c> = QQ[] sage: cubic = a^3+b^3+60*c^3 sage: P = [1,-1,0] sage: E = EllipticCurve_from_cubic(cubic, P, morphism=False); E Elliptic Curve defined by y^2 + 2*x*y + 20*y = x^3 - x^2 - 20*x - 400/3 over Rational Field sage: E.minimal_model() Elliptic Curve defined by y^2 = x^3 - 24300 over Rational Field sage: E.conductor() 24300 We can also get the birational equivalence to and from the Weierstrass form. We start with an example where ``P`` is a flex and the equivalence is an isomorphism:: sage: f = EllipticCurve_from_cubic(cubic, P, morphism=True) sage: f Scheme morphism: From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: a^3 + b^3 + 60*c^3 To: Elliptic Curve defined by y^2 + 2*x*y + 20*y = x^3 - x^2 - 20*x - 400/3 over Rational Field Defn: Defined on coordinates by sending (a : b : c) to (-c : -b + c : 1/20*a + 1/20*b) sage: finv = f.inverse(); finv Scheme morphism: From: Elliptic Curve defined by y^2 + 2*x*y + 20*y = x^3 - x^2 - 20*x - 400/3 over Rational Field To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: a^3 + b^3 + 60*c^3 Defn: Defined on coordinates by sending (x : y : z) to (x + y + 20*z : -x - y : -x) We verify that `f` maps the chosen point `P=(1,-1,0)` on the cubic to the origin of the elliptic curve:: sage: f([1,-1,0]) (0 : 1 : 0) sage: finv([0,1,0]) (-1 : 1 : 0) To verify the output, we plug in the polynomials to check that this indeed transforms the cubic into Weierstrass form:: sage: cubic(finv.defining_polynomials()) * finv.post_rescaling() -x^3 + x^2*z + 2*x*y*z + y^2*z + 20*x*z^2 + 20*y*z^2 + 400/3*z^3 sage: E.defining_polynomial()(f.defining_polynomials()) * f.post_rescaling() a^3 + b^3 + 60*c^3 If the point is not a flex then the cubic can not be transformed to a Weierstrass equation by a linear transformation. The general birational transformation is quadratic:: sage: cubic = a^3+7*b^3+64*c^3 sage: P = [2,2,-1] sage: f = EllipticCurve_from_cubic(cubic, P, morphism=True) sage: E = f.codomain(); E Elliptic Curve defined by y^2 + 722*x*y + 21870000*y = x^3 + 23579*x^2 over Rational Field sage: E.minimal_model() Elliptic Curve defined by y^2 + y = x^3 - 331 over Rational Field sage: f Scheme morphism: From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: a^3 + 7*b^3 + 64*c^3 To: Elliptic Curve defined by y^2 + 722*x*y + 21870000*y = x^3 + 23579*x^2 over Rational Field Defn: Defined on coordinates by sending (a : b : c) to (-5/112896*a^2 - 17/40320*a*b - 1/1280*b^2 - 29/35280*a*c - 13/5040*b*c - 4/2205*c^2 : 4055/112896*a^2 + 4787/40320*a*b + 91/1280*b^2 + 7769/35280*a*c + 1993/5040*b*c + 724/2205*c^2 : 1/4572288000*a^2 + 1/326592000*a*b + 1/93312000*b^2 + 1/142884000*a*c + 1/20412000*b*c + 1/17860500*c^2) sage: finv = f.inverse(); finv Scheme morphism: From: Elliptic Curve defined by y^2 + 722*x*y + 21870000*y = x^3 + 23579*x^2 over Rational Field To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: a^3 + 7*b^3 + 64*c^3 Defn: Defined on coordinates by sending (x : y : z) to (2*x^2 + 227700*x*z + 900*y*z : 2*x^2 - 32940*x*z - 540*y*z : -x^2 - 56520*x*z + 180*y*z) sage: cubic(finv.defining_polynomials()) * finv.post_rescaling() -x^3 - 23579*x^2*z + 722*x*y*z + y^2*z + 21870000*y*z^2 sage: E.defining_polynomial()(f.defining_polynomials()) * f.post_rescaling() a^3 + 7*b^3 + 64*c^3 """ import sage.matrix.all as matrix # check the input R = F.parent() if not rings.is_MPolynomialRing(R): raise TypeError('equation must be a polynomial') if R.ngens() != 3: raise TypeError('equation must be a polynomial in three variables') if not F.is_homogeneous(): raise TypeError('equation must be a homogeneous polynomial') K = F.parent().base_ring() try: P = [K(c) for c in P] except TypeError: raise TypeError('cannot convert %s into %s'%(P,K)) if F(P) != 0: raise ValueError('%s is not a point on %s'%(P,F)) if len(P) != 3: raise TypeError('%s is not a projective point'%P) x, y, z = R.gens() # First case: if P = P2 then P is a flex P2 = chord_and_tangent(F, P) if are_projectively_equivalent(P, P2, base_ring=K): # find the tangent to F in P dx = K(F.derivative(x)(P)) dy = K(F.derivative(y)(P)) dz = K(F.derivative(z)(P)) # find a second point Q on the tangent line but not on the cubic for tangent in [[dy, -dx, K.zero()], [dz, K.zero(), -dx], [K.zero(), -dz, dx]]: tangent = projective_point(tangent) Q = [tangent[0]+P[0], tangent[1]+P[1], tangent[2]+P[2]] F_Q = F(Q) if F_Q != 0: # At most one further point may accidentally be on the cubic break assert F_Q != 0 # pick linearly independent third point for third_point in [(1,0,0), (0,1,0), (0,0,1)]: M = matrix.matrix(K, [Q, P, third_point]).transpose() if M.is_invertible(): break F2 = R(M.act_on_polynomial(F)) # scale and dehomogenise a = K(F2.coefficient(x**3)) F3 = F2/a b = K(F3.coefficient(y*y*z)) S = rings.PolynomialRing(K, 'x,y,z') # elliptic curve coordinates X, Y, Z = S.gen(0), S.gen(1), S(-1/b)*S.gen(2) F4 = F3(X, Y, Z) E = EllipticCurve(F4.subs(z=1)) if not morphism: return E inv_defining_poly = [ M[i,0]*X + M[i,1]*Y + M[i,2]*Z for i in range(3) ] inv_post = -1/a M = M.inverse() trans_x, trans_y, trans_z = [ M[i,0]*x + M[i,1]*y + M[i,2]*z for i in range(3) ] fwd_defining_poly = [trans_x, trans_y, -b*trans_z] fwd_post = -a # Second case: P is not a flex, then P, P2, P3 are different else: P3 = chord_and_tangent(F, P2) # send P, P2, P3 to (1:0:0), (0:1:0), (0:0:1) respectively M = matrix.matrix(K, [P, P2, P3]).transpose() F2 = M.act_on_polynomial(F) # substitute x = U^2, y = V*W, z = U*W, and rename (x,y,z)=(U,V,W) F3 = F2.substitute({x:x**2, y:y*z, z:x*z}) // (x**2*z) # scale and dehomogenise a = K(F3.coefficient(x**3)) F4 = F3/a b = K(F4.coefficient(y*y*z)) # change to a polynomial in only two variables S = rings.PolynomialRing(K, 'x,y,z') # elliptic curve coordinates X, Y, Z = S.gen(0), S.gen(1), S(-1/b)*S.gen(2) F5 = F4(X, Y, Z) E = EllipticCurve(F5.subs(z=1)) if not morphism: return E inv_defining_poly = [ M[i,0]*X*X + M[i,1]*Y*Z + M[i,2]*X*Z for i in range(3) ] inv_post = -1/a/(X**2)/Z M = M.inverse() trans_x, trans_y, trans_z = [ (M[i,0]*x + M[i,1]*y + M[i,2]*z) for i in range(3) ] fwd_defining_poly = [ trans_x*trans_z, trans_x*trans_y, -b*trans_z*trans_z ] fwd_post = -a/(trans_x*trans_z*trans_z) # Construct the morphism from sage.schemes.projective.projective_space import ProjectiveSpace P2 = ProjectiveSpace(2, K, names=map(str, R.gens())) cubic = P2.subscheme(F) from sage.schemes.elliptic_curves.weierstrass_transform import \ WeierstrassTransformationWithInverse return WeierstrassTransformationWithInverse( cubic, E, fwd_defining_poly, fwd_post, inv_defining_poly, inv_post)
def ProjectiveSpace(n, R=None, names='x'): r""" Return projective space of dimension `n` over the ring `R`. EXAMPLES: The dimension and ring can be given in either order. :: sage: ProjectiveSpace(3, QQ) Projective Space of dimension 3 over Rational Field sage: ProjectiveSpace(5, QQ) Projective Space of dimension 5 over Rational Field sage: P = ProjectiveSpace(2, QQ, names='XYZ'); P Projective Space of dimension 2 over Rational Field sage: P.coordinate_ring() Multivariate Polynomial Ring in X, Y, Z over Rational Field The divide operator does base extension. :: sage: ProjectiveSpace(5)/GF(17) Projective Space of dimension 5 over Finite Field of size 17 The default base ring is `\ZZ`. :: sage: ProjectiveSpace(5) Projective Space of dimension 5 over Integer Ring There is also an projective space associated each polynomial ring. :: sage: R = GF(7)['x,y,z'] sage: P = ProjectiveSpace(R); P Projective Space of dimension 2 over Finite Field of size 7 sage: P.coordinate_ring() Multivariate Polynomial Ring in x, y, z over Finite Field of size 7 sage: P.coordinate_ring() is R True :: sage: ProjectiveSpace(3, Zp(5), 'y') Projective Space of dimension 3 over 5-adic Ring with capped relative precision 20 :: sage: ProjectiveSpace(2,QQ,'x,y,z') Projective Space of dimension 2 over Rational Field :: sage: PS.<x,y>=ProjectiveSpace(1,CC) sage: PS Projective Space of dimension 1 over Complex Field with 53 bits of precision Projective spaces are not cached, i.e., there can be several with the same base ring and dimension (to facilitate gluing constructions). """ if is_MPolynomialRing(n) and R is None: A = ProjectiveSpace(n.ngens()-1, n.base_ring()) A._coordinate_ring = n return A if isinstance(R, (int, long, Integer)): n, R = R, n if R is None: R = ZZ # default is the integers if R in _Fields: if is_FiniteField(R): return ProjectiveSpace_finite_field(n, R, names) if is_RationalField(R): return ProjectiveSpace_rational_field(n, R, names) else: return ProjectiveSpace_field(n, R, names) elif is_CommutativeRing(R): return ProjectiveSpace_ring(n, R, names) else: raise TypeError("R (=%s) must be a commutative ring"%R)
def Curve(F): """ Return the plane or space curve defined by `F`, where `F` can be either a multivariate polynomial, a list or tuple of polynomials, or an algebraic scheme. If `F` is in two variables the curve is affine, and if it is homogenous in `3` variables, then the curve is projective. EXAMPLE: A projective plane curve :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve(x^3 + y^3 + z^3); C Projective Curve over Rational Field defined by x^3 + y^3 + z^3 sage: C.genus() 1 EXAMPLE: Affine plane curves :: sage: x,y = GF(7)['x,y'].gens() sage: C = Curve(y^2 + x^3 + x^10); C Affine Curve over Finite Field of size 7 defined by x^10 + x^3 + y^2 sage: C.genus() 0 sage: x, y = QQ['x,y'].gens() sage: Curve(x^3 + y^3 + 1) Affine Curve over Rational Field defined by x^3 + y^3 + 1 EXAMPLE: A projective space curve :: sage: x,y,z,w = QQ['x,y,z,w'].gens() sage: C = Curve([x^3 + y^3 - z^3 - w^3, x^5 - y*z^4]); C Projective Space Curve over Rational Field defined by x^3 + y^3 - z^3 - w^3, x^5 - y*z^4 sage: C.genus() 13 EXAMPLE: An affine space curve :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve([y^2 + x^3 + x^10 + z^7, x^2 + y^2]); C Affine Space Curve over Rational Field defined by x^10 + z^7 + x^3 + y^2, x^2 + y^2 sage: C.genus() 47 EXAMPLE: We can also make non-reduced non-irreducible curves. :: sage: x,y,z = QQ['x,y,z'].gens() sage: Curve((x-y)*(x+y)) Projective Conic Curve over Rational Field defined by x^2 - y^2 sage: Curve((x-y)^2*(x+y)^2) Projective Curve over Rational Field defined by x^4 - 2*x^2*y^2 + y^4 EXAMPLE: A union of curves is a curve. :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve(x^3 + y^3 + z^3) sage: D = Curve(x^4 + y^4 + z^4) sage: C.union(D) Projective Curve over Rational Field defined by x^7 + x^4*y^3 + x^3*y^4 + y^7 + x^4*z^3 + y^4*z^3 + x^3*z^4 + y^3*z^4 + z^7 The intersection is not a curve, though it is a scheme. :: sage: X = C.intersection(D); X Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: x^3 + y^3 + z^3, x^4 + y^4 + z^4 Note that the intersection has dimension `0`. :: sage: X.dimension() 0 sage: I = X.defining_ideal(); I Ideal (x^3 + y^3 + z^3, x^4 + y^4 + z^4) of Multivariate Polynomial Ring in x, y, z over Rational Field EXAMPLE: In three variables, the defining equation must be homogeneous. If the parent polynomial ring is in three variables, then the defining ideal must be homogeneous. :: sage: x,y,z = QQ['x,y,z'].gens() sage: Curve(x^2+y^2) Projective Conic Curve over Rational Field defined by x^2 + y^2 sage: Curve(x^2+y^2+z) Traceback (most recent call last): ... TypeError: x^2 + y^2 + z is not a homogeneous polynomial! The defining polynomial must always be nonzero:: sage: P1.<x,y> = ProjectiveSpace(1,GF(5)) sage: Curve(0*x) Traceback (most recent call last): ... ValueError: defining polynomial of curve must be nonzero """ if is_AlgebraicScheme(F): return Curve(F.defining_polynomials()) if isinstance(F, (list, tuple)): if len(F) == 1: return Curve(F[0]) F = Sequence(F) P = F.universe() if not is_MPolynomialRing(P): raise TypeError, "universe of F must be a multivariate polynomial ring" for f in F: if not f.is_homogeneous(): A = AffineSpace(P.ngens(), P.base_ring()) A._coordinate_ring = P return AffineSpaceCurve_generic(A, F) A = ProjectiveSpace(P.ngens() - 1, P.base_ring()) A._coordinate_ring = P return ProjectiveSpaceCurve_generic(A, F) if not is_MPolynomial(F): raise TypeError, "F (=%s) must be a multivariate polynomial" % F P = F.parent() k = F.base_ring() if F.parent().ngens() == 2: if F == 0: raise ValueError, "defining polynomial of curve must be nonzero" A2 = AffineSpace(2, P.base_ring()) A2._coordinate_ring = P if is_FiniteField(k): if k.is_prime_field(): return AffineCurve_prime_finite_field(A2, F) else: return AffineCurve_finite_field(A2, F) else: return AffineCurve_generic(A2, F) elif F.parent().ngens() == 3: if F == 0: raise ValueError, "defining polynomial of curve must be nonzero" P2 = ProjectiveSpace(2, P.base_ring()) P2._coordinate_ring = P if F.total_degree() == 2 and k.is_field(): return Conic(F) if is_FiniteField(k): if k.is_prime_field(): return ProjectiveCurve_prime_finite_field(P2, F) else: return ProjectiveCurve_finite_field(P2, F) else: return ProjectiveCurve_generic(P2, F) else: raise TypeError, "Number of variables of F (=%s) must be 2 or 3" % F