Path: blob/master/sage/schemes/plane_conics/con_rational_field.py
4108 views
r"""1Projective plane conics over `\QQ`23AUTHORS: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 (PolynomialRing, ZZ, QQ,27is_RealField, is_RingHomomorphism)28from sage.structure.sequence import Sequence29from sage.schemes.generic.projective_space import ProjectiveSpace30from sage.matrix.constructor import Matrix3132from sage.quadratic_forms.qfsolve import qfsolve, qfparam3334from con_number_field import ProjectiveConic_number_field3536from sage.structure.element import is_InfinityElement3738from sage.rings.arith import (lcm, hilbert_symbol)3940class ProjectiveConic_rational_field(ProjectiveConic_number_field):41r"""42Create a projective plane conic curve over `\QQ`.43See ``Conic`` for full documentation.4445EXAMPLES::4647sage: P.<X, Y, Z> = QQ[]48sage: Conic(X^2 + Y^2 - 3*Z^2)49Projective Conic Curve over Rational Field defined by X^2 + Y^2 - 3*Z^25051TESTS::5253sage: Conic([2, 1, -1])._test_pickling()54"""55def __init__(self, A, f):56r"""57See ``Conic`` for full documentation.5859EXAMPLES::6061sage: Conic([1, 1, 1])62Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^263"""64ProjectiveConic_number_field.__init__(self, A, f)656667def has_rational_point(self, point = False, obstruction = False,68algorithm = 'default', read_cache = True):69r"""70Returns True if and only if ``self`` has a point defined over `\QQ`.7172If ``point`` and ``obstruction`` are both False (default), then73the output is a boolean ``out`` saying whether ``self`` has a74rational point.7576If ``point`` or ``obstruction`` is True, then the output is77a pair ``(out, S)``, where ``out`` is as above and the following78holds:7980- if ``point`` is True and ``self`` has a rational point,81then ``S`` is a rational point,8283- if ``obstruction`` is True and ``self`` has no rational point,84then ``S`` is a prime such that no rational point exists85over the completion at ``S`` or `-1` if no point exists over `\RR`.8687Points and obstructions are cached, whenever they are found.88Cached information is used if and only if ``read_cache`` is True.8990ALGORITHM:9192The parameter ``algorithm``93specifies the algorithm to be used:9495- ``'qfsolve'`` -- Use Denis Simon's pari script Qfsolve96(see ``sage.quadratic_forms.qfsolve.qfsolve``)9798- ``'rnfisnorm'`` -- Use PARI's function rnfisnorm99(cannot be combined with ``obstruction = True``)100101- ``'local'`` -- Check if a local solution exists for all primes102and infinite places of `\QQ` and apply the Hasse principle103(cannot be combined with ``point = True``)104105- ``'default'`` -- Use ``'qfsolve'``106107EXAMPLES::108109sage: C = Conic(QQ, [1, 2, -3])110sage: C.has_rational_point(point = True)111(True, (1 : 1 : 1))112sage: D = Conic(QQ, [1, 3, -5])113sage: D.has_rational_point(point = True)114(False, 3)115sage: P.<X,Y,Z> = QQ[]116sage: E = Curve(X^2 + Y^2 + Z^2); E117Projective Conic Curve over Rational Field defined by X^2 + Y^2 + Z^2118sage: E.has_rational_point(obstruction = True)119(False, -1)120121The following would not terminate quickly with122``algorithm = 'rnfisnorm'`` ::123124sage: C = Conic(QQ, [1, 113922743, -310146482690273725409])125sage: C.has_rational_point(point = True)126(True, (-76842858034579/5424 : -5316144401/5424 : 1))127sage: C.has_rational_point(algorithm = 'local', read_cache = False)128True129130TESTS:131132Create a bunch of conics over `\QQ`, check if ``has_rational_point`` runs without errors133and returns consistent answers for all algorithms. Check if all points returned are valid. ::134135sage: l = Sequence(cartesian_product_iterator([[-1, 0, 1] for i in range(6)]))136sage: c = [Conic(QQ, a) for a in l if a != [0,0,0] and a != (0,0,0,0,0,0)]137sage: d = []138sage: d = [[C]+[C.has_rational_point(algorithm = algorithm, read_cache = False, obstruction = (algorithm != 'rnfisnorm'), point = (algorithm != 'local')) for algorithm in ['local', 'qfsolve', 'rnfisnorm']] for C in c[::10]] # long time: 7 seconds139sage: assert all([e[1][0] == e[2][0] and e[1][0] == e[3][0] for e in d])140sage: assert all([e[0].defining_polynomial()(Sequence(e[i][1])) == 0 for e in d for i in [2,3] if e[1][0]])141"""142if read_cache:143if self._rational_point is not None:144if point or obstruction:145return True, self._rational_point146else:147return True148if self._local_obstruction is not None:149if point or obstruction:150return False, self._local_obstruction151else:152return False153if (not point) and self._finite_obstructions == [] and \154self._infinite_obstructions == []:155if obstruction:156return True, None157return True158if self.has_singular_point():159if point:160return self.has_singular_point(point = True)161if obstruction:162return True, None163return True164if algorithm == 'default' or algorithm == 'qfsolve':165M = self.symmetric_matrix()166M *= lcm([ t.denominator() for t in M.list() ])167pt = qfsolve(M)168if pt in ZZ:169if self._local_obstruction == None:170self._local_obstruction = pt171if point or obstruction:172return False, pt173return False174pt = self.point([pt[0], pt[1], pt[2]])175if point or obstruction:176return True, pt177return True178ret = ProjectiveConic_number_field.has_rational_point( \179self, point = point, \180obstruction = obstruction, \181algorithm = algorithm, \182read_cache = read_cache)183if point or obstruction:184if is_RingHomomorphism(ret[1]):185ret[1] = -1186return ret187188189def is_locally_solvable(self, p):190r"""191Returns True if and only if ``self`` has a solution over the192`p`-adic numbers. Here `p` is a prime number or equals193`-1`, infinity, or `\RR` to denote the infinite place.194195EXAMPLES::196197sage: C = Conic(QQ, [1,2,3])198sage: C.is_locally_solvable(-1)199False200sage: C.is_locally_solvable(2)201False202sage: C.is_locally_solvable(3)203True204sage: C.is_locally_solvable(QQ.hom(RR))205False206sage: D = Conic(QQ, [1, 2, -3])207sage: D.is_locally_solvable(infinity)208True209sage: D.is_locally_solvable(RR)210True211212"""213D, T = self.diagonal_matrix()214abc = [D[j, j] for j in range(3)]215if abc[2] == 0:216return True217a = -abc[0]/abc[2]218b = -abc[1]/abc[2]219if is_RealField(p) or is_InfinityElement(p):220p = -1221elif is_RingHomomorphism(p):222if p.domain() is QQ and is_RealField(p.codomain()):223p = -1224else:225raise TypeError, "p (=%s) needs to be a prime of base field " \226"B ( =`QQ`) in is_locally_solvable" % p227if hilbert_symbol(a, b, p) == -1:228if self._local_obstruction == None:229self._local_obstruction = p230return False231return True232233234def local_obstructions(self, finite = True, infinite = True, read_cache = True):235r"""236Returns the sequence of finite primes and/or infinite places237such that self is locally solvable at those primes and places.238239The infinite place is denoted `-1`.240241The parameters ``finite`` and ``infinite`` (both True by default) are242used to specify whether to look at finite and/or infinite places.243Note that ``finite = True`` involves factorization of the determinant244of ``self``, hence may be slow.245246Local obstructions are cached. The parameter ``read_cache`` specifies247whether to look at the cache before computing anything.248249EXAMPLES ::250251sage: Conic(QQ, [1, 1, 1]).local_obstructions()252[2, -1]253sage: Conic(QQ, [1, 2, -3]).local_obstructions()254[]255sage: Conic(QQ, [1, 2, 3, 4, 5, 6]).local_obstructions()256[41, -1]257258"""259obs0 = []260obs1 = []261if infinite:262if read_cache and self._infinite_obstructions != None:263obs0 = self._infinite_obstructions264else:265if not self.is_locally_solvable(-1):266obs0 = [-1]267self._infinite_obstructions = obs0268if finite:269if read_cache and self._finite_obstructions != None:270obs1 = self._finite_obstructions271else:272candidates = []273if self.determinant() != 0:274for a in self.symmetric_matrix().list():275if a != 0:276for f in a.factor():277if f[1] < 0 and not f[0] in candidates:278candidates.append(f[0])279for f in (2*self.determinant()).factor():280if f[1] > 0 and not f[0] in candidates:281candidates.append(f[0])282for b in candidates:283if not self.is_locally_solvable(b):284obs1.append(b)285self._infinite_obstructions = obs1286obs = obs1 + obs0287if finite and infinite:288assert len(obs) % 2 == 0289return obs290291292def parametrization(self, point=None, morphism=True):293r"""294Return a parametrization `f` of ``self`` together with the295inverse of `f`.296297If ``point`` is specified, then that point is used298for the parametrization. Otherwise, use ``self.rational_point()``299to find a point.300301If ``morphism`` is True, then `f` is returned in the form302of a Scheme morphism. Otherwise, it is a tuple of polynomials303that gives the parametrization.304305ALGORITHM:306307Uses Denis Simon's pari script Qfparam.308See ``sage.quadratic_forms.qfsolve.qfparam``.309310EXAMPLES ::311312sage: c = Conic([1,1,-1])313sage: c.parametrization()314(Scheme morphism:315From: Projective Space of dimension 1 over Rational Field316To: Projective Conic Curve over Rational Field defined by x^2 + y^2 - z^2317Defn: Defined on coordinates by sending (x : y) to318(2*x*y : x^2 - y^2 : x^2 + y^2),319Scheme morphism:320From: Projective Conic Curve over Rational Field defined by x^2 + y^2 - z^2321To: Projective Space of dimension 1 over Rational Field322Defn: Defined on coordinates by sending (x : y : z) to323(1/2*x : -1/2*y + 1/2*z))324325An example with ``morphism = False`` ::326327sage: R.<x,y,z> = QQ[]328sage: C = Curve(7*x^2 + 2*y*z + z^2)329sage: (p, i) = C.parametrization(morphism = False); (p, i)330([-2*x*y, 7*x^2 + y^2, -2*y^2], [-1/2*x, -1/2*z])331sage: C.defining_polynomial()(p)3320333sage: i[0](p) / i[1](p)334x/y335336A ``ValueError`` is raised if ``self`` has no rational point ::337338sage: C = Conic(x^2 + 2*y^2 + z^2)339sage: C.parametrization()340Traceback (most recent call last):341...342ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + z^2 has no rational points over Rational Field!343344A ``ValueError`` is raised if ``self`` is not smooth ::345346sage: C = Conic(x^2 + y^2)347sage: C.parametrization()348Traceback (most recent call last):349...350ValueError: The conic self (=Projective Conic Curve over Rational Field defined by x^2 + y^2) is not smooth, hence does not have a parametrization.351"""352if (not self._parametrization is None) and not point:353par = self._parametrization354else:355if not self.is_smooth():356raise ValueError, "The conic self (=%s) is not smooth, hence does not have a parametrization." % self357if point == None:358point = self.rational_point()359point = Sequence(point)360Q = PolynomialRing(QQ, 'x,y')361[x, y] = Q.gens()362gens = self.ambient_space().gens()363M = self.symmetric_matrix()364M *= lcm([ t.denominator() for t in M.list() ])365par1 = qfparam(M, point)366B = Matrix([[par1[i][j] for j in range(3)] for i in range(3)])367# self is in the image of B and does not lie on a line,368# hence B is invertible369A = B.inverse()370par2 = [sum([A[i,j]*gens[j] for j in range(3)]) for i in [1,0]]371par = ([Q(pol(x/y)*y**2) for pol in par1], par2)372if self._parametrization is None:373self._parametrization = par374if not morphism:375return par376P1 = ProjectiveSpace(self.base_ring(), 1, 'x,y')377return P1.hom(par[0],self), self.Hom(P1)(par[1], check = False)378379380381