Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/schemes/plane_conics/con_number_field.py
4107 views
1
r"""
2
Projective plane conics over a number field
3
4
AUTHORS:
5
6
- Marco Streng (2010-07-20)
7
8
"""
9
#*****************************************************************************
10
# Copyright (C) 2009/2010 Marco Streng <[email protected]>
11
#
12
# Distributed under the terms of the GNU General Public License (GPL)
13
#
14
# This code is distributed in the hope that it will be useful,
15
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
# General Public License for more details.
18
#
19
# The full text of the GPL is available at:
20
#
21
# http://www.gnu.org/licenses/
22
#*****************************************************************************
23
24
from sage.rings.all import (is_RationalField,
25
is_RingHomomorphism, is_RealIntervalField,
26
is_ComplexField, is_ComplexIntervalField,
27
RDF, CDF, AA, QQbar, PolynomialRing)
28
29
from con_field import ProjectiveConic_field
30
31
class ProjectiveConic_number_field(ProjectiveConic_field):
32
r"""
33
Create a projective plane conic curve over a number field.
34
See ``Conic`` for full documentation.
35
36
EXAMPLES::
37
38
sage: K.<a> = NumberField(x^3 - 2, 'a')
39
sage: P.<X, Y, Z> = K[]
40
sage: Conic(X^2 + Y^2 - a*Z^2)
41
Projective Conic Curve over Number Field in a with defining polynomial x^3 - 2 defined by X^2 + Y^2 + (-a)*Z^2
42
43
TESTS::
44
45
sage: K.<a> = NumberField(x^3 - 3, 'a')
46
sage: Conic([a, 1, -1])._test_pickling()
47
"""
48
def __init__(self, A, f):
49
r"""
50
See ``Conic`` for full documentation.
51
52
EXAMPLES ::
53
54
sage: Conic([1, 1, 1])
55
Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2
56
"""
57
ProjectiveConic_field.__init__(self, A, f)
58
59
# a single prime such that self has no point over the completion
60
self._local_obstruction = None
61
# all finite primes such that self has no point over the completion
62
self._finite_obstructions = None
63
# all infinite primes such that self has no point over the completion
64
self._infinite_obstructions = None
65
66
67
def has_rational_point(self, point = False, obstruction = False,
68
algorithm = 'default', read_cache = True):
69
r"""
70
Returns ``True`` if and only if ``self`` has a point
71
defined over its base field `B`.
72
73
If ``point`` and ``obstruction`` are both False (default),
74
then the output is a boolean ``out`` saying whether ``self``
75
has a 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:
79
80
- if ``point`` is True and ``self`` has a rational point,
81
then ``S`` is a rational point,
82
83
- if ``obstruction`` is True, ``self`` has no rational point,
84
then ``S`` is a prime or infinite place of `B` such that no
85
rational point exists over the completion at ``S``.
86
Finding obstructions is not yet implemented for number fields
87
(see Sage trac ticket #10742).
88
89
Points and obstructions are cached whenever they are found.
90
Cached information is used for the output if available, but only
91
if ``read_cache`` is True.
92
93
ALGORITHM:
94
95
The parameter ``algorithm``
96
specifies the algorithm to be used:
97
98
- ``'rnfisnorm'`` -- Use PARI's rnfisnorm
99
(cannot be combined with ``obstruction = True``)
100
101
- ``'local'`` -- Check if a local solution exists for all primes
102
and infinite places of `B` and apply the Hasse principle.
103
(cannot be combined with ``point = True``, not yet implemented
104
for number fields other than `QQ`, see Sage trac ticket #10742.)
105
106
- ``'default'`` -- Use ``'rnfisnorm'``.
107
108
EXAMPLES:
109
110
An example over `\QQ` ::
111
112
sage: C = Conic(QQ, [1, 113922743, -310146482690273725409])
113
sage: C.has_rational_point(point = True)
114
(True, (-76842858034579/5424 : -5316144401/5424 : 1))
115
sage: C.has_rational_point(algorithm = 'local', read_cache = False)
116
True
117
118
Examples over number fields ::
119
120
sage: K.<i> = QuadraticField(-1)
121
sage: C = Conic(K, [1, 3, -5])
122
sage: C.has_rational_point(point = True)
123
(False, None)
124
sage: C.has_rational_point(algorithm = "rnfisnorm")
125
False
126
sage: C.has_rational_point(algorithm = "rnfisnorm", obstruction = True)
127
Traceback (most recent call last):
128
...
129
ValueError: Algorithm rnfisnorm cannot be combined with obstruction = True in has_rational_point
130
131
sage: P.<x> = QQ[]
132
sage: L.<b> = NumberField(x^3-5)
133
sage: C = Conic(L, [1, 2, -3])
134
sage: C.has_rational_point(point = True, algorithm = 'rnfisnorm')
135
(True, (5/3 : -1/3 : 1))
136
137
TESTS:
138
139
Create a bunch of conics over number fields and check if ``has_rational_point``
140
runs without errors for ``algorithm = 'rnfisnorm'``. Check if all points
141
returned are valid. ::
142
143
sage: P.<X> = QQ[]
144
sage: Q = P.fraction_field()
145
sage: c = [1, X/2, 1/X]
146
sage: l = Sequence(cartesian_product_iterator([c for i in range(3)]))
147
sage: l = l + [[X, 1, 1, 1, 1, 1]] + [[X, 1/5, 1, 1, 2, 1]]
148
sage: K.<a> = QuadraticField(-23)
149
sage: L.<b> = QuadraticField(19)
150
sage: M.<c> = NumberField(X^3+3*X+1)
151
sage: m = [[Q(b)(F.gen()) for b in a] for a in l for F in [K, L, M]]
152
sage: d = []
153
sage: c = []
154
sage: c = [Conic(a) for a in m if a != [0,0,0]] # long time: 1 second
155
sage: d = [C.has_rational_point(algorithm = 'rnfisnorm', point = True) for C in c] # long time: 15 seconds
156
sage: assert all([c[k].defining_polynomial()(Sequence(d[k][1])) == 0 for k in range(len(c)) if d[k][0]])
157
158
Create a bunch of conics that are known to have rational points
159
already over `\QQ` and check if points are found by
160
``has_rational_point``. ::
161
162
sage: l = Sequence(cartesian_product_iterator([[-1, 0, 1] for i in range(3)]))
163
sage: K.<a> = QuadraticField(-23)
164
sage: L.<b> = QuadraticField(19)
165
sage: M.<c> = NumberField(x^5+3*x+1)
166
sage: m = [[F(b) for b in a] for a in l for F in [K, L, M]]
167
sage: c = [Conic(a) for a in m if a != [0,0,0] and a != [1,1,1] and a != [-1,-1,-1]] # long time 0.4 seconds
168
sage: assert all([C.has_rational_point(algorithm = 'rnfisnorm') for C in c]) # long time: 3.5 seconds
169
sage: assert all([C.defining_polynomial()(Sequence(C.has_rational_point(point = True)[1])) == 0 for C in c]) # uses cache, long time if previous line isn't run
170
"""
171
if read_cache:
172
if self._rational_point is not None:
173
if point or obstruction:
174
return True, self._rational_point
175
else:
176
return True
177
if self._local_obstruction is not None:
178
if point or obstruction:
179
return False, self._local_obstruction
180
else:
181
return False
182
if (not point) and self._finite_obstructions == [] and \
183
self._infinite_obstructions == []:
184
if obstruction:
185
return True, None
186
return True
187
if self.has_singular_point():
188
if point:
189
return self.has_singular_point(point = True)
190
if obstruction:
191
return True, None
192
return True
193
B = self.base_ring()
194
if algorithm == 'default':
195
algorithm = 'rnfisnorm'
196
if algorithm == 'local':
197
if point:
198
raise ValueError, "Algorithm 'local' cannot be combined with " \
199
"point = True in has_rational_point"
200
obs = self.local_obstructions(infinite = True, finite = False,
201
read_cache = read_cache)
202
if obs != []:
203
if obstruction:
204
return False, obs[0]
205
return False
206
obs = self.local_obstructions(read_cache = read_cache)
207
if obs == []:
208
if obstruction:
209
return True, None
210
return True
211
if obstruction:
212
return False, obs[0]
213
return False
214
if algorithm == 'rnfisnorm':
215
from sage.modules.free_module_element import vector
216
if obstruction:
217
raise ValueError, "Algorithm rnfisnorm cannot be combined with " \
218
"obstruction = True in has_rational_point"
219
D, T = self.diagonal_matrix()
220
abc = [D[0,0], D[1,1], D[2,2]]
221
for j in range(3):
222
if abc[j] == 0:
223
pt = self.point(T*vector({2:0,j:1}))
224
if point or obstruction:
225
return True, pt
226
return True
227
if (-abc[1]/abc[0]).is_square():
228
pt = self.point(T*vector([(-abc[1]/abc[0]).sqrt(), 1, 0]))
229
if point or obstruction:
230
return True, pt
231
return True
232
if (-abc[2]/abc[0]).is_square():
233
pt = self.point(T*vector([(-abc[2]/abc[0]).sqrt(), 0, 1]))
234
if point or obstruction:
235
return True, pt
236
return True
237
if is_RationalField(B):
238
K = B
239
[KtoB, BtoK] = [K.hom(K) for i in range(2)]
240
else:
241
K = B.absolute_field('Y')
242
[KtoB, BtoK] = K.structure()
243
X = PolynomialRing(K, 'X').gen()
244
d = BtoK(-abc[1]/abc[0])
245
den = d.denominator()
246
L = K.extension(X**2 - d*den**2, names='y')
247
isnorm = BtoK(-abc[2]/abc[0]).is_norm(L, element=True)
248
if isnorm[0]:
249
250
pt = self.point(T*vector([KtoB(isnorm[1][0]),
251
KtoB(isnorm[1][1]*den), 1]))
252
if point:
253
return True, pt
254
return True
255
if point:
256
return False, None
257
return False
258
if algorithm == 'qfsolve':
259
raise TypeError, "Algorithm qfsolve in has_rational_point only " \
260
"for conics over QQ, not over %s" % B
261
raise ValueError, "Unknown algorithm %s in has_rational_point for %s" \
262
% algorithm, self
263
264
265
def is_locally_solvable(self, p):
266
r"""
267
Returns ``True`` if and only if ``self`` has a solution over the
268
completion of the base field `B` of ``self`` at ``p``. Here ``p``
269
is a finite prime or infinite place of `B`.
270
271
This is currently not implemented for Number Fields.
272
See Sage trac ticket #10742.
273
274
EXAMPLES::
275
276
sage: P.<x> = QQ[]
277
sage: K.<a> = NumberField(x^3 + 5)
278
sage: C = Conic(K, [1, 2, 3 - a])
279
sage: [p1, p2] = K.places()
280
sage: C.is_locally_solvable(p1)
281
Traceback (most recent call last):
282
...
283
NotImplementedError: Sorry, is_locally_solvable is not yet implemented for number fields.
284
285
sage: C.is_locally_solvable(p2)
286
Traceback (most recent call last):
287
...
288
NotImplementedError: Sorry, is_locally_solvable is not yet implemented for number fields.
289
290
sage: O = K.maximal_order()
291
sage: f = (2*O).factor()
292
sage: C.is_locally_solvable(f[0][0])
293
Traceback (most recent call last):
294
...
295
NotImplementedError: Sorry, is_locally_solvable is not yet implemented for number fields.
296
297
sage: C.is_locally_solvable(f[1][0])
298
Traceback (most recent call last):
299
...
300
NotImplementedError: Sorry, is_locally_solvable is not yet implemented for number fields.
301
"""
302
raise NotImplementedError, "Sorry, is_locally_solvable is not yet implemented for number fields."
303
304
305
def local_obstructions(self, finite = True, infinite = True, read_cache = True):
306
r"""
307
Returns the sequence of finite primes and/or infinite places
308
such that ``self`` is locally solvable at those primes and places.
309
310
If the base field is `\QQ`, then the infinite place is denoted `-1`.
311
312
The parameters ``finite`` and ``infinite`` (both True by default) are
313
used to specify whether to look at finite and/or infinite places.
314
Note that ``finite = True`` involves factorization of the determinant
315
of ``self``, hence may be slow.
316
317
Local obstructions are cached. The parameter ``read_cache``
318
specifies whether to look at the cache before computing anything.
319
320
This is currently not implemented for Number Fields.
321
See Sage trac ticket #10742.
322
323
EXAMPLES ::
324
325
sage: K.<i> = QuadraticField(-1)
326
sage: Conic(K, [1, 2, 3]).local_obstructions()
327
Traceback (most recent call last):
328
...
329
NotImplementedError: Sorry, is_locally_solvable is not yet implemented for number fields.
330
331
sage: L.<a> = QuadraticField(5)
332
sage: Conic(L, [1, 2, 3]).local_obstructions()
333
Traceback (most recent call last):
334
...
335
NotImplementedError: Sorry, is_locally_solvable is not yet implemented for number fields.
336
337
338
"""
339
obs0 = []
340
obs1 = []
341
B = self.base_ring()
342
if infinite:
343
if read_cache and self._infinite_obstructions != None:
344
obs0 = self._infinite_obstructions
345
else:
346
for b in B.embeddings(AA):
347
if not self.is_locally_solvable(b):
348
obs0.append(b)
349
self._infinite_obstructions = obs0
350
if finite:
351
if read_cache and self._finite_obstructions != None:
352
obs1 = self._finite_obstructions
353
else:
354
candidates = []
355
if self.determinant() != 0:
356
O = B.maximal_order()
357
for a in self.symmetric_matrix().list():
358
if a != 0:
359
for f in O.fractional_ideal(a).factor():
360
if f[1] < 0 and not f[0] in candidates:
361
candidates.append(f[0])
362
for f in O.fractional_ideal(2*self.determinant()).factor():
363
if f[1] > 0 and not f[0] in candidates:
364
candidates.append(f[0])
365
for b in candidates:
366
if not self.is_locally_solvable(b):
367
obs1.append(b)
368
self._infinite_obstructions = obs1
369
obs = obs1 + obs0
370
if finite and infinite:
371
assert len(obs) % 2 == 0
372
return obs
373
374
375
376