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