Path: blob/master/src/sage/schemes/plane_conics/con_field.py
8820 views
r"""1Projective plane conics over a field23AUTHORS:45- Marco Streng (2010-07-20)67- Nick Alexander (2008-01-08)89"""10#*****************************************************************************11# Copyright (C) 2008 Nick Alexander <[email protected]>12# Copyright (C) 2009/2010 Marco Streng <[email protected]>13#14# Distributed under the terms of the GNU General Public License (GPL)15#16# This code is distributed in the hope that it will be useful,17# but WITHOUT ANY WARRANTY; without even the implied warranty of18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU19# General Public License for more details.20#21# The full text of the GPL is available at:22#23# http://www.gnu.org/licenses/24#*****************************************************************************2526from sage.rings.all import PolynomialRing2728from sage.rings.complex_field import is_ComplexField29from sage.rings.real_mpfr import is_RealField3031from sage.modules.free_module_element import vector32from sage.structure.sequence import Sequence33from sage.structure.element import is_Vector34from sage.schemes.projective.projective_space import ProjectiveSpace35from sage.matrix.constructor import Matrix36from sage.matrix.matrix import is_Matrix3738from sage.schemes.plane_curves.projective_curve import ProjectiveCurve_generic3940from sage.categories.fields import Fields41_Fields = Fields()4243class ProjectiveConic_field(ProjectiveCurve_generic):44r"""45Create a projective plane conic curve over a field.46See ``Conic`` for full documentation.4748EXAMPLES::4950sage: K = FractionField(PolynomialRing(QQ, 't'))51sage: P.<X, Y, Z> = K[]52sage: Conic(X^2 + Y^2 - Z^2)53Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Rational Field defined by X^2 + Y^2 - Z^25455TESTS::5657sage: K = FractionField(PolynomialRing(QQ, 't'))58sage: Conic([K(1), 1, -1])._test_pickling()59"""60def __init__(self, A, f):61r"""62See ``Conic`` for full documentation.6364EXAMPLES:6566::6768sage: c = Conic([1, 1, 1]); c69Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^270"""71ProjectiveCurve_generic.__init__(self, A, f)72self._coefficients = [f[(2,0,0)], f[(1,1,0)], f[(1,0,1)],73f[(0,2,0)], f[(0,1,1)], f[(0,0,2)]]74self._parametrization = None75self._diagonal_matrix = None7677self._rational_point = None7879808182def _repr_type(self):83r"""84Returns ``'Projective Conic'``, which is the first part of the85plain text representation of this object as output by86the function ``_repr_`` of the class ``Curve_generic``.8788EXAMPLES::8990sage: c = Conic([1, 1, 1]); c91Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^292sage: c._repr_()93'Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2'94sage: c._repr_type()95'Projective Conic'96"""97return "Projective Conic"9899def base_extend(self, S):100r"""101Returns the conic over ``S`` given by the same equation as ``self``.102103EXAMPLES::104105sage: c = Conic([1, 1, 1]); c106Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2107sage: c.has_rational_point()108False109sage: d = c.base_extend(QuadraticField(-1, 'i')); d110Projective Conic Curve over Number Field in i with defining polynomial x^2 + 1 defined by x^2 + y^2 + z^2111sage: d.rational_point(algorithm = 'rnfisnorm')112(i : 1 : 0)113"""114if S in _Fields:115B = self.base_ring()116if B == S:117return self118if not S.has_coerce_map_from(B):119raise ValueError, "No natural map from the base ring of self " \120"(= %s) to S (= %s)" % (self, S)121from constructor import Conic122con = Conic([S(c) for c in self.coefficients()], \123self.variable_names())124if self._rational_point != None:125pt = [S(c) for c in Sequence(self._rational_point)]126if not pt == [0,0,0]:127# The following line stores the point in the cache128# if (and only if) there is no point in the cache.129pt = con.point(pt)130return con131return ProjectiveCurve_generic.base_extend(self, S)132133def cache_point(self, p):134r"""135Replace the point in the cache of ``self`` by ``p`` for use136by ``self.rational_point()`` and ``self.parametrization()``.137138EXAMPLES::139140sage: c = Conic([1, -1, 1])141sage: c.point([15, 17, 8])142(15/8 : 17/8 : 1)143sage: c.rational_point()144(15/8 : 17/8 : 1)145sage: c.cache_point(c.rational_point(read_cache = False))146sage: c.rational_point()147(1 : 1 : 0)148"""149if isinstance(p, (tuple, list)):150p = self.point(p)151self._rational_point = p152153def coefficients(self):154r"""155Gives a the `6` coefficients of the conic ``self``156in lexicographic order.157158EXAMPLES::159160sage: Conic(QQ, [1,2,3,4,5,6]).coefficients()161[1, 2, 3, 4, 5, 6]162163sage: P.<x,y,z> = GF(13)[]164sage: a = Conic(x^2+5*x*y+y^2+z^2).coefficients(); a165[1, 5, 0, 1, 0, 1]166sage: Conic(a)167Projective Conic Curve over Finite Field of size 13 defined by x^2 + 5*x*y + y^2 + z^2168"""169return self._coefficients170171172def derivative_matrix(self):173r"""174Gives the derivative of the defining polynomial of175the conic ``self``, which is a linear map,176as a `3 \times 3` matrix.177178EXAMPLES:179180In characteristic different from `2`, the181derivative matrix is twice the symmetric matrix:182183::184185sage: c = Conic(QQ, [1,1,1,1,1,0])186sage: c.symmetric_matrix()187[ 1 1/2 1/2]188[1/2 1 1/2]189[1/2 1/2 0]190sage: c.derivative_matrix()191[2 1 1]192[1 2 1]193[1 1 0]194195An example in characteristic `2`:196197::198199sage: P.<t> = GF(2)[]200sage: c = Conic([t, 1, t^2, 1, 1, 0]); c201Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 2 (using NTL) defined by t*x^2 + x*y + y^2 + t^2*x*z + y*z202sage: c.is_smooth()203True204sage: c.derivative_matrix()205[ 0 1 t^2]206[ 1 0 1]207[t^2 1 0]208"""209from sage.matrix.constructor import matrix210[a,b,c,d,e,f] = self.coefficients()211return matrix([[ 2*a , b , c ],212[ b , 2*d , e ],213[ c , e , 2*f ]])214215def determinant(self):216r"""217Returns the determinant of the symmetric matrix that defines218the conic ``self``.219220This is defined only if the base field has characteristic221different from `2`.222223EXAMPLES:224225::226227sage: C = Conic([1,2,3,4,5,6])228sage: C.determinant()22941/4230sage: C.symmetric_matrix().determinant()23141/4232233Determinants are only defined in characteristic different from `2`::234235sage: C = Conic(GF(2), [1, 1, 1, 1, 1, 0])236sage: C.is_smooth()237True238sage: C.determinant()239Traceback (most recent call last):240...241ValueError: The conic self (= Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y + y^2 + x*z + y*z) has no symmetric matrix because the base field has characteristic 2242"""243return self.symmetric_matrix().determinant()244245def diagonal_matrix(self):246r"""247Returns a diagonal matrix `D` and a matrix `T` such that `T^t A T = D`248holds, where `(x, y, z) A (x, y, z)^t` is the defining polynomial249of the conic ``self``.250251EXAMPLES:252253::254255sage: c = Conic(QQ, [1,2,3,4,5,6])256sage: d, t = c.diagonal_matrix(); d, t257(258[ 1 0 0] [ 1 -1 -7/6]259[ 0 3 0] [ 0 1 -1/3]260[ 0 0 41/12], [ 0 0 1]261)262sage: t.transpose()*c.symmetric_matrix()*t263[ 1 0 0]264[ 0 3 0]265[ 0 0 41/12]266267Diagonal matrices are only defined in characteristic different268from `2`:269270::271272sage: c = Conic(GF(4, 'a'), [0, 1, 1, 1, 1, 1])273sage: c.is_smooth()274True275sage: c.diagonal_matrix()276Traceback (most recent call last):277...278ValueError: The conic self (= Projective Conic Curve over Finite Field in a of size 2^2 defined by x*y + y^2 + x*z + y*z + z^2) has no symmetric matrix because the base field has characteristic 2279"""280A = self.symmetric_matrix()281B = self.base_ring()282basis = [vector(B,{2:0,i:1}) for i in range(3)]283for i in range(3):284zerovalue = (basis[i]*A*basis[i].column()== 0)285if zerovalue:286for j in range(i+1,3):287if basis[j]*A*basis[j].column() != 0:288b = basis[i]289basis[i] = basis[j]290basis[j] = b291zerovalue = False292if zerovalue:293for j in range(i+1,3):294if basis[i]*A*basis[j].column() != 0:295basis[i] = basis[i]+basis[j]296zerovalue = False297if not zerovalue:298l = (basis[i]*A*basis[i].column())299for j in range(i+1,3):300basis[j] = basis[j] - \301(basis[i]*A*basis[j].column())/l * basis[i]302T = Matrix(basis).transpose()303return T.transpose()*A*T, T304305def diagonalization(self,names = None):306r"""307Returns a diagonal conic `C`, an isomorphism of schemes `M: C` -> ``self``308and the inverse `N` of `M`.309310EXAMPLES::311312sage: Conic(GF(5), [1,0,1,1,0,1]).diagonalization()313(Projective Conic Curve over Finite Field of size 5 defined by x^2 + y^2 + 2*z^2,314Scheme morphism:315From: Projective Conic Curve over Finite Field of size 5 defined by x^2 + y^2 + 2*z^2316To: Projective Conic Curve over Finite Field of size 5 defined by x^2 + y^2 + x*z + z^2317Defn: Defined on coordinates by sending (x : y : z) to318(x + 2*z : y : z),319Scheme morphism:320From: Projective Conic Curve over Finite Field of size 5 defined by x^2 + y^2 + x*z + z^2321To: Projective Conic Curve over Finite Field of size 5 defined by x^2 + y^2 + 2*z^2322Defn: Defined on coordinates by sending (x : y : z) to323(x - 2*z : y : z))324325The diagonalization is only defined in characteristic different326from 2:327328::329330sage: Conic(GF(2), [1,1,1,1,1,0]).diagonalization()331Traceback (most recent call last):332...333ValueError: The conic self (= Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y + y^2 + x*z + y*z) has no symmetric matrix because the base field has characteristic 2334"""335if names == None:336names = self.defining_polynomial().parent().variable_names()337from constructor import Conic338D, T = self.diagonal_matrix()339con = Conic(D, names = names)340return con, con.hom(T, self), self.hom(T.inverse(), con)341342def gens(self):343r"""344Returns the generators of the coordinate ring of ``self``.345346EXAMPLES:347348::349350sage: P.<x,y,z> = QQ[]351sage: c = Conic(x^2+y^2+z^2)352sage: c.gens()353(xbar, ybar, zbar)354sage: c.defining_polynomial()(c.gens())3550356357The function ``gens()`` is required for the following construction:358359::360361sage: C.<a,b,c> = Conic(GF(3), [1, 1, 1])362sage: C363Projective Conic Curve over Finite Field of size 3 defined by a^2 + b^2 + c^2364365"""366return self.coordinate_ring().gens()367368def has_rational_point(self, point = False,369algorithm = 'default', read_cache = True):370r"""371Returns True if and only if the conic ``self``372has a point over its base field `B`.373374If ``point`` is True, then returns a second output, which is375a rational point if one exists.376377Points are cached whenever they are found. Cached information378is used if and only if ``read_cache`` is True.379380ALGORITHM:381382The parameter ``algorithm`` specifies the algorithm383to be used:384385- ``'default'`` -- If the base field is real or complex,386use an elementary native Sage implementation.387388- ``'magma'`` (requires Magma to be installed) --389delegates the task to the Magma computer algebra390system.391392EXAMPLES:393394sage: Conic(RR, [1, 1, 1]).has_rational_point()395False396sage: Conic(CC, [1, 1, 1]).has_rational_point()397True398399sage: Conic(RR, [1, 2, -3]).has_rational_point(point = True)400(True, (1.73205080756888 : 0.000000000000000 : 1.00000000000000))401402Conics over polynomial rings can not be solved yet without Magma::403404sage: R.<t> = QQ[]405sage: C = Conic([-2,t^2+1,t^2-1])406sage: C.has_rational_point()407Traceback (most recent call last):408...409NotImplementedError: has_rational_point not implemented for conics over base field Fraction Field of Univariate Polynomial Ring in t over Rational Field410411But they can be solved with Magma::412413sage: C.has_rational_point(algorithm='magma') # optional - magma414True415sage: C.has_rational_point(algorithm='magma', point=True) # optional - magma416(True, (t : 1 : 1))417418sage: D = Conic([t,1,t^2])419sage: D.has_rational_point(algorithm='magma') # optional - magma420False421422TESTS:423424One of the following fields comes with an embedding into the complex425numbers, one does not. Check that they are both handled correctly by426the Magma interface.::427428sage: K.<i> = QuadraticField(-1)429sage: K.coerce_embedding()430Generic morphism:431From: Number Field in i with defining polynomial x^2 + 1432To: Complex Lazy Field433Defn: i -> 1*I434sage: Conic(K, [1,1,1]).rational_point(algorithm='magma') # optional - magma435(-i : 1 : 0)436437sage: x = QQ['x'].gen()438sage: L.<i> = NumberField(x^2+1, embedding=None)439sage: Conic(L, [1,1,1]).rational_point(algorithm='magma') # optional - magma440(-i : 1 : 0)441sage: L == K442False443"""444if read_cache:445if self._rational_point is not None:446if point:447return True, self._rational_point448else:449return True450451B = self.base_ring()452453if algorithm == 'magma':454from sage.interfaces.magma import magma455M = magma(self)456b = M.HasRationalPoint().sage()457if not point:458return b459if not b:460return False, None461M_pt = M.HasRationalPoint(nvals=2)[1]462463# Various attempts will be made to convert `pt` to464# a Sage object. The end result will always be checked465# by self.point().466467pt = [M_pt[1], M_pt[2], M_pt[3]]468469# The first attempt is to use sequences. This is efficient and470# succeeds in cases where the Magma interface fails to convert471# number field elements, because embeddings between number fields472# may be lost on conversion to and from Magma.473# This should deal with all absolute number fields.474try:475return True, self.point([B(c.Eltseq().sage()) for c in pt])476except TypeError:477pass478479# The second attempt tries to split Magma elements into480# numerators and denominators first. This is neccessary481# for the field of rational functions, because (at the moment of482# writing) fraction field elements are not converted automatically483# from Magma to Sage.484try:485return True, self.point( \486[B(c.Numerator().sage()/c.Denominator().sage()) for c in pt])487except (TypeError, NameError):488pass489490# Finally, let the Magma interface handle conversion.491try:492return True, self.point([B(c.sage()) for c in pt])493except (TypeError, NameError):494pass495496raise NotImplementedError, "No correct conversion implemented for converting the Magma point %s on %s to a correct Sage point on self (=%s)" % (M_pt, M, self)497498if algorithm != 'default':499raise ValueError, "Unknown algorithm: %s" % algorithm500501if is_ComplexField(B):502if point:503[_,_,_,d,e,f] = self._coefficients504if d == 0:505return True, self.point([0,1,0])506return True, self.point([0, ((e**2-4*d*f).sqrt()-e)/(2*d), 1],507check = False)508return True509if is_RealField(B):510D, T = self.diagonal_matrix()511[a, b, c] = [D[0,0], D[1,1], D[2,2]]512if a == 0:513ret = True, self.point(T*vector([1,0,0]), check = False)514elif a*c <= 0:515ret = True, self.point(T*vector([(-c/a).sqrt(),0,1]),516check = False)517elif b == 0:518ret = True, self.point(T*vector([0,1,0]), check = False)519elif b*c <= 0:520ret = True, self.point(T*vector([0,(-c/b).sqrt(),0,1]),521check = False)522else:523ret = False, None524if point:525return ret526return ret[0]527raise NotImplementedError, "has_rational_point not implemented for " \528"conics over base field %s" % B529530def has_singular_point(self, point = False):531r"""532Return True if and only if the conic ``self`` has a rational533singular point.534535If ``point`` is True, then also return a rational singular536point (or ``None`` if no such point exists).537538EXAMPLES:539540::541542sage: c = Conic(QQ, [1,0,1]); c543Projective Conic Curve over Rational Field defined by x^2 + z^2544sage: c.has_singular_point(point = True)545(True, (0 : 1 : 0))546547sage: P.<x,y,z> = GF(7)[]548sage: e = Conic((x+y+z)*(x-y+2*z)); e549Projective Conic Curve over Finite Field of size 7 defined by x^2 - y^2 + 3*x*z + y*z + 2*z^2550sage: e.has_singular_point(point = True)551(True, (2 : 4 : 1))552553sage: Conic([1, 1, -1]).has_singular_point()554False555sage: Conic([1, 1, -1]).has_singular_point(point = True)556(False, None)557558``has_singular_point`` is not implemented over all fields559of characteristic `2`. It is implemented over finite fields.560561::562563sage: F.<a> = FiniteField(8)564sage: Conic([a, a+1, 1]).has_singular_point(point = True)565(True, (a + 1 : 0 : 1))566567sage: P.<t> = GF(2)[]568sage: C = Conic(P, [t,t,1]); C569Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 2 (using NTL) defined by t*x^2 + t*y^2 + z^2570sage: C.has_singular_point(point = False)571Traceback (most recent call last):572...573NotImplementedError: Sorry, find singular point on conics not implemented over all fields of characteristic 2.574"""575if not point:576ret = self.has_singular_point(point = True)577return ret[0]578B = self.base_ring()579if B.characteristic() == 2:580[a,b,c,d,e,f] = self.coefficients()581if b == 0 and c == 0 and e == 0:582for i in range(3):583if [a, d, f][i] == 0:584return True, self.point(vector(B, {2:0, i:1}))585if hasattr(a/f, 'is_square') and hasattr(a/f, 'sqrt'):586if (a/f).is_square():587return True, self.point([1,0,(a/f).sqrt()])588if (d/f).is_square():589return True, self.point([0,1,(d/f).sqrt()])590raise NotImplementedError, "Sorry, find singular point on conics not implemented over all fields of characteristic 2."591pt = [e, c, b]592if self.defining_polynomial()(pt) == 0:593return True, self.point(pt)594return False, None595D = self.symmetric_matrix()596if D.determinant() == 0:597return True, self.point(Sequence(D.right_kernel().gen()))598return False, None599600def hom(self, x, Y=None):601r"""602Return the scheme morphism from ``self`` to ``Y`` defined by ``x``.603Here ``x`` can be a matrix or a sequence of polynomials.604If ``Y`` is omitted, then a natural image is found if possible.605606EXAMPLES:607608Here are a few Morphisms given by matrices. In the first609example, ``Y`` is omitted, in the second example, ``Y`` is specified.610611::612613sage: c = Conic([-1, 1, 1])614sage: h = c.hom(Matrix([[1,1,0],[0,1,0],[0,0,1]])); h615Scheme morphism:616From: Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2617To: Projective Conic Curve over Rational Field defined by -x^2 + 2*x*y + z^2618Defn: Defined on coordinates by sending (x : y : z) to619(x + y : y : z)620sage: h([-1, 1, 0])621(0 : 1 : 0)622623sage: c = Conic([-1, 1, 1])624sage: d = Conic([4, 1, -1])625sage: c.hom(Matrix([[0, 0, 1/2], [0, 1, 0], [1, 0, 0]]), d)626Scheme morphism:627From: Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2628To: Projective Conic Curve over Rational Field defined by 4*x^2 + y^2 - z^2629Defn: Defined on coordinates by sending (x : y : z) to630(1/2*z : y : x)631632``ValueError`` is raised if the wrong codomain ``Y`` is specified:633634::635636sage: c = Conic([-1, 1, 1])637sage: c.hom(Matrix([[0, 0, 1/2], [0, 1, 0], [1, 0, 0]]), c)638Traceback (most recent call last):639...640ValueError: The matrix x (= [ 0 0 1/2]641[ 0 1 0]642[ 1 0 0]) does not define a map from self (= Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2) to Y (= Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2)643"""644if is_Matrix(x):645from constructor import Conic646y = x.inverse()647A = y.transpose()*self.matrix()*y648im = Conic(A)649if Y == None:650Y = im651else:652q = Y.defining_polynomial()/im.defining_polynomial()653if not (q.numerator().is_constant()654and q.denominator().is_constant()):655raise ValueError, "The matrix x (= %s) does not define a " \656"map from self (= %s) to Y (= %s)" % \657(x, self, Y)658x = Sequence(x*vector(self.ambient_space().gens()))659return self.Hom(Y)(x, check = False)660return ProjectiveCurve_generic.hom(self, x, Y)661662663def is_diagonal(self):664r"""665Return True if and only if the conic has the form666`a*x^2 + b*y^2 + c*z^2`.667668EXAMPLES:669670::671672sage: c=Conic([1,1,0,1,0,1]); c673Projective Conic Curve over Rational Field defined by x^2 + x*y + y^2 + z^2674sage: d,t = c.diagonal_matrix()675sage: c.is_diagonal()676False677sage: c.diagonalization()[0].is_diagonal()678True679"""680return all([self.coefficients()[i] == 0 for i in [1,2,4]])681682683def is_smooth(self):684r"""685Returns True if and only if ``self`` is smooth.686687EXAMPLES:688689::690691sage: Conic([1,-1,0]).is_smooth()692False693sage: Conic(GF(2),[1,1,1,1,1,0]).is_smooth()694True695"""696if self.base_ring().characteristic() == 2:697[a,b,c,d,e,f] = self.coefficients()698if b == 0 and c == 0 and e == 0:699return False700return self.defining_polynomial()([e, c, b]) != 0701return self.determinant() != 0702703704def _magma_init_(self, magma):705"""706Internal function. Returns a string to initialize this707conic in the Magma subsystem.708709EXAMPLES::710711sage: C = Conic(QQ, [1,2,3])712sage: C._magma_init_(magma) # optional - magma713'Conic([_sage_ref...|1/1,2/1,3/1,0/1,0/1,0/1])'714sage: C = Conic(GF(41), [-1,2,5]) # optional - magma715sage: C._magma_init_(magma) # optional - magma716'Conic([_sage_ref...|GF(41)!40,GF(41)!2,GF(41)!5,GF(41)!0,GF(41)!0,GF(41)!0])'717sage: F.<a> = GF(25)718sage: C = Conic([3,0,1,4,a,2])719sage: C720Projective Conic Curve over Finite Field in a of size 5^2 defined by -2*x^2 - y^2 + x*z + (a)*y*z + 2*z^2721sage: magma(C) # optional - magma722Conic over GF(5^2) defined by7233*X^2 + 4*Y^2 + X*Z + a*Y*Z + 2*Z^2724sage: magma(Conic([1/2,2/3,-4/5,6/7,8/9,-10/11])) # optional - magma725Conic over Rational Field defined by7261/2*X^2 + 2/3*X*Y + 6/7*Y^2 - 4/5*X*Z + 8/9*Y*Z - 10/11*Z^2727sage: R.<x> = Frac(QQ['x'])728sage: magma(Conic([x,1+x,1-x])) # optional - magma729Conic over Univariate rational function field over Rational Field defined by730x*X^2 + (x + 1)*Y^2 + (-x + 1)*Z^2731sage: P.<x> = QQ[]732sage: K.<b> = NumberField(x^3+x+1)733sage: magma(Conic([b,1,2])) # optional - magma734Conic over Number Field with defining polynomial x^3 + x + 1 over the Rational Field defined by735b*X^2 + Y^2 + 2*Z^2736"""737kmn = magma(self.base_ring())._ref()738coeffs = self.coefficients()739magma_coeffs = [coeffs[i]._magma_init_(magma) for i in [0, 3, 5, 1, 4, 2]]740return 'Conic([%s|%s])' % (kmn,','.join(magma_coeffs))741742743def matrix(self):744r"""745Returns a matrix `M` such that `(x, y, z) M (x, y, z)^t`746is the defining equation of ``self``.747748The matrix `M` is upper triangular if the base field has749characteristic `2` and symmetric otherwise.750751EXAMPLES::752753sage: R.<x, y, z> = QQ[]754sage: C = Conic(x^2 + x*y + y^2 + z^2)755sage: C.matrix()756[ 1 1/2 0]757[1/2 1 0]758[ 0 0 1]759760sage: R.<x, y, z> = GF(2)[]761sage: C = Conic(x^2 + x*y + y^2 + x*z + z^2)762sage: C.matrix()763[1 1 1]764[0 1 0]765[0 0 1]766"""767if self.base_ring().characteristic() == 2:768return self.upper_triangular_matrix()769return self.symmetric_matrix()770771_matrix_ = matrix772773def parametrization(self, point=None, morphism=True):774r"""775Return a parametrization `f` of ``self`` together with the776inverse of `f`.777778If ``point`` is specified, then that point is used779for the parametrization. Otherwise, use ``self.rational_point()``780to find a point.781782If ``morphism`` is True, then `f` is returned in the form783of a Scheme morphism. Otherwise, it is a tuple of polynomials784that gives the parametrization.785786EXAMPLES:787788An example over a finite field ::789790sage: c = Conic(GF(2), [1,1,1,1,1,0])791sage: c.parametrization()792(Scheme morphism:793From: Projective Space of dimension 1 over Finite Field of size 2794To: Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y795+ y^2 + x*z + y*z796Defn: Defined on coordinates by sending (x : y) to797(x*y + y^2 : x^2 + x*y : x^2 + x*y + y^2),798Scheme morphism:799From: Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y800+ y^2 + x*z + y*z801To: Projective Space of dimension 1 over Finite Field of size 2802Defn: Defined on coordinates by sending (x : y : z) to803(y : x))804805An example with ``morphism = False`` ::806807sage: R.<x,y,z> = QQ[]808sage: C = Curve(7*x^2 + 2*y*z + z^2)809sage: (p, i) = C.parametrization(morphism = False); (p, i)810([-2*x*y, 7*x^2 + y^2, -2*y^2], [-1/2*x, -1/2*z])811sage: C.defining_polynomial()(p)8120813sage: i[0](p) / i[1](p)814x/y815816A ``ValueError`` is raised if ``self`` has no rational point ::817818sage: C = Conic(x^2 + y^2 + 7*z^2)819sage: C.parametrization()820Traceback (most recent call last):821...822ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + y^2 + 7*z^2 has no rational points over Rational Field!823824A ``ValueError`` is raised if ``self`` is not smooth ::825826sage: C = Conic(x^2 + y^2)827sage: C.parametrization()828Traceback (most recent call last):829...830ValueError: The conic self (=Projective Conic Curve over Rational Field defined by x^2 + y^2) is not smooth, hence does not have a parametrization.831"""832if (not self._parametrization is None) and not point:833par = self._parametrization834else:835if not self.is_smooth():836raise ValueError, "The conic self (=%s) is not smooth, hence does not have a parametrization." % self837if point == None:838point = self.rational_point()839point = Sequence(point)840B = self.base_ring()841Q = PolynomialRing(B, 'x,y')842[x, y] = Q.gens()843gens = self.ambient_space().gens()844P = PolynomialRing(B, 4, ['X', 'Y', 'T0', 'T1'])845[X, Y, T0, T1] = P.gens()846c3 = [j for j in range(2,-1,-1) if point[j] != 0][0]847c1 = [j for j in range(3) if j != c3][0]848c2 = [j for j in range(3) if j != c3 and j != c1][0]849L = [0,0,0]850L[c1] = Y*T1*point[c1] + Y*T0851L[c2] = Y*T1*point[c2] + X*T0852L[c3] = Y*T1*point[c3]853bezout = P(self.defining_polynomial()(L) / T0)854t = [bezout([x,y,0,-1]),bezout([x,y,1,0])]855par = (tuple([Q(p([x,y,t[0],t[1]])/y) for p in L]),856tuple([gens[m]*point[c3]-gens[c3]*point[m]857for m in [c2,c1]]))858if self._parametrization is None:859self._parametrization = par860if not morphism:861return par862P1 = ProjectiveSpace(self.base_ring(), 1, 'x,y')863return P1.hom(par[0],self), self.Hom(P1)(par[1], check = False)864865def point(self, v, check=True):866r"""867Constructs a point on ``self`` corresponding to the input ``v``.868869If ``check`` is True, then checks if ``v`` defines a valid870point on ``self``.871872If no rational point on ``self`` is known yet, then also caches the point873for use by ``self.rational_point()`` and ``self.parametrization()``.874875EXAMPLES ::876877sage: c = Conic([1, -1, 1])878sage: c.point([15, 17, 8])879(15/8 : 17/8 : 1)880sage: c.rational_point()881(15/8 : 17/8 : 1)882sage: d = Conic([1, -1, 1])883sage: d.rational_point()884(1 : 1 : 0)885"""886if is_Vector(v):887v = Sequence(v)888p = ProjectiveCurve_generic.point(self, v, check=check)889if self._rational_point is None:890self._rational_point = p891return p892893894def random_rational_point(self, *args1, **args2):895r"""896Return a random rational point of the conic ``self``.897898ALGORITHM:8999001. Compute a parametrization `f` of ``self`` using901``self.parametrization()``.9022. Computes a random point `(x:y)` on the projective903line.9043. Output `f(x:y)`.905906The coordinates x and y are computed using907``B.random_element``, where ``B`` is the base field of908``self`` and additional arguments to ``random_rational_point``909are passed to ``random_element``.910911If the base field is a finite field, then the912output is uniformly distributed over the points of self.913914EXAMPLES ::915916sage: c = Conic(GF(2), [1,1,1,1,1,0])917sage: [c.random_rational_point() for i in range(10)] # output is random918[(1 : 0 : 1), (1 : 0 : 1), (1 : 0 : 1), (0 : 1 : 1), (1 : 0 : 1), (0 : 0 : 1), (1 : 0 : 1), (1 : 0 : 1), (0 : 0 : 1), (1 : 0 : 1)]919920sage: d = Conic(QQ, [1, 1, -1])921sage: d.random_rational_point(den_bound = 1, num_bound = 5) # output is random922(-24/25 : 7/25 : 1)923924sage: Conic(QQ, [1, 1, 1]).random_rational_point()925Traceback (most recent call last):926...927ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2 has no rational points over Rational Field!928929"""930if not self.is_smooth():931raise NotImplementedError, "Sorry, random points not implemented " \932"for non-smooth conics"933par = self.parametrization()934x = 0935y = 0936B = self.base_ring()937while x == 0 and y == 0:938x = B.random_element(*args1, **args2)939y = B.random_element(*args1, **args2)940return par[0]([x,y])941942943def rational_point(self, algorithm = 'default', read_cache = True):944r"""945Return a point on ``self`` defined over the base field.946947Raises ``ValueError`` if no rational point exists.948949See ``self.has_rational_point`` for the algorithm used950and for the use of the parameters ``algorithm`` and ``read_cache``.951952EXAMPLES:953954Examples over `\QQ` ::955956sage: R.<x,y,z> = QQ[]957sage: C = Conic(7*x^2 + 2*y*z + z^2)958sage: C.rational_point()959(0 : 1 : 0)960961sage: C = Conic(x^2 + 2*y^2 + z^2)962sage: C.rational_point()963Traceback (most recent call last):964...965ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + z^2 has no rational points over Rational Field!966967sage: C = Conic(x^2 + y^2 + 7*z^2)968sage: C.rational_point(algorithm = 'rnfisnorm')969Traceback (most recent call last):970...971ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + y^2 + 7*z^2 has no rational points over Rational Field!972973Examples over number fields ::974975sage: P.<x> = QQ[]976sage: L.<b> = NumberField(x^3-5)977sage: C = Conic(L, [3, 2, -5])978sage: p = C.rational_point(algorithm = 'rnfisnorm')979sage: p # output is random980(60*b^2 - 196*b + 161 : -120*b^2 - 6*b + 361 : 1)981sage: C.defining_polynomial()(list(p))9820983984sage: K.<i> = QuadraticField(-1)985sage: D = Conic(K, [3, 2, 5])986sage: D.rational_point(algorithm = 'rnfisnorm') # output is random987(-3 : 4*i : 1)988989sage: L.<s> = QuadraticField(2)990sage: Conic(QQ, [1, 1, -3]).has_rational_point()991False992sage: E = Conic(L, [1, 1, -3])993sage: E.rational_point() # output is random994(-1 : -s : 1)995996Currently Magma is better at solving conics over number fields than997Sage, so it helps to use the algorithm 'magma' if Magma is installed::998999sage: q = C.rational_point(algorithm = 'magma', read_cache=False) # optional - magma1000sage: q # output is random, optional - magma1001(-1 : -1 : 1)1002sage: C.defining_polynomial()(list(p)) # optional - magma100301004sage: len(str(p)) / len(str(q)) > 2 # optional - magma1005True10061007sage: D.rational_point(algorithm = 'magma', read_cache=False) # random, optional - magma1008(1 : 2*i : 1)10091010sage: E.rational_point(algorithm='magma', read_cache=False) # random, optional - magma1011(-s : 1 : 1)10121013sage: F = Conic([L.gen(), 30, -20])1014sage: q = F.rational_point(algorithm='magma') # optional - magma1015sage: q # output is random, optional - magma1016(-10/7*s + 40/7 : 5/7*s - 6/7 : 1)1017sage: p = F.rational_point(read_cache=False)1018sage: p # output is random1019(788210*s - 1114700 : -171135*s + 242022 : 1)1020sage: len(str(p)) > len(str(q)) # optional - magma1021True10221023sage: Conic([L.gen(), 30, -21]).has_rational_point(algorithm='magma') # optional - magma1024False10251026Examples over finite fields ::10271028sage: F.<a> = FiniteField(7^20)1029sage: C = Conic([1, a, -5]); C1030Projective Conic Curve over Finite Field in a of size 7^20 defined by x^2 + (a)*y^2 + 2*z^21031sage: C.rational_point() # output is random1032(4*a^19 + 5*a^18 + 4*a^17 + a^16 + 6*a^15 + 3*a^13 + 6*a^11 + a^9 + 3*a^8 + 2*a^7 + 4*a^6 + 3*a^5 + 3*a^4 + a^3 + a + 6 : 5*a^18 + a^17 + a^16 + 6*a^15 + 4*a^14 + a^13 + 5*a^12 + 5*a^10 + 2*a^9 + 6*a^8 + 6*a^7 + 6*a^6 + 2*a^4 + 3 : 1)10331034Examples over `\RR` and `\CC` ::10351036sage: Conic(CC, [1, 2, 3]).rational_point()1037(0 : 1.22474487139159*I : 1)10381039sage: Conic(RR, [1, 1, 1]).rational_point()1040Traceback (most recent call last):1041...1042ValueError: Conic Projective Conic Curve over Real Field with 53 bits of precision defined by x^2 + y^2 + z^2 has no rational points over Real Field with 53 bits of precision!1043"""1044bl,pt = self.has_rational_point(point = True, algorithm = algorithm,1045read_cache = read_cache)1046if bl:1047return pt1048raise ValueError, "Conic %s has no rational points over %s!" % \1049(self, self.ambient_space().base_ring())105010511052def singular_point(self):1053r"""1054Returns a singular rational point of ``self``10551056EXAMPLES:10571058::10591060sage: Conic(GF(2), [1,1,1,1,1,1]).singular_point()1061(1 : 1 : 1)10621063``ValueError`` is raised if the conic has no rational singular point10641065::10661067sage: Conic(QQ, [1,1,1,1,1,1]).singular_point()1068Traceback (most recent call last):1069...1070ValueError: The conic self (= Projective Conic Curve over Rational Field defined by x^2 + x*y + y^2 + x*z + y*z + z^2) has no rational singular point1071"""1072b = self.has_singular_point(point = True)1073if not b[0]:1074raise ValueError, "The conic self (= %s) has no rational " \1075"singular point" % self1076return b[1]10771078def symmetric_matrix(self):1079r"""1080The symmetric matrix `M` such that `(x y z) M (x y z)^t`1081is the defining equation of ``self``.10821083EXAMPLES ::10841085sage: R.<x, y, z> = QQ[]1086sage: C = Conic(x^2 + x*y/2 + y^2 + z^2)1087sage: C.symmetric_matrix()1088[ 1 1/4 0]1089[1/4 1 0]1090[ 0 0 1]10911092sage: C = Conic(x^2 + 2*x*y + y^2 + 3*x*z + z^2)1093sage: v = vector([x, y, z])1094sage: v * C.symmetric_matrix() * v1095x^2 + 2*x*y + y^2 + 3*x*z + z^21096"""1097[a,b,c,d,e,f] = self.coefficients()1098if self.base_ring().characteristic() == 2:1099if b == 0 and c == 0 and e == 0:1100return matrix([[a,0,0],[0,d,0],[0,0,f]])1101raise ValueError, "The conic self (= %s) has no symmetric matrix " \1102"because the base field has characteristic 2" % \1103self1104from sage.matrix.constructor import matrix1105return matrix([[ a , b/2, c/2 ],1106[ b/2, d , e/2 ],1107[ c/2, e/2, f ]])110811091110def upper_triangular_matrix(self):1111r"""1112The upper-triangular matrix `M` such that `(x y z) M (x y z)^t`1113is the defining equation of ``self``.11141115EXAMPLES::11161117sage: R.<x, y, z> = QQ[]1118sage: C = Conic(x^2 + x*y + y^2 + z^2)1119sage: C.upper_triangular_matrix()1120[1 1 0]1121[0 1 0]1122[0 0 1]11231124sage: C = Conic(x^2 + 2*x*y + y^2 + 3*x*z + z^2)1125sage: v = vector([x, y, z])1126sage: v * C.upper_triangular_matrix() * v1127x^2 + 2*x*y + y^2 + 3*x*z + z^21128"""1129from sage.matrix.constructor import matrix1130[a,b,c,d,e,f] = self.coefficients()1131return matrix([[ a, b, c ],1132[ 0, d, e ],1133[ 0, 0, f ]])11341135def variable_names(self):1136r"""1137Returns the variable names of the defining polynomial1138of ``self``.11391140EXAMPLES:11411142::11431144sage: c=Conic([1,1,0,1,0,1], 'x,y,z')1145sage: c.variable_names()1146('x', 'y', 'z')1147sage: c.variable_name()1148'x'11491150The function ``variable_names()`` is required1151for the following construction:11521153::11541155sage: C.<p,q,r> = Conic(QQ, [1, 1, 1])1156sage: C1157Projective Conic Curve over Rational Field defined by p^2 + q^2 + r^211581159"""1160return self.defining_polynomial().parent().variable_names()11611162116311641165