Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/schemes/plane_conics/con_number_field.py
8820 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 (RDF, CDF, AA, RLF, QQbar, PolynomialRing)
25
26
from sage.rings.complex_field import is_ComplexField
27
28
from sage.rings.ring import is_Ring
29
from sage.rings.rational_field import is_RationalField
30
from sage.rings.morphism import is_RingHomomorphism
31
from sage.rings.real_mpfi import is_RealIntervalField
32
from sage.rings.complex_interval_field import is_ComplexIntervalField
33
34
from con_field import ProjectiveConic_field
35
36
class ProjectiveConic_number_field(ProjectiveConic_field):
37
r"""
38
Create a projective plane conic curve over a number field.
39
See ``Conic`` for full documentation.
40
41
EXAMPLES::
42
43
sage: K.<a> = NumberField(x^3 - 2, 'a')
44
sage: P.<X, Y, Z> = K[]
45
sage: Conic(X^2 + Y^2 - a*Z^2)
46
Projective Conic Curve over Number Field in a with defining polynomial x^3 - 2 defined by X^2 + Y^2 + (-a)*Z^2
47
48
TESTS::
49
50
sage: K.<a> = NumberField(x^3 - 3, 'a')
51
sage: Conic([a, 1, -1])._test_pickling()
52
"""
53
def __init__(self, A, f):
54
r"""
55
See ``Conic`` for full documentation.
56
57
EXAMPLES ::
58
59
sage: Conic([1, 1, 1])
60
Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2
61
"""
62
ProjectiveConic_field.__init__(self, A, f)
63
64
# a single prime such that self has no point over the completion
65
self._local_obstruction = None
66
# all finite primes such that self has no point over the completion
67
self._finite_obstructions = None
68
# all infinite primes such that self has no point over the completion
69
self._infinite_obstructions = None
70
71
72
def has_rational_point(self, point = False, obstruction = False,
73
algorithm = 'default', read_cache = True):
74
r"""
75
Returns ``True`` if and only if ``self`` has a point
76
defined over its base field `B`.
77
78
If ``point`` and ``obstruction`` are both False (default),
79
then the output is a boolean ``out`` saying whether ``self``
80
has a rational point.
81
82
If ``point`` or ``obstruction`` is True, then the output is
83
a pair ``(out, S)``, where ``out`` is as above and:
84
85
- if ``point`` is True and ``self`` has a rational point,
86
then ``S`` is a rational point,
87
88
- if ``obstruction`` is True, ``self`` has no rational point,
89
then ``S`` is a prime or infinite place of `B` such that no
90
rational point exists over the completion at ``S``.
91
92
Points and obstructions are cached whenever they are found.
93
Cached information is used for the output if available, but only
94
if ``read_cache`` is True.
95
96
ALGORITHM:
97
98
The parameter ``algorithm``
99
specifies the algorithm to be used:
100
101
- ``'rnfisnorm'`` -- Use PARI's rnfisnorm
102
(cannot be combined with ``obstruction = True``)
103
104
- ``'local'`` -- Check if a local solution exists for all primes
105
and infinite places of `B` and apply the Hasse principle.
106
(Cannot be combined with ``point = True``.)
107
108
- ``'default'`` -- Use algorithm ``'rnfisnorm'`` first.
109
Then, if no point exists and obstructions are requested, use
110
algorithm ``'local'`` to find an obstruction.
111
112
- ``'magma'`` (requires Magma to be installed) --
113
delegates the task to the Magma computer algebra
114
system.
115
116
117
EXAMPLES:
118
119
An example over `\QQ` ::
120
121
sage: C = Conic(QQ, [1, 113922743, -310146482690273725409])
122
sage: C.has_rational_point(point = True)
123
(True, (-76842858034579/5424 : -5316144401/5424 : 1))
124
sage: C.has_rational_point(algorithm = 'local', read_cache = False)
125
True
126
127
Examples over number fields ::
128
129
sage: K.<i> = QuadraticField(-1)
130
sage: C = Conic(K, [1, 3, -5])
131
sage: C.has_rational_point(point = True, obstruction = True)
132
(False, Fractional ideal (-i - 2))
133
sage: C.has_rational_point(algorithm = "rnfisnorm")
134
False
135
sage: C.has_rational_point(algorithm = "rnfisnorm", obstruction = True, read_cache=False)
136
Traceback (most recent call last):
137
...
138
ValueError: Algorithm rnfisnorm cannot be combined with obstruction = True in has_rational_point
139
140
sage: P.<x> = QQ[]
141
sage: L.<b> = NumberField(x^3-5)
142
sage: C = Conic(L, [1, 2, -3])
143
sage: C.has_rational_point(point = True, algorithm = 'rnfisnorm')
144
(True, (5/3 : -1/3 : 1))
145
146
sage: K.<a> = NumberField(x^4+2)
147
sage: Conic(QQ, [4,5,6]).has_rational_point()
148
False
149
sage: Conic(K, [4,5,6]).has_rational_point()
150
True
151
sage: Conic(K, [4,5,6]).has_rational_point(algorithm='magma', read_cache=False) # optional - magma
152
True
153
154
TESTS:
155
156
Create a bunch of conics over number fields and check whether
157
``has_rational_point`` runs without errors for algorithms
158
``'rnfisnorm'`` and ``'local'``. Check if all points returned are
159
valid. If Magma is available, then also check if the output agrees with
160
Magma. ::
161
162
sage: P.<X> = QQ[]
163
sage: Q = P.fraction_field()
164
sage: c = [1, X/2, 1/X]
165
sage: l = Sequence(cartesian_product_iterator([c for i in range(3)]))
166
sage: l = l + [[X, 1, 1, 1, 1, 1]] + [[X, 1/5, 1, 1, 2, 1]]
167
sage: K.<a> = QuadraticField(-23)
168
sage: L.<b> = QuadraticField(19)
169
sage: M.<c> = NumberField(X^3+3*X+1)
170
sage: m = [[Q(b)(F.gen()) for b in a] for a in l for F in [K, L, M]]
171
sage: d = []
172
sage: c = []
173
sage: c = [Conic(a) for a in m if a != [0,0,0]]
174
sage: d = [C.has_rational_point(algorithm = 'rnfisnorm', point = True) for C in c] # long time: 3.3 seconds
175
sage: all([c[k].defining_polynomial()(Sequence(d[k][1])) == 0 for k in range(len(d)) if d[k][0]])
176
True
177
sage: [C.has_rational_point(algorithm='local', read_cache=False) for C in c] == [o[0] for o in d] # long time: 5 seconds
178
True
179
sage: [C.has_rational_point(algorithm = 'magma', read_cache=False) for C in c] == [o[0] for o in d] # long time: 3 seconds, optional - magma
180
True
181
182
Create a bunch of conics that are known to have rational points
183
already over `\QQ` and check if points are found by
184
``has_rational_point``. ::
185
186
sage: l = Sequence(cartesian_product_iterator([[-1, 0, 1] for i in range(3)]))
187
sage: K.<a> = QuadraticField(-23)
188
sage: L.<b> = QuadraticField(19)
189
sage: M.<c> = NumberField(x^5+3*x+1)
190
sage: m = [[F(b) for b in a] for a in l for F in [K, L, M]]
191
sage: c = [Conic(a) for a in m if a != [0,0,0] and a != [1,1,1] and a != [-1,-1,-1]]
192
sage: assert all([C.has_rational_point(algorithm = 'rnfisnorm') for C in c])
193
sage: assert all([C.defining_polynomial()(Sequence(C.has_rational_point(point = True)[1])) == 0 for C in c])
194
sage: assert all([C.has_rational_point(algorithm='local', read_cache=False) for C in c]) # long time: 1 second
195
"""
196
if read_cache:
197
if self._rational_point is not None:
198
if point or obstruction:
199
return True, self._rational_point
200
else:
201
return True
202
if self._local_obstruction is not None:
203
if point or obstruction:
204
return False, self._local_obstruction
205
else:
206
return False
207
if (not point) and self._finite_obstructions == [] and \
208
self._infinite_obstructions == []:
209
if obstruction:
210
return True, None
211
return True
212
if self.has_singular_point():
213
if point:
214
return self.has_singular_point(point = True)
215
if obstruction:
216
return True, None
217
return True
218
B = self.base_ring()
219
220
if algorithm == 'default':
221
ret = self.has_rational_point(point=True, obstruction=False,
222
algorithm='rnfisnorm',
223
read_cache=False)
224
if ret[0]:
225
if point or obstruction:
226
return ret
227
return True
228
if obstruction:
229
ret = self.has_rational_point(point=False, obstruction=True,
230
algorithm='local',
231
read_cache=False)
232
if ret[0]:
233
raise RuntimeError, "Outputs of algorithms in " \
234
"has_rational_point disagree " \
235
"for conic %s" % self
236
return ret
237
if point:
238
return False, None
239
return False
240
241
if algorithm == 'local':
242
if point:
243
raise ValueError, "Algorithm 'local' cannot be combined " \
244
"with point = True in has_rational_point"
245
obs = self.local_obstructions(infinite = True, finite = False,
246
read_cache = read_cache)
247
if obs != []:
248
if obstruction:
249
return False, obs[0]
250
return False
251
obs = self.local_obstructions(read_cache = read_cache)
252
if obs == []:
253
if obstruction:
254
return True, None
255
return True
256
if obstruction:
257
return False, obs[0]
258
return False
259
if algorithm == 'rnfisnorm':
260
from sage.modules.free_module_element import vector
261
if obstruction:
262
raise ValueError, "Algorithm rnfisnorm cannot be combined " \
263
"with obstruction = True in " \
264
"has_rational_point"
265
D, T = self.diagonal_matrix()
266
abc = [D[0,0], D[1,1], D[2,2]]
267
for j in range(3):
268
if abc[j] == 0:
269
pt = self.point(T*vector({2:0,j:1}))
270
if point or obstruction:
271
return True, pt
272
return True
273
if (-abc[1]/abc[0]).is_square():
274
pt = self.point(T*vector([(-abc[1]/abc[0]).sqrt(), 1, 0]))
275
if point or obstruction:
276
return True, pt
277
return True
278
if (-abc[2]/abc[0]).is_square():
279
pt = self.point(T*vector([(-abc[2]/abc[0]).sqrt(), 0, 1]))
280
if point or obstruction:
281
return True, pt
282
return True
283
if is_RationalField(B):
284
K = B
285
[KtoB, BtoK] = [K.hom(K) for i in range(2)]
286
else:
287
K = B.absolute_field('Y')
288
[KtoB, BtoK] = K.structure()
289
X = PolynomialRing(K, 'X').gen()
290
d = BtoK(-abc[1]/abc[0])
291
den = d.denominator()
292
L = K.extension(X**2 - d*den**2, names='y')
293
isnorm = BtoK(-abc[2]/abc[0]).is_norm(L, element=True)
294
if isnorm[0]:
295
296
pt = self.point(T*vector([KtoB(isnorm[1][0]),
297
KtoB(isnorm[1][1]*den), 1]))
298
if point:
299
return True, pt
300
return True
301
if point:
302
return False, None
303
return False
304
if algorithm == 'qfsolve':
305
raise TypeError, "Algorithm qfsolve in has_rational_point only " \
306
"for conics over QQ, not over %s" % B
307
if obstruction:
308
raise ValueError, "Invalid combination: obstruction=True and " \
309
"algorithm=%s" % algorithm
310
311
return ProjectiveConic_field.has_rational_point(self, point = point,
312
algorithm = algorithm, read_cache = False)
313
314
315
def is_locally_solvable(self, p):
316
r"""
317
Returns ``True`` if and only if ``self`` has a solution over the
318
completion of the base field `B` of ``self`` at ``p``. Here ``p``
319
is a finite prime or infinite place of `B`.
320
321
EXAMPLES::
322
323
sage: P.<x> = QQ[]
324
sage: K.<a> = NumberField(x^3 + 5)
325
sage: C = Conic(K, [1, 2, 3 - a])
326
sage: [p1, p2] = K.places()
327
sage: C.is_locally_solvable(p1)
328
False
329
330
sage: C.is_locally_solvable(p2)
331
True
332
333
sage: O = K.maximal_order()
334
sage: f = (2*O).factor()
335
sage: C.is_locally_solvable(f[0][0])
336
True
337
338
sage: C.is_locally_solvable(f[1][0])
339
False
340
"""
341
D, T = self.diagonal_matrix()
342
abc = [D[j, j] for j in range(3)]
343
for a in abc:
344
if a == 0:
345
return True
346
a = -abc[0]/abc[2]
347
b = -abc[1]/abc[2]
348
349
ret = self.base_ring().hilbert_symbol(a, b, p)
350
351
if ret == -1:
352
if self._local_obstruction == None:
353
if (not is_RingHomomorphism(p)) or p.codomain() is AA or \
354
p.codomain() is RLF:
355
self._local_obstruction = p
356
return False
357
358
return True
359
360
361
def local_obstructions(self, finite = True, infinite = True, read_cache = True):
362
r"""
363
Returns the sequence of finite primes and/or infinite places
364
such that ``self`` is locally solvable at those primes and places.
365
366
If the base field is `\QQ`, then the infinite place is denoted `-1`.
367
368
The parameters ``finite`` and ``infinite`` (both True by default) are
369
used to specify whether to look at finite and/or infinite places.
370
Note that ``finite = True`` involves factorization of the determinant
371
of ``self``, hence may be slow.
372
373
Local obstructions are cached. The parameter ``read_cache``
374
specifies whether to look at the cache before computing anything.
375
376
EXAMPLES ::
377
378
sage: K.<i> = QuadraticField(-1)
379
sage: Conic(K, [1, 2, 3]).local_obstructions()
380
[]
381
382
sage: L.<a> = QuadraticField(5)
383
sage: Conic(L, [1, 2, 3]).local_obstructions()
384
[Ring morphism:
385
From: Number Field in a with defining polynomial x^2 - 5
386
To: Algebraic Real Field
387
Defn: a |--> -2.236067977499790?, Ring morphism:
388
From: Number Field in a with defining polynomial x^2 - 5
389
To: Algebraic Real Field
390
Defn: a |--> 2.236067977499790?]
391
"""
392
obs0 = []
393
obs1 = []
394
B = self.base_ring()
395
if infinite:
396
if read_cache and self._infinite_obstructions != None:
397
obs0 = self._infinite_obstructions
398
else:
399
for b in B.embeddings(AA):
400
if not self.is_locally_solvable(b):
401
obs0.append(b)
402
self._infinite_obstructions = obs0
403
if finite:
404
if read_cache and self._finite_obstructions != None:
405
obs1 = self._finite_obstructions
406
else:
407
candidates = []
408
if self.determinant() != 0:
409
O = B.maximal_order()
410
for a in self.symmetric_matrix().list():
411
if a != 0:
412
for f in O.fractional_ideal(a).factor():
413
if f[1] < 0 and not f[0] in candidates:
414
candidates.append(f[0])
415
for f in O.fractional_ideal(2*self.determinant()).factor():
416
if f[1] > 0 and not f[0] in candidates:
417
candidates.append(f[0])
418
for b in candidates:
419
if not self.is_locally_solvable(b):
420
obs1.append(b)
421
self._infinite_obstructions = obs1
422
obs = obs1 + obs0
423
if finite and infinite:
424
assert len(obs) % 2 == 0
425
return obs
426
427
428
429