Path: blob/master/src/sage/schemes/plane_conics/con_number_field.py
8820 views
r"""1Projective plane conics over a number field23AUTHORS:45- Marco Streng (2010-07-20)67"""8#*****************************************************************************9# Copyright (C) 2009/2010 Marco Streng <[email protected]>10#11# Distributed under the terms of the GNU General Public License (GPL)12#13# This code is distributed in the hope that it will be useful,14# but WITHOUT ANY WARRANTY; without even the implied warranty of15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU16# General Public License for more details.17#18# The full text of the GPL is available at:19#20# http://www.gnu.org/licenses/21#*****************************************************************************2223from sage.rings.all import (RDF, CDF, AA, RLF, QQbar, PolynomialRing)2425from sage.rings.complex_field import is_ComplexField2627from sage.rings.ring import is_Ring28from sage.rings.rational_field import is_RationalField29from sage.rings.morphism import is_RingHomomorphism30from sage.rings.real_mpfi import is_RealIntervalField31from sage.rings.complex_interval_field import is_ComplexIntervalField3233from con_field import ProjectiveConic_field3435class ProjectiveConic_number_field(ProjectiveConic_field):36r"""37Create a projective plane conic curve over a number field.38See ``Conic`` for full documentation.3940EXAMPLES::4142sage: K.<a> = NumberField(x^3 - 2, 'a')43sage: P.<X, Y, Z> = K[]44sage: Conic(X^2 + Y^2 - a*Z^2)45Projective Conic Curve over Number Field in a with defining polynomial x^3 - 2 defined by X^2 + Y^2 + (-a)*Z^24647TESTS::4849sage: K.<a> = NumberField(x^3 - 3, 'a')50sage: Conic([a, 1, -1])._test_pickling()51"""52def __init__(self, A, f):53r"""54See ``Conic`` for full documentation.5556EXAMPLES ::5758sage: Conic([1, 1, 1])59Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^260"""61ProjectiveConic_field.__init__(self, A, f)6263# a single prime such that self has no point over the completion64self._local_obstruction = None65# all finite primes such that self has no point over the completion66self._finite_obstructions = None67# all infinite primes such that self has no point over the completion68self._infinite_obstructions = None697071def has_rational_point(self, point = False, obstruction = False,72algorithm = 'default', read_cache = True):73r"""74Returns ``True`` if and only if ``self`` has a point75defined over its base field `B`.7677If ``point`` and ``obstruction`` are both False (default),78then the output is a boolean ``out`` saying whether ``self``79has a rational point.8081If ``point`` or ``obstruction`` is True, then the output is82a pair ``(out, S)``, where ``out`` is as above and:8384- if ``point`` is True and ``self`` has a rational point,85then ``S`` is a rational point,8687- if ``obstruction`` is True, ``self`` has no rational point,88then ``S`` is a prime or infinite place of `B` such that no89rational point exists over the completion at ``S``.9091Points and obstructions are cached whenever they are found.92Cached information is used for the output if available, but only93if ``read_cache`` is True.9495ALGORITHM:9697The parameter ``algorithm``98specifies the algorithm to be used:99100- ``'rnfisnorm'`` -- Use PARI's rnfisnorm101(cannot be combined with ``obstruction = True``)102103- ``'local'`` -- Check if a local solution exists for all primes104and infinite places of `B` and apply the Hasse principle.105(Cannot be combined with ``point = True``.)106107- ``'default'`` -- Use algorithm ``'rnfisnorm'`` first.108Then, if no point exists and obstructions are requested, use109algorithm ``'local'`` to find an obstruction.110111- ``'magma'`` (requires Magma to be installed) --112delegates the task to the Magma computer algebra113system.114115116EXAMPLES:117118An example over `\QQ` ::119120sage: C = Conic(QQ, [1, 113922743, -310146482690273725409])121sage: C.has_rational_point(point = True)122(True, (-76842858034579/5424 : -5316144401/5424 : 1))123sage: C.has_rational_point(algorithm = 'local', read_cache = False)124True125126Examples over number fields ::127128sage: K.<i> = QuadraticField(-1)129sage: C = Conic(K, [1, 3, -5])130sage: C.has_rational_point(point = True, obstruction = True)131(False, Fractional ideal (-i - 2))132sage: C.has_rational_point(algorithm = "rnfisnorm")133False134sage: C.has_rational_point(algorithm = "rnfisnorm", obstruction = True, read_cache=False)135Traceback (most recent call last):136...137ValueError: Algorithm rnfisnorm cannot be combined with obstruction = True in has_rational_point138139sage: P.<x> = QQ[]140sage: L.<b> = NumberField(x^3-5)141sage: C = Conic(L, [1, 2, -3])142sage: C.has_rational_point(point = True, algorithm = 'rnfisnorm')143(True, (5/3 : -1/3 : 1))144145sage: K.<a> = NumberField(x^4+2)146sage: Conic(QQ, [4,5,6]).has_rational_point()147False148sage: Conic(K, [4,5,6]).has_rational_point()149True150sage: Conic(K, [4,5,6]).has_rational_point(algorithm='magma', read_cache=False) # optional - magma151True152153TESTS:154155Create a bunch of conics over number fields and check whether156``has_rational_point`` runs without errors for algorithms157``'rnfisnorm'`` and ``'local'``. Check if all points returned are158valid. If Magma is available, then also check if the output agrees with159Magma. ::160161sage: P.<X> = QQ[]162sage: Q = P.fraction_field()163sage: c = [1, X/2, 1/X]164sage: l = Sequence(cartesian_product_iterator([c for i in range(3)]))165sage: l = l + [[X, 1, 1, 1, 1, 1]] + [[X, 1/5, 1, 1, 2, 1]]166sage: K.<a> = QuadraticField(-23)167sage: L.<b> = QuadraticField(19)168sage: M.<c> = NumberField(X^3+3*X+1)169sage: m = [[Q(b)(F.gen()) for b in a] for a in l for F in [K, L, M]]170sage: d = []171sage: c = []172sage: c = [Conic(a) for a in m if a != [0,0,0]]173sage: d = [C.has_rational_point(algorithm = 'rnfisnorm', point = True) for C in c] # long time: 3.3 seconds174sage: all([c[k].defining_polynomial()(Sequence(d[k][1])) == 0 for k in range(len(d)) if d[k][0]])175True176sage: [C.has_rational_point(algorithm='local', read_cache=False) for C in c] == [o[0] for o in d] # long time: 5 seconds177True178sage: [C.has_rational_point(algorithm = 'magma', read_cache=False) for C in c] == [o[0] for o in d] # long time: 3 seconds, optional - magma179True180181Create a bunch of conics that are known to have rational points182already over `\QQ` and check if points are found by183``has_rational_point``. ::184185sage: l = Sequence(cartesian_product_iterator([[-1, 0, 1] for i in range(3)]))186sage: K.<a> = QuadraticField(-23)187sage: L.<b> = QuadraticField(19)188sage: M.<c> = NumberField(x^5+3*x+1)189sage: m = [[F(b) for b in a] for a in l for F in [K, L, M]]190sage: c = [Conic(a) for a in m if a != [0,0,0] and a != [1,1,1] and a != [-1,-1,-1]]191sage: assert all([C.has_rational_point(algorithm = 'rnfisnorm') for C in c])192sage: assert all([C.defining_polynomial()(Sequence(C.has_rational_point(point = True)[1])) == 0 for C in c])193sage: assert all([C.has_rational_point(algorithm='local', read_cache=False) for C in c]) # long time: 1 second194"""195if read_cache:196if self._rational_point is not None:197if point or obstruction:198return True, self._rational_point199else:200return True201if self._local_obstruction is not None:202if point or obstruction:203return False, self._local_obstruction204else:205return False206if (not point) and self._finite_obstructions == [] and \207self._infinite_obstructions == []:208if obstruction:209return True, None210return True211if self.has_singular_point():212if point:213return self.has_singular_point(point = True)214if obstruction:215return True, None216return True217B = self.base_ring()218219if algorithm == 'default':220ret = self.has_rational_point(point=True, obstruction=False,221algorithm='rnfisnorm',222read_cache=False)223if ret[0]:224if point or obstruction:225return ret226return True227if obstruction:228ret = self.has_rational_point(point=False, obstruction=True,229algorithm='local',230read_cache=False)231if ret[0]:232raise RuntimeError, "Outputs of algorithms in " \233"has_rational_point disagree " \234"for conic %s" % self235return ret236if point:237return False, None238return False239240if algorithm == 'local':241if point:242raise ValueError, "Algorithm 'local' cannot be combined " \243"with point = True in has_rational_point"244obs = self.local_obstructions(infinite = True, finite = False,245read_cache = read_cache)246if obs != []:247if obstruction:248return False, obs[0]249return False250obs = self.local_obstructions(read_cache = read_cache)251if obs == []:252if obstruction:253return True, None254return True255if obstruction:256return False, obs[0]257return False258if algorithm == 'rnfisnorm':259from sage.modules.free_module_element import vector260if obstruction:261raise ValueError, "Algorithm rnfisnorm cannot be combined " \262"with obstruction = True in " \263"has_rational_point"264D, T = self.diagonal_matrix()265abc = [D[0,0], D[1,1], D[2,2]]266for j in range(3):267if abc[j] == 0:268pt = self.point(T*vector({2:0,j:1}))269if point or obstruction:270return True, pt271return True272if (-abc[1]/abc[0]).is_square():273pt = self.point(T*vector([(-abc[1]/abc[0]).sqrt(), 1, 0]))274if point or obstruction:275return True, pt276return True277if (-abc[2]/abc[0]).is_square():278pt = self.point(T*vector([(-abc[2]/abc[0]).sqrt(), 0, 1]))279if point or obstruction:280return True, pt281return True282if is_RationalField(B):283K = B284[KtoB, BtoK] = [K.hom(K) for i in range(2)]285else:286K = B.absolute_field('Y')287[KtoB, BtoK] = K.structure()288X = PolynomialRing(K, 'X').gen()289d = BtoK(-abc[1]/abc[0])290den = d.denominator()291L = K.extension(X**2 - d*den**2, names='y')292isnorm = BtoK(-abc[2]/abc[0]).is_norm(L, element=True)293if isnorm[0]:294295pt = self.point(T*vector([KtoB(isnorm[1][0]),296KtoB(isnorm[1][1]*den), 1]))297if point:298return True, pt299return True300if point:301return False, None302return False303if algorithm == 'qfsolve':304raise TypeError, "Algorithm qfsolve in has_rational_point only " \305"for conics over QQ, not over %s" % B306if obstruction:307raise ValueError, "Invalid combination: obstruction=True and " \308"algorithm=%s" % algorithm309310return ProjectiveConic_field.has_rational_point(self, point = point,311algorithm = algorithm, read_cache = False)312313314def is_locally_solvable(self, p):315r"""316Returns ``True`` if and only if ``self`` has a solution over the317completion of the base field `B` of ``self`` at ``p``. Here ``p``318is a finite prime or infinite place of `B`.319320EXAMPLES::321322sage: P.<x> = QQ[]323sage: K.<a> = NumberField(x^3 + 5)324sage: C = Conic(K, [1, 2, 3 - a])325sage: [p1, p2] = K.places()326sage: C.is_locally_solvable(p1)327False328329sage: C.is_locally_solvable(p2)330True331332sage: O = K.maximal_order()333sage: f = (2*O).factor()334sage: C.is_locally_solvable(f[0][0])335True336337sage: C.is_locally_solvable(f[1][0])338False339"""340D, T = self.diagonal_matrix()341abc = [D[j, j] for j in range(3)]342for a in abc:343if a == 0:344return True345a = -abc[0]/abc[2]346b = -abc[1]/abc[2]347348ret = self.base_ring().hilbert_symbol(a, b, p)349350if ret == -1:351if self._local_obstruction == None:352if (not is_RingHomomorphism(p)) or p.codomain() is AA or \353p.codomain() is RLF:354self._local_obstruction = p355return False356357return True358359360def local_obstructions(self, finite = True, infinite = True, read_cache = True):361r"""362Returns the sequence of finite primes and/or infinite places363such that ``self`` is locally solvable at those primes and places.364365If the base field is `\QQ`, then the infinite place is denoted `-1`.366367The parameters ``finite`` and ``infinite`` (both True by default) are368used to specify whether to look at finite and/or infinite places.369Note that ``finite = True`` involves factorization of the determinant370of ``self``, hence may be slow.371372Local obstructions are cached. The parameter ``read_cache``373specifies whether to look at the cache before computing anything.374375EXAMPLES ::376377sage: K.<i> = QuadraticField(-1)378sage: Conic(K, [1, 2, 3]).local_obstructions()379[]380381sage: L.<a> = QuadraticField(5)382sage: Conic(L, [1, 2, 3]).local_obstructions()383[Ring morphism:384From: Number Field in a with defining polynomial x^2 - 5385To: Algebraic Real Field386Defn: a |--> -2.236067977499790?, Ring morphism:387From: Number Field in a with defining polynomial x^2 - 5388To: Algebraic Real Field389Defn: a |--> 2.236067977499790?]390"""391obs0 = []392obs1 = []393B = self.base_ring()394if infinite:395if read_cache and self._infinite_obstructions != None:396obs0 = self._infinite_obstructions397else:398for b in B.embeddings(AA):399if not self.is_locally_solvable(b):400obs0.append(b)401self._infinite_obstructions = obs0402if finite:403if read_cache and self._finite_obstructions != None:404obs1 = self._finite_obstructions405else:406candidates = []407if self.determinant() != 0:408O = B.maximal_order()409for a in self.symmetric_matrix().list():410if a != 0:411for f in O.fractional_ideal(a).factor():412if f[1] < 0 and not f[0] in candidates:413candidates.append(f[0])414for f in O.fractional_ideal(2*self.determinant()).factor():415if f[1] > 0 and not f[0] in candidates:416candidates.append(f[0])417for b in candidates:418if not self.is_locally_solvable(b):419obs1.append(b)420self._infinite_obstructions = obs1421obs = obs1 + obs0422if finite and infinite:423assert len(obs) % 2 == 0424return obs425426427428429