Path: blob/master/src/sage/schemes/plane_conics/con_rational_field.py
8820 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)2728from sage.rings.morphism import is_RingHomomorphism29from sage.rings.real_mpfr import is_RealField3031from sage.structure.sequence import Sequence32from sage.schemes.projective.projective_space import ProjectiveSpace33from sage.matrix.constructor import Matrix3435from sage.quadratic_forms.qfsolve import qfsolve, qfparam3637from con_number_field import ProjectiveConic_number_field3839from sage.structure.element import is_InfinityElement4041from sage.rings.arith import (lcm, hilbert_symbol)4243class ProjectiveConic_rational_field(ProjectiveConic_number_field):44r"""45Create a projective plane conic curve over `\QQ`.46See ``Conic`` for full documentation.4748EXAMPLES::4950sage: P.<X, Y, Z> = QQ[]51sage: Conic(X^2 + Y^2 - 3*Z^2)52Projective Conic Curve over Rational Field defined by X^2 + Y^2 - 3*Z^25354TESTS::5556sage: Conic([2, 1, -1])._test_pickling()57"""58def __init__(self, A, f):59r"""60See ``Conic`` for full documentation.6162EXAMPLES::6364sage: Conic([1, 1, 1])65Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^266"""67ProjectiveConic_number_field.__init__(self, A, f)686970def has_rational_point(self, point = False, obstruction = False,71algorithm = 'default', read_cache = True):72r"""73Returns True if and only if ``self`` has a point defined over `\QQ`.7475If ``point`` and ``obstruction`` are both False (default), then76the output is a boolean ``out`` saying whether ``self`` has a77rational point.7879If ``point`` or ``obstruction`` is True, then the output is80a pair ``(out, S)``, where ``out`` is as above and the following81holds:8283- if ``point`` is True and ``self`` has a rational point,84then ``S`` is a rational point,8586- if ``obstruction`` is True and ``self`` has no rational point,87then ``S`` is a prime such that no rational point exists88over the completion at ``S`` or `-1` if no point exists over `\RR`.8990Points and obstructions are cached, whenever they are found.91Cached information is used if and only if ``read_cache`` is True.9293ALGORITHM:9495The parameter ``algorithm``96specifies the algorithm to be used:9798- ``'qfsolve'`` -- Use Denis Simon's pari script Qfsolve99(see ``sage.quadratic_forms.qfsolve.qfsolve``)100101- ``'rnfisnorm'`` -- Use PARI's function rnfisnorm102(cannot be combined with ``obstruction = True``)103104- ``'local'`` -- Check if a local solution exists for all primes105and infinite places of `\QQ` and apply the Hasse principle106(cannot be combined with ``point = True``)107108- ``'default'`` -- Use ``'qfsolve'``109110- ``'magma'`` (requires Magma to be installed) --111delegates the task to the Magma computer algebra112system.113114EXAMPLES::115116sage: C = Conic(QQ, [1, 2, -3])117sage: C.has_rational_point(point = True)118(True, (1 : 1 : 1))119sage: D = Conic(QQ, [1, 3, -5])120sage: D.has_rational_point(point = True)121(False, 3)122sage: P.<X,Y,Z> = QQ[]123sage: E = Curve(X^2 + Y^2 + Z^2); E124Projective Conic Curve over Rational Field defined by X^2 + Y^2 + Z^2125sage: E.has_rational_point(obstruction = True)126(False, -1)127128The following would not terminate quickly with129``algorithm = 'rnfisnorm'`` ::130131sage: C = Conic(QQ, [1, 113922743, -310146482690273725409])132sage: C.has_rational_point(point = True)133(True, (-76842858034579/5424 : -5316144401/5424 : 1))134sage: C.has_rational_point(algorithm = 'local', read_cache = False)135True136sage: C.has_rational_point(point=True, algorithm='magma', read_cache=False) # optional - magma137(True, (30106379962113/7913 : 12747947692/7913 : 1))138139TESTS:140141Create a bunch of conics over `\QQ`, check if ``has_rational_point`` runs without errors142and returns consistent answers for all algorithms. Check if all points returned are valid. ::143144sage: l = Sequence(cartesian_product_iterator([[-1, 0, 1] for i in range(6)]))145sage: c = [Conic(QQ, a) for a in l if a != [0,0,0] and a != (0,0,0,0,0,0)]146sage: d = []147sage: 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 seconds148sage: assert all([e[1][0] == e[2][0] and e[1][0] == e[3][0] for e in d])149sage: assert all([e[0].defining_polynomial()(Sequence(e[i][1])) == 0 for e in d for i in [2,3] if e[1][0]])150"""151if read_cache:152if self._rational_point is not None:153if point or obstruction:154return True, self._rational_point155else:156return True157if self._local_obstruction is not None:158if point or obstruction:159return False, self._local_obstruction160else:161return False162if (not point) and self._finite_obstructions == [] and \163self._infinite_obstructions == []:164if obstruction:165return True, None166return True167if self.has_singular_point():168if point:169return self.has_singular_point(point = True)170if obstruction:171return True, None172return True173if algorithm == 'default' or algorithm == 'qfsolve':174M = self.symmetric_matrix()175M *= lcm([ t.denominator() for t in M.list() ])176pt = qfsolve(M)177if pt in ZZ:178if self._local_obstruction == None:179self._local_obstruction = pt180if point or obstruction:181return False, pt182return False183pt = self.point([pt[0], pt[1], pt[2]])184if point or obstruction:185return True, pt186return True187ret = ProjectiveConic_number_field.has_rational_point( \188self, point = point, \189obstruction = obstruction, \190algorithm = algorithm, \191read_cache = read_cache)192if point or obstruction:193if is_RingHomomorphism(ret[1]):194ret[1] = -1195return ret196197198def is_locally_solvable(self, p):199r"""200Returns True if and only if ``self`` has a solution over the201`p`-adic numbers. Here `p` is a prime number or equals202`-1`, infinity, or `\RR` to denote the infinite place.203204EXAMPLES::205206sage: C = Conic(QQ, [1,2,3])207sage: C.is_locally_solvable(-1)208False209sage: C.is_locally_solvable(2)210False211sage: C.is_locally_solvable(3)212True213sage: C.is_locally_solvable(QQ.hom(RR))214False215sage: D = Conic(QQ, [1, 2, -3])216sage: D.is_locally_solvable(infinity)217True218sage: D.is_locally_solvable(RR)219True220221"""222D, T = self.diagonal_matrix()223abc = [D[j, j] for j in range(3)]224if abc[2] == 0:225return True226a = -abc[0]/abc[2]227b = -abc[1]/abc[2]228if is_RealField(p) or is_InfinityElement(p):229p = -1230elif is_RingHomomorphism(p):231if p.domain() is QQ and is_RealField(p.codomain()):232p = -1233else:234raise TypeError, "p (=%s) needs to be a prime of base field " \235"B ( =`QQ`) in is_locally_solvable" % p236if hilbert_symbol(a, b, p) == -1:237if self._local_obstruction == None:238self._local_obstruction = p239return False240return True241242243def local_obstructions(self, finite = True, infinite = True, read_cache = True):244r"""245Returns the sequence of finite primes and/or infinite places246such that self is locally solvable at those primes and places.247248The infinite place is denoted `-1`.249250The parameters ``finite`` and ``infinite`` (both True by default) are251used to specify whether to look at finite and/or infinite places.252Note that ``finite = True`` involves factorization of the determinant253of ``self``, hence may be slow.254255Local obstructions are cached. The parameter ``read_cache`` specifies256whether to look at the cache before computing anything.257258EXAMPLES ::259260sage: Conic(QQ, [1, 1, 1]).local_obstructions()261[2, -1]262sage: Conic(QQ, [1, 2, -3]).local_obstructions()263[]264sage: Conic(QQ, [1, 2, 3, 4, 5, 6]).local_obstructions()265[41, -1]266267"""268obs0 = []269obs1 = []270if infinite:271if read_cache and self._infinite_obstructions != None:272obs0 = self._infinite_obstructions273else:274if not self.is_locally_solvable(-1):275obs0 = [-1]276self._infinite_obstructions = obs0277if finite:278if read_cache and self._finite_obstructions != None:279obs1 = self._finite_obstructions280else:281candidates = []282if self.determinant() != 0:283for a in self.symmetric_matrix().list():284if a != 0:285for f in a.factor():286if f[1] < 0 and not f[0] in candidates:287candidates.append(f[0])288for f in (2*self.determinant()).factor():289if f[1] > 0 and not f[0] in candidates:290candidates.append(f[0])291for b in candidates:292if not self.is_locally_solvable(b):293obs1.append(b)294self._infinite_obstructions = obs1295obs = obs1 + obs0296if finite and infinite:297assert len(obs) % 2 == 0298return obs299300301def parametrization(self, point=None, morphism=True):302r"""303Return a parametrization `f` of ``self`` together with the304inverse of `f`.305306If ``point`` is specified, then that point is used307for the parametrization. Otherwise, use ``self.rational_point()``308to find a point.309310If ``morphism`` is True, then `f` is returned in the form311of a Scheme morphism. Otherwise, it is a tuple of polynomials312that gives the parametrization.313314ALGORITHM:315316Uses Denis Simon's pari script Qfparam.317See ``sage.quadratic_forms.qfsolve.qfparam``.318319EXAMPLES ::320321sage: c = Conic([1,1,-1])322sage: c.parametrization()323(Scheme morphism:324From: Projective Space of dimension 1 over Rational Field325To: Projective Conic Curve over Rational Field defined by x^2 + y^2 - z^2326Defn: Defined on coordinates by sending (x : y) to327(2*x*y : x^2 - y^2 : x^2 + y^2),328Scheme morphism:329From: Projective Conic Curve over Rational Field defined by x^2 + y^2 - z^2330To: Projective Space of dimension 1 over Rational Field331Defn: Defined on coordinates by sending (x : y : z) to332(1/2*x : -1/2*y + 1/2*z))333334An example with ``morphism = False`` ::335336sage: R.<x,y,z> = QQ[]337sage: C = Curve(7*x^2 + 2*y*z + z^2)338sage: (p, i) = C.parametrization(morphism = False); (p, i)339([-2*x*y, 7*x^2 + y^2, -2*y^2], [-1/2*x, -1/2*z])340sage: C.defining_polynomial()(p)3410342sage: i[0](p) / i[1](p)343x/y344345A ``ValueError`` is raised if ``self`` has no rational point ::346347sage: C = Conic(x^2 + 2*y^2 + z^2)348sage: C.parametrization()349Traceback (most recent call last):350...351ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + z^2 has no rational points over Rational Field!352353A ``ValueError`` is raised if ``self`` is not smooth ::354355sage: C = Conic(x^2 + y^2)356sage: C.parametrization()357Traceback (most recent call last):358...359ValueError: The conic self (=Projective Conic Curve over Rational Field defined by x^2 + y^2) is not smooth, hence does not have a parametrization.360"""361if (not self._parametrization is None) and not point:362par = self._parametrization363else:364if not self.is_smooth():365raise ValueError, "The conic self (=%s) is not smooth, hence does not have a parametrization." % self366if point == None:367point = self.rational_point()368point = Sequence(point)369Q = PolynomialRing(QQ, 'x,y')370[x, y] = Q.gens()371gens = self.ambient_space().gens()372M = self.symmetric_matrix()373M *= lcm([ t.denominator() for t in M.list() ])374par1 = qfparam(M, point)375B = Matrix([[par1[i][j] for j in range(3)] for i in range(3)])376# self is in the image of B and does not lie on a line,377# hence B is invertible378A = B.inverse()379par2 = [sum([A[i,j]*gens[j] for j in range(3)]) for i in [1,0]]380par = ([Q(pol(x/y)*y**2) for pol in par1], par2)381if self._parametrization is None:382self._parametrization = par383if not morphism:384return par385P1 = ProjectiveSpace(self.base_ring(), 1, 'x,y')386return P1.hom(par[0],self), self.Hom(P1)(par[1], check = False)387388389390