Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/schemes/plane_conics/con_rational_field.py
4108 views
1
r"""
2
Projective plane conics over `\QQ`
3
4
AUTHORS:
5
6
- Marco Streng (2010-07-20)
7
8
- Nick Alexander (2008-01-08)
9
10
"""
11
#*****************************************************************************
12
# Copyright (C) 2008 Nick Alexander <[email protected]>
13
# Copyright (C) 2009/2010 Marco Streng <[email protected]>
14
#
15
# Distributed under the terms of the GNU General Public License (GPL)
16
#
17
# This code is distributed in the hope that it will be useful,
18
# but WITHOUT ANY WARRANTY; without even the implied warranty of
19
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20
# General Public License for more details.
21
#
22
# The full text of the GPL is available at:
23
#
24
# http://www.gnu.org/licenses/
25
#*****************************************************************************
26
27
from sage.rings.all import (PolynomialRing, ZZ, QQ,
28
is_RealField, is_RingHomomorphism)
29
from sage.structure.sequence import Sequence
30
from sage.schemes.generic.projective_space import ProjectiveSpace
31
from sage.matrix.constructor import Matrix
32
33
from sage.quadratic_forms.qfsolve import qfsolve, qfparam
34
35
from con_number_field import ProjectiveConic_number_field
36
37
from sage.structure.element import is_InfinityElement
38
39
from sage.rings.arith import (lcm, hilbert_symbol)
40
41
class ProjectiveConic_rational_field(ProjectiveConic_number_field):
42
r"""
43
Create a projective plane conic curve over `\QQ`.
44
See ``Conic`` for full documentation.
45
46
EXAMPLES::
47
48
sage: P.<X, Y, Z> = QQ[]
49
sage: Conic(X^2 + Y^2 - 3*Z^2)
50
Projective Conic Curve over Rational Field defined by X^2 + Y^2 - 3*Z^2
51
52
TESTS::
53
54
sage: Conic([2, 1, -1])._test_pickling()
55
"""
56
def __init__(self, A, f):
57
r"""
58
See ``Conic`` for full documentation.
59
60
EXAMPLES::
61
62
sage: Conic([1, 1, 1])
63
Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2
64
"""
65
ProjectiveConic_number_field.__init__(self, A, f)
66
67
68
def has_rational_point(self, point = False, obstruction = False,
69
algorithm = 'default', read_cache = True):
70
r"""
71
Returns True if and only if ``self`` has a point defined over `\QQ`.
72
73
If ``point`` and ``obstruction`` are both False (default), then
74
the output is a boolean ``out`` saying whether ``self`` has a
75
rational point.
76
77
If ``point`` or ``obstruction`` is True, then the output is
78
a pair ``(out, S)``, where ``out`` is as above and the following
79
holds:
80
81
- if ``point`` is True and ``self`` has a rational point,
82
then ``S`` is a rational point,
83
84
- if ``obstruction`` is True and ``self`` has no rational point,
85
then ``S`` is a prime such that no rational point exists
86
over the completion at ``S`` or `-1` if no point exists over `\RR`.
87
88
Points and obstructions are cached, whenever they are found.
89
Cached information is used if and only if ``read_cache`` is True.
90
91
ALGORITHM:
92
93
The parameter ``algorithm``
94
specifies the algorithm to be used:
95
96
- ``'qfsolve'`` -- Use Denis Simon's pari script Qfsolve
97
(see ``sage.quadratic_forms.qfsolve.qfsolve``)
98
99
- ``'rnfisnorm'`` -- Use PARI's function rnfisnorm
100
(cannot be combined with ``obstruction = True``)
101
102
- ``'local'`` -- Check if a local solution exists for all primes
103
and infinite places of `\QQ` and apply the Hasse principle
104
(cannot be combined with ``point = True``)
105
106
- ``'default'`` -- Use ``'qfsolve'``
107
108
EXAMPLES::
109
110
sage: C = Conic(QQ, [1, 2, -3])
111
sage: C.has_rational_point(point = True)
112
(True, (1 : 1 : 1))
113
sage: D = Conic(QQ, [1, 3, -5])
114
sage: D.has_rational_point(point = True)
115
(False, 3)
116
sage: P.<X,Y,Z> = QQ[]
117
sage: E = Curve(X^2 + Y^2 + Z^2); E
118
Projective Conic Curve over Rational Field defined by X^2 + Y^2 + Z^2
119
sage: E.has_rational_point(obstruction = True)
120
(False, -1)
121
122
The following would not terminate quickly with
123
``algorithm = 'rnfisnorm'`` ::
124
125
sage: C = Conic(QQ, [1, 113922743, -310146482690273725409])
126
sage: C.has_rational_point(point = True)
127
(True, (-76842858034579/5424 : -5316144401/5424 : 1))
128
sage: C.has_rational_point(algorithm = 'local', read_cache = False)
129
True
130
131
TESTS:
132
133
Create a bunch of conics over `\QQ`, check if ``has_rational_point`` runs without errors
134
and returns consistent answers for all algorithms. Check if all points returned are valid. ::
135
136
sage: l = Sequence(cartesian_product_iterator([[-1, 0, 1] for i in range(6)]))
137
sage: c = [Conic(QQ, a) for a in l if a != [0,0,0] and a != (0,0,0,0,0,0)]
138
sage: d = []
139
sage: 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 seconds
140
sage: assert all([e[1][0] == e[2][0] and e[1][0] == e[3][0] for e in d])
141
sage: assert all([e[0].defining_polynomial()(Sequence(e[i][1])) == 0 for e in d for i in [2,3] if e[1][0]])
142
"""
143
if read_cache:
144
if self._rational_point is not None:
145
if point or obstruction:
146
return True, self._rational_point
147
else:
148
return True
149
if self._local_obstruction is not None:
150
if point or obstruction:
151
return False, self._local_obstruction
152
else:
153
return False
154
if (not point) and self._finite_obstructions == [] and \
155
self._infinite_obstructions == []:
156
if obstruction:
157
return True, None
158
return True
159
if self.has_singular_point():
160
if point:
161
return self.has_singular_point(point = True)
162
if obstruction:
163
return True, None
164
return True
165
if algorithm == 'default' or algorithm == 'qfsolve':
166
M = self.symmetric_matrix()
167
M *= lcm([ t.denominator() for t in M.list() ])
168
pt = qfsolve(M)
169
if pt in ZZ:
170
if self._local_obstruction == None:
171
self._local_obstruction = pt
172
if point or obstruction:
173
return False, pt
174
return False
175
pt = self.point([pt[0], pt[1], pt[2]])
176
if point or obstruction:
177
return True, pt
178
return True
179
ret = ProjectiveConic_number_field.has_rational_point( \
180
self, point = point, \
181
obstruction = obstruction, \
182
algorithm = algorithm, \
183
read_cache = read_cache)
184
if point or obstruction:
185
if is_RingHomomorphism(ret[1]):
186
ret[1] = -1
187
return ret
188
189
190
def is_locally_solvable(self, p):
191
r"""
192
Returns True if and only if ``self`` has a solution over the
193
`p`-adic numbers. Here `p` is a prime number or equals
194
`-1`, infinity, or `\RR` to denote the infinite place.
195
196
EXAMPLES::
197
198
sage: C = Conic(QQ, [1,2,3])
199
sage: C.is_locally_solvable(-1)
200
False
201
sage: C.is_locally_solvable(2)
202
False
203
sage: C.is_locally_solvable(3)
204
True
205
sage: C.is_locally_solvable(QQ.hom(RR))
206
False
207
sage: D = Conic(QQ, [1, 2, -3])
208
sage: D.is_locally_solvable(infinity)
209
True
210
sage: D.is_locally_solvable(RR)
211
True
212
213
"""
214
D, T = self.diagonal_matrix()
215
abc = [D[j, j] for j in range(3)]
216
if abc[2] == 0:
217
return True
218
a = -abc[0]/abc[2]
219
b = -abc[1]/abc[2]
220
if is_RealField(p) or is_InfinityElement(p):
221
p = -1
222
elif is_RingHomomorphism(p):
223
if p.domain() is QQ and is_RealField(p.codomain()):
224
p = -1
225
else:
226
raise TypeError, "p (=%s) needs to be a prime of base field " \
227
"B ( =`QQ`) in is_locally_solvable" % p
228
if hilbert_symbol(a, b, p) == -1:
229
if self._local_obstruction == None:
230
self._local_obstruction = p
231
return False
232
return True
233
234
235
def local_obstructions(self, finite = True, infinite = True, read_cache = True):
236
r"""
237
Returns the sequence of finite primes and/or infinite places
238
such that self is locally solvable at those primes and places.
239
240
The infinite place is denoted `-1`.
241
242
The parameters ``finite`` and ``infinite`` (both True by default) are
243
used to specify whether to look at finite and/or infinite places.
244
Note that ``finite = True`` involves factorization of the determinant
245
of ``self``, hence may be slow.
246
247
Local obstructions are cached. The parameter ``read_cache`` specifies
248
whether to look at the cache before computing anything.
249
250
EXAMPLES ::
251
252
sage: Conic(QQ, [1, 1, 1]).local_obstructions()
253
[2, -1]
254
sage: Conic(QQ, [1, 2, -3]).local_obstructions()
255
[]
256
sage: Conic(QQ, [1, 2, 3, 4, 5, 6]).local_obstructions()
257
[41, -1]
258
259
"""
260
obs0 = []
261
obs1 = []
262
if infinite:
263
if read_cache and self._infinite_obstructions != None:
264
obs0 = self._infinite_obstructions
265
else:
266
if not self.is_locally_solvable(-1):
267
obs0 = [-1]
268
self._infinite_obstructions = obs0
269
if finite:
270
if read_cache and self._finite_obstructions != None:
271
obs1 = self._finite_obstructions
272
else:
273
candidates = []
274
if self.determinant() != 0:
275
for a in self.symmetric_matrix().list():
276
if a != 0:
277
for f in a.factor():
278
if f[1] < 0 and not f[0] in candidates:
279
candidates.append(f[0])
280
for f in (2*self.determinant()).factor():
281
if f[1] > 0 and not f[0] in candidates:
282
candidates.append(f[0])
283
for b in candidates:
284
if not self.is_locally_solvable(b):
285
obs1.append(b)
286
self._infinite_obstructions = obs1
287
obs = obs1 + obs0
288
if finite and infinite:
289
assert len(obs) % 2 == 0
290
return obs
291
292
293
def parametrization(self, point=None, morphism=True):
294
r"""
295
Return a parametrization `f` of ``self`` together with the
296
inverse of `f`.
297
298
If ``point`` is specified, then that point is used
299
for the parametrization. Otherwise, use ``self.rational_point()``
300
to find a point.
301
302
If ``morphism`` is True, then `f` is returned in the form
303
of a Scheme morphism. Otherwise, it is a tuple of polynomials
304
that gives the parametrization.
305
306
ALGORITHM:
307
308
Uses Denis Simon's pari script Qfparam.
309
See ``sage.quadratic_forms.qfsolve.qfparam``.
310
311
EXAMPLES ::
312
313
sage: c = Conic([1,1,-1])
314
sage: c.parametrization()
315
(Scheme morphism:
316
From: Projective Space of dimension 1 over Rational Field
317
To: Projective Conic Curve over Rational Field defined by x^2 + y^2 - z^2
318
Defn: Defined on coordinates by sending (x : y) to
319
(2*x*y : x^2 - y^2 : x^2 + y^2),
320
Scheme morphism:
321
From: Projective Conic Curve over Rational Field defined by x^2 + y^2 - z^2
322
To: Projective Space of dimension 1 over Rational Field
323
Defn: Defined on coordinates by sending (x : y : z) to
324
(1/2*x : -1/2*y + 1/2*z))
325
326
An example with ``morphism = False`` ::
327
328
sage: R.<x,y,z> = QQ[]
329
sage: C = Curve(7*x^2 + 2*y*z + z^2)
330
sage: (p, i) = C.parametrization(morphism = False); (p, i)
331
([-2*x*y, 7*x^2 + y^2, -2*y^2], [-1/2*x, -1/2*z])
332
sage: C.defining_polynomial()(p)
333
0
334
sage: i[0](p) / i[1](p)
335
x/y
336
337
A ``ValueError`` is raised if ``self`` has no rational point ::
338
339
sage: C = Conic(x^2 + 2*y^2 + z^2)
340
sage: C.parametrization()
341
Traceback (most recent call last):
342
...
343
ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + z^2 has no rational points over Rational Field!
344
345
A ``ValueError`` is raised if ``self`` is not smooth ::
346
347
sage: C = Conic(x^2 + y^2)
348
sage: C.parametrization()
349
Traceback (most recent call last):
350
...
351
ValueError: The conic self (=Projective Conic Curve over Rational Field defined by x^2 + y^2) is not smooth, hence does not have a parametrization.
352
"""
353
if (not self._parametrization is None) and not point:
354
par = self._parametrization
355
else:
356
if not self.is_smooth():
357
raise ValueError, "The conic self (=%s) is not smooth, hence does not have a parametrization." % self
358
if point == None:
359
point = self.rational_point()
360
point = Sequence(point)
361
Q = PolynomialRing(QQ, 'x,y')
362
[x, y] = Q.gens()
363
gens = self.ambient_space().gens()
364
M = self.symmetric_matrix()
365
M *= lcm([ t.denominator() for t in M.list() ])
366
par1 = qfparam(M, point)
367
B = Matrix([[par1[i][j] for j in range(3)] for i in range(3)])
368
# self is in the image of B and does not lie on a line,
369
# hence B is invertible
370
A = B.inverse()
371
par2 = [sum([A[i,j]*gens[j] for j in range(3)]) for i in [1,0]]
372
par = ([Q(pol(x/y)*y**2) for pol in par1], par2)
373
if self._parametrization is None:
374
self._parametrization = par
375
if not morphism:
376
return par
377
P1 = ProjectiveSpace(self.base_ring(), 1, 'x,y')
378
return P1.hom(par[0],self), self.Hom(P1)(par[1], check = False)
379
380
381