Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/schemes/plane_conics/con_field.py
8820 views
1
r"""
2
Projective plane conics over a field
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
28
29
from sage.rings.complex_field import is_ComplexField
30
from sage.rings.real_mpfr import is_RealField
31
32
from sage.modules.free_module_element import vector
33
from sage.structure.sequence import Sequence
34
from sage.structure.element import is_Vector
35
from sage.schemes.projective.projective_space import ProjectiveSpace
36
from sage.matrix.constructor import Matrix
37
from sage.matrix.matrix import is_Matrix
38
39
from sage.schemes.plane_curves.projective_curve import ProjectiveCurve_generic
40
41
from sage.categories.fields import Fields
42
_Fields = Fields()
43
44
class ProjectiveConic_field(ProjectiveCurve_generic):
45
r"""
46
Create a projective plane conic curve over a field.
47
See ``Conic`` for full documentation.
48
49
EXAMPLES::
50
51
sage: K = FractionField(PolynomialRing(QQ, 't'))
52
sage: P.<X, Y, Z> = K[]
53
sage: Conic(X^2 + Y^2 - Z^2)
54
Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Rational Field defined by X^2 + Y^2 - Z^2
55
56
TESTS::
57
58
sage: K = FractionField(PolynomialRing(QQ, 't'))
59
sage: Conic([K(1), 1, -1])._test_pickling()
60
"""
61
def __init__(self, A, f):
62
r"""
63
See ``Conic`` for full documentation.
64
65
EXAMPLES:
66
67
::
68
69
sage: c = Conic([1, 1, 1]); c
70
Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2
71
"""
72
ProjectiveCurve_generic.__init__(self, A, f)
73
self._coefficients = [f[(2,0,0)], f[(1,1,0)], f[(1,0,1)],
74
f[(0,2,0)], f[(0,1,1)], f[(0,0,2)]]
75
self._parametrization = None
76
self._diagonal_matrix = None
77
78
self._rational_point = None
79
80
81
82
83
def _repr_type(self):
84
r"""
85
Returns ``'Projective Conic'``, which is the first part of the
86
plain text representation of this object as output by
87
the function ``_repr_`` of the class ``Curve_generic``.
88
89
EXAMPLES::
90
91
sage: c = Conic([1, 1, 1]); c
92
Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2
93
sage: c._repr_()
94
'Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2'
95
sage: c._repr_type()
96
'Projective Conic'
97
"""
98
return "Projective Conic"
99
100
def base_extend(self, S):
101
r"""
102
Returns the conic over ``S`` given by the same equation as ``self``.
103
104
EXAMPLES::
105
106
sage: c = Conic([1, 1, 1]); c
107
Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2
108
sage: c.has_rational_point()
109
False
110
sage: d = c.base_extend(QuadraticField(-1, 'i')); d
111
Projective Conic Curve over Number Field in i with defining polynomial x^2 + 1 defined by x^2 + y^2 + z^2
112
sage: d.rational_point(algorithm = 'rnfisnorm')
113
(i : 1 : 0)
114
"""
115
if S in _Fields:
116
B = self.base_ring()
117
if B == S:
118
return self
119
if not S.has_coerce_map_from(B):
120
raise ValueError, "No natural map from the base ring of self " \
121
"(= %s) to S (= %s)" % (self, S)
122
from constructor import Conic
123
con = Conic([S(c) for c in self.coefficients()], \
124
self.variable_names())
125
if self._rational_point != None:
126
pt = [S(c) for c in Sequence(self._rational_point)]
127
if not pt == [0,0,0]:
128
# The following line stores the point in the cache
129
# if (and only if) there is no point in the cache.
130
pt = con.point(pt)
131
return con
132
return ProjectiveCurve_generic.base_extend(self, S)
133
134
def cache_point(self, p):
135
r"""
136
Replace the point in the cache of ``self`` by ``p`` for use
137
by ``self.rational_point()`` and ``self.parametrization()``.
138
139
EXAMPLES::
140
141
sage: c = Conic([1, -1, 1])
142
sage: c.point([15, 17, 8])
143
(15/8 : 17/8 : 1)
144
sage: c.rational_point()
145
(15/8 : 17/8 : 1)
146
sage: c.cache_point(c.rational_point(read_cache = False))
147
sage: c.rational_point()
148
(1 : 1 : 0)
149
"""
150
if isinstance(p, (tuple, list)):
151
p = self.point(p)
152
self._rational_point = p
153
154
def coefficients(self):
155
r"""
156
Gives a the `6` coefficients of the conic ``self``
157
in lexicographic order.
158
159
EXAMPLES::
160
161
sage: Conic(QQ, [1,2,3,4,5,6]).coefficients()
162
[1, 2, 3, 4, 5, 6]
163
164
sage: P.<x,y,z> = GF(13)[]
165
sage: a = Conic(x^2+5*x*y+y^2+z^2).coefficients(); a
166
[1, 5, 0, 1, 0, 1]
167
sage: Conic(a)
168
Projective Conic Curve over Finite Field of size 13 defined by x^2 + 5*x*y + y^2 + z^2
169
"""
170
return self._coefficients
171
172
173
def derivative_matrix(self):
174
r"""
175
Gives the derivative of the defining polynomial of
176
the conic ``self``, which is a linear map,
177
as a `3 \times 3` matrix.
178
179
EXAMPLES:
180
181
In characteristic different from `2`, the
182
derivative matrix is twice the symmetric matrix:
183
184
::
185
186
sage: c = Conic(QQ, [1,1,1,1,1,0])
187
sage: c.symmetric_matrix()
188
[ 1 1/2 1/2]
189
[1/2 1 1/2]
190
[1/2 1/2 0]
191
sage: c.derivative_matrix()
192
[2 1 1]
193
[1 2 1]
194
[1 1 0]
195
196
An example in characteristic `2`:
197
198
::
199
200
sage: P.<t> = GF(2)[]
201
sage: c = Conic([t, 1, t^2, 1, 1, 0]); c
202
Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 2 (using NTL) defined by t*x^2 + x*y + y^2 + t^2*x*z + y*z
203
sage: c.is_smooth()
204
True
205
sage: c.derivative_matrix()
206
[ 0 1 t^2]
207
[ 1 0 1]
208
[t^2 1 0]
209
"""
210
from sage.matrix.constructor import matrix
211
[a,b,c,d,e,f] = self.coefficients()
212
return matrix([[ 2*a , b , c ],
213
[ b , 2*d , e ],
214
[ c , e , 2*f ]])
215
216
def determinant(self):
217
r"""
218
Returns the determinant of the symmetric matrix that defines
219
the conic ``self``.
220
221
This is defined only if the base field has characteristic
222
different from `2`.
223
224
EXAMPLES:
225
226
::
227
228
sage: C = Conic([1,2,3,4,5,6])
229
sage: C.determinant()
230
41/4
231
sage: C.symmetric_matrix().determinant()
232
41/4
233
234
Determinants are only defined in characteristic different from `2`::
235
236
sage: C = Conic(GF(2), [1, 1, 1, 1, 1, 0])
237
sage: C.is_smooth()
238
True
239
sage: C.determinant()
240
Traceback (most recent call last):
241
...
242
ValueError: The conic self (= Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y + y^2 + x*z + y*z) has no symmetric matrix because the base field has characteristic 2
243
"""
244
return self.symmetric_matrix().determinant()
245
246
def diagonal_matrix(self):
247
r"""
248
Returns a diagonal matrix `D` and a matrix `T` such that `T^t A T = D`
249
holds, where `(x, y, z) A (x, y, z)^t` is the defining polynomial
250
of the conic ``self``.
251
252
EXAMPLES:
253
254
::
255
256
sage: c = Conic(QQ, [1,2,3,4,5,6])
257
sage: d, t = c.diagonal_matrix(); d, t
258
(
259
[ 1 0 0] [ 1 -1 -7/6]
260
[ 0 3 0] [ 0 1 -1/3]
261
[ 0 0 41/12], [ 0 0 1]
262
)
263
sage: t.transpose()*c.symmetric_matrix()*t
264
[ 1 0 0]
265
[ 0 3 0]
266
[ 0 0 41/12]
267
268
Diagonal matrices are only defined in characteristic different
269
from `2`:
270
271
::
272
273
sage: c = Conic(GF(4, 'a'), [0, 1, 1, 1, 1, 1])
274
sage: c.is_smooth()
275
True
276
sage: c.diagonal_matrix()
277
Traceback (most recent call last):
278
...
279
ValueError: The conic self (= Projective Conic Curve over Finite Field in a of size 2^2 defined by x*y + y^2 + x*z + y*z + z^2) has no symmetric matrix because the base field has characteristic 2
280
"""
281
A = self.symmetric_matrix()
282
B = self.base_ring()
283
basis = [vector(B,{2:0,i:1}) for i in range(3)]
284
for i in range(3):
285
zerovalue = (basis[i]*A*basis[i].column()== 0)
286
if zerovalue:
287
for j in range(i+1,3):
288
if basis[j]*A*basis[j].column() != 0:
289
b = basis[i]
290
basis[i] = basis[j]
291
basis[j] = b
292
zerovalue = False
293
if zerovalue:
294
for j in range(i+1,3):
295
if basis[i]*A*basis[j].column() != 0:
296
basis[i] = basis[i]+basis[j]
297
zerovalue = False
298
if not zerovalue:
299
l = (basis[i]*A*basis[i].column())
300
for j in range(i+1,3):
301
basis[j] = basis[j] - \
302
(basis[i]*A*basis[j].column())/l * basis[i]
303
T = Matrix(basis).transpose()
304
return T.transpose()*A*T, T
305
306
def diagonalization(self,names = None):
307
r"""
308
Returns a diagonal conic `C`, an isomorphism of schemes `M: C` -> ``self``
309
and the inverse `N` of `M`.
310
311
EXAMPLES::
312
313
sage: Conic(GF(5), [1,0,1,1,0,1]).diagonalization()
314
(Projective Conic Curve over Finite Field of size 5 defined by x^2 + y^2 + 2*z^2,
315
Scheme morphism:
316
From: Projective Conic Curve over Finite Field of size 5 defined by x^2 + y^2 + 2*z^2
317
To: Projective Conic Curve over Finite Field of size 5 defined by x^2 + y^2 + x*z + z^2
318
Defn: Defined on coordinates by sending (x : y : z) to
319
(x + 2*z : y : z),
320
Scheme morphism:
321
From: Projective Conic Curve over Finite Field of size 5 defined by x^2 + y^2 + x*z + z^2
322
To: Projective Conic Curve over Finite Field of size 5 defined by x^2 + y^2 + 2*z^2
323
Defn: Defined on coordinates by sending (x : y : z) to
324
(x - 2*z : y : z))
325
326
The diagonalization is only defined in characteristic different
327
from 2:
328
329
::
330
331
sage: Conic(GF(2), [1,1,1,1,1,0]).diagonalization()
332
Traceback (most recent call last):
333
...
334
ValueError: The conic self (= Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y + y^2 + x*z + y*z) has no symmetric matrix because the base field has characteristic 2
335
"""
336
if names == None:
337
names = self.defining_polynomial().parent().variable_names()
338
from constructor import Conic
339
D, T = self.diagonal_matrix()
340
con = Conic(D, names = names)
341
return con, con.hom(T, self), self.hom(T.inverse(), con)
342
343
def gens(self):
344
r"""
345
Returns the generators of the coordinate ring of ``self``.
346
347
EXAMPLES:
348
349
::
350
351
sage: P.<x,y,z> = QQ[]
352
sage: c = Conic(x^2+y^2+z^2)
353
sage: c.gens()
354
(xbar, ybar, zbar)
355
sage: c.defining_polynomial()(c.gens())
356
0
357
358
The function ``gens()`` is required for the following construction:
359
360
::
361
362
sage: C.<a,b,c> = Conic(GF(3), [1, 1, 1])
363
sage: C
364
Projective Conic Curve over Finite Field of size 3 defined by a^2 + b^2 + c^2
365
366
"""
367
return self.coordinate_ring().gens()
368
369
def has_rational_point(self, point = False,
370
algorithm = 'default', read_cache = True):
371
r"""
372
Returns True if and only if the conic ``self``
373
has a point over its base field `B`.
374
375
If ``point`` is True, then returns a second output, which is
376
a rational point if one exists.
377
378
Points are cached whenever they are found. Cached information
379
is used if and only if ``read_cache`` is True.
380
381
ALGORITHM:
382
383
The parameter ``algorithm`` specifies the algorithm
384
to be used:
385
386
- ``'default'`` -- If the base field is real or complex,
387
use an elementary native Sage implementation.
388
389
- ``'magma'`` (requires Magma to be installed) --
390
delegates the task to the Magma computer algebra
391
system.
392
393
EXAMPLES:
394
395
sage: Conic(RR, [1, 1, 1]).has_rational_point()
396
False
397
sage: Conic(CC, [1, 1, 1]).has_rational_point()
398
True
399
400
sage: Conic(RR, [1, 2, -3]).has_rational_point(point = True)
401
(True, (1.73205080756888 : 0.000000000000000 : 1.00000000000000))
402
403
Conics over polynomial rings can not be solved yet without Magma::
404
405
sage: R.<t> = QQ[]
406
sage: C = Conic([-2,t^2+1,t^2-1])
407
sage: C.has_rational_point()
408
Traceback (most recent call last):
409
...
410
NotImplementedError: has_rational_point not implemented for conics over base field Fraction Field of Univariate Polynomial Ring in t over Rational Field
411
412
But they can be solved with Magma::
413
414
sage: C.has_rational_point(algorithm='magma') # optional - magma
415
True
416
sage: C.has_rational_point(algorithm='magma', point=True) # optional - magma
417
(True, (t : 1 : 1))
418
419
sage: D = Conic([t,1,t^2])
420
sage: D.has_rational_point(algorithm='magma') # optional - magma
421
False
422
423
TESTS:
424
425
One of the following fields comes with an embedding into the complex
426
numbers, one does not. Check that they are both handled correctly by
427
the Magma interface.::
428
429
sage: K.<i> = QuadraticField(-1)
430
sage: K.coerce_embedding()
431
Generic morphism:
432
From: Number Field in i with defining polynomial x^2 + 1
433
To: Complex Lazy Field
434
Defn: i -> 1*I
435
sage: Conic(K, [1,1,1]).rational_point(algorithm='magma') # optional - magma
436
(-i : 1 : 0)
437
438
sage: x = QQ['x'].gen()
439
sage: L.<i> = NumberField(x^2+1, embedding=None)
440
sage: Conic(L, [1,1,1]).rational_point(algorithm='magma') # optional - magma
441
(-i : 1 : 0)
442
sage: L == K
443
False
444
"""
445
if read_cache:
446
if self._rational_point is not None:
447
if point:
448
return True, self._rational_point
449
else:
450
return True
451
452
B = self.base_ring()
453
454
if algorithm == 'magma':
455
from sage.interfaces.magma import magma
456
M = magma(self)
457
b = M.HasRationalPoint().sage()
458
if not point:
459
return b
460
if not b:
461
return False, None
462
M_pt = M.HasRationalPoint(nvals=2)[1]
463
464
# Various attempts will be made to convert `pt` to
465
# a Sage object. The end result will always be checked
466
# by self.point().
467
468
pt = [M_pt[1], M_pt[2], M_pt[3]]
469
470
# The first attempt is to use sequences. This is efficient and
471
# succeeds in cases where the Magma interface fails to convert
472
# number field elements, because embeddings between number fields
473
# may be lost on conversion to and from Magma.
474
# This should deal with all absolute number fields.
475
try:
476
return True, self.point([B(c.Eltseq().sage()) for c in pt])
477
except TypeError:
478
pass
479
480
# The second attempt tries to split Magma elements into
481
# numerators and denominators first. This is neccessary
482
# for the field of rational functions, because (at the moment of
483
# writing) fraction field elements are not converted automatically
484
# from Magma to Sage.
485
try:
486
return True, self.point( \
487
[B(c.Numerator().sage()/c.Denominator().sage()) for c in pt])
488
except (TypeError, NameError):
489
pass
490
491
# Finally, let the Magma interface handle conversion.
492
try:
493
return True, self.point([B(c.sage()) for c in pt])
494
except (TypeError, NameError):
495
pass
496
497
raise NotImplementedError, "No correct conversion implemented for converting the Magma point %s on %s to a correct Sage point on self (=%s)" % (M_pt, M, self)
498
499
if algorithm != 'default':
500
raise ValueError, "Unknown algorithm: %s" % algorithm
501
502
if is_ComplexField(B):
503
if point:
504
[_,_,_,d,e,f] = self._coefficients
505
if d == 0:
506
return True, self.point([0,1,0])
507
return True, self.point([0, ((e**2-4*d*f).sqrt()-e)/(2*d), 1],
508
check = False)
509
return True
510
if is_RealField(B):
511
D, T = self.diagonal_matrix()
512
[a, b, c] = [D[0,0], D[1,1], D[2,2]]
513
if a == 0:
514
ret = True, self.point(T*vector([1,0,0]), check = False)
515
elif a*c <= 0:
516
ret = True, self.point(T*vector([(-c/a).sqrt(),0,1]),
517
check = False)
518
elif b == 0:
519
ret = True, self.point(T*vector([0,1,0]), check = False)
520
elif b*c <= 0:
521
ret = True, self.point(T*vector([0,(-c/b).sqrt(),0,1]),
522
check = False)
523
else:
524
ret = False, None
525
if point:
526
return ret
527
return ret[0]
528
raise NotImplementedError, "has_rational_point not implemented for " \
529
"conics over base field %s" % B
530
531
def has_singular_point(self, point = False):
532
r"""
533
Return True if and only if the conic ``self`` has a rational
534
singular point.
535
536
If ``point`` is True, then also return a rational singular
537
point (or ``None`` if no such point exists).
538
539
EXAMPLES:
540
541
::
542
543
sage: c = Conic(QQ, [1,0,1]); c
544
Projective Conic Curve over Rational Field defined by x^2 + z^2
545
sage: c.has_singular_point(point = True)
546
(True, (0 : 1 : 0))
547
548
sage: P.<x,y,z> = GF(7)[]
549
sage: e = Conic((x+y+z)*(x-y+2*z)); e
550
Projective Conic Curve over Finite Field of size 7 defined by x^2 - y^2 + 3*x*z + y*z + 2*z^2
551
sage: e.has_singular_point(point = True)
552
(True, (2 : 4 : 1))
553
554
sage: Conic([1, 1, -1]).has_singular_point()
555
False
556
sage: Conic([1, 1, -1]).has_singular_point(point = True)
557
(False, None)
558
559
``has_singular_point`` is not implemented over all fields
560
of characteristic `2`. It is implemented over finite fields.
561
562
::
563
564
sage: F.<a> = FiniteField(8)
565
sage: Conic([a, a+1, 1]).has_singular_point(point = True)
566
(True, (a + 1 : 0 : 1))
567
568
sage: P.<t> = GF(2)[]
569
sage: C = Conic(P, [t,t,1]); C
570
Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 2 (using NTL) defined by t*x^2 + t*y^2 + z^2
571
sage: C.has_singular_point(point = False)
572
Traceback (most recent call last):
573
...
574
NotImplementedError: Sorry, find singular point on conics not implemented over all fields of characteristic 2.
575
"""
576
if not point:
577
ret = self.has_singular_point(point = True)
578
return ret[0]
579
B = self.base_ring()
580
if B.characteristic() == 2:
581
[a,b,c,d,e,f] = self.coefficients()
582
if b == 0 and c == 0 and e == 0:
583
for i in range(3):
584
if [a, d, f][i] == 0:
585
return True, self.point(vector(B, {2:0, i:1}))
586
if hasattr(a/f, 'is_square') and hasattr(a/f, 'sqrt'):
587
if (a/f).is_square():
588
return True, self.point([1,0,(a/f).sqrt()])
589
if (d/f).is_square():
590
return True, self.point([0,1,(d/f).sqrt()])
591
raise NotImplementedError, "Sorry, find singular point on conics not implemented over all fields of characteristic 2."
592
pt = [e, c, b]
593
if self.defining_polynomial()(pt) == 0:
594
return True, self.point(pt)
595
return False, None
596
D = self.symmetric_matrix()
597
if D.determinant() == 0:
598
return True, self.point(Sequence(D.right_kernel().gen()))
599
return False, None
600
601
def hom(self, x, Y=None):
602
r"""
603
Return the scheme morphism from ``self`` to ``Y`` defined by ``x``.
604
Here ``x`` can be a matrix or a sequence of polynomials.
605
If ``Y`` is omitted, then a natural image is found if possible.
606
607
EXAMPLES:
608
609
Here are a few Morphisms given by matrices. In the first
610
example, ``Y`` is omitted, in the second example, ``Y`` is specified.
611
612
::
613
614
sage: c = Conic([-1, 1, 1])
615
sage: h = c.hom(Matrix([[1,1,0],[0,1,0],[0,0,1]])); h
616
Scheme morphism:
617
From: Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2
618
To: Projective Conic Curve over Rational Field defined by -x^2 + 2*x*y + z^2
619
Defn: Defined on coordinates by sending (x : y : z) to
620
(x + y : y : z)
621
sage: h([-1, 1, 0])
622
(0 : 1 : 0)
623
624
sage: c = Conic([-1, 1, 1])
625
sage: d = Conic([4, 1, -1])
626
sage: c.hom(Matrix([[0, 0, 1/2], [0, 1, 0], [1, 0, 0]]), d)
627
Scheme morphism:
628
From: Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2
629
To: Projective Conic Curve over Rational Field defined by 4*x^2 + y^2 - z^2
630
Defn: Defined on coordinates by sending (x : y : z) to
631
(1/2*z : y : x)
632
633
``ValueError`` is raised if the wrong codomain ``Y`` is specified:
634
635
::
636
637
sage: c = Conic([-1, 1, 1])
638
sage: c.hom(Matrix([[0, 0, 1/2], [0, 1, 0], [1, 0, 0]]), c)
639
Traceback (most recent call last):
640
...
641
ValueError: The matrix x (= [ 0 0 1/2]
642
[ 0 1 0]
643
[ 1 0 0]) does not define a map from self (= Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2) to Y (= Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2)
644
"""
645
if is_Matrix(x):
646
from constructor import Conic
647
y = x.inverse()
648
A = y.transpose()*self.matrix()*y
649
im = Conic(A)
650
if Y == None:
651
Y = im
652
else:
653
q = Y.defining_polynomial()/im.defining_polynomial()
654
if not (q.numerator().is_constant()
655
and q.denominator().is_constant()):
656
raise ValueError, "The matrix x (= %s) does not define a " \
657
"map from self (= %s) to Y (= %s)" % \
658
(x, self, Y)
659
x = Sequence(x*vector(self.ambient_space().gens()))
660
return self.Hom(Y)(x, check = False)
661
return ProjectiveCurve_generic.hom(self, x, Y)
662
663
664
def is_diagonal(self):
665
r"""
666
Return True if and only if the conic has the form
667
`a*x^2 + b*y^2 + c*z^2`.
668
669
EXAMPLES:
670
671
::
672
673
sage: c=Conic([1,1,0,1,0,1]); c
674
Projective Conic Curve over Rational Field defined by x^2 + x*y + y^2 + z^2
675
sage: d,t = c.diagonal_matrix()
676
sage: c.is_diagonal()
677
False
678
sage: c.diagonalization()[0].is_diagonal()
679
True
680
"""
681
return all([self.coefficients()[i] == 0 for i in [1,2,4]])
682
683
684
def is_smooth(self):
685
r"""
686
Returns True if and only if ``self`` is smooth.
687
688
EXAMPLES:
689
690
::
691
692
sage: Conic([1,-1,0]).is_smooth()
693
False
694
sage: Conic(GF(2),[1,1,1,1,1,0]).is_smooth()
695
True
696
"""
697
if self.base_ring().characteristic() == 2:
698
[a,b,c,d,e,f] = self.coefficients()
699
if b == 0 and c == 0 and e == 0:
700
return False
701
return self.defining_polynomial()([e, c, b]) != 0
702
return self.determinant() != 0
703
704
705
def _magma_init_(self, magma):
706
"""
707
Internal function. Returns a string to initialize this
708
conic in the Magma subsystem.
709
710
EXAMPLES::
711
712
sage: C = Conic(QQ, [1,2,3])
713
sage: C._magma_init_(magma) # optional - magma
714
'Conic([_sage_ref...|1/1,2/1,3/1,0/1,0/1,0/1])'
715
sage: C = Conic(GF(41), [-1,2,5]) # optional - magma
716
sage: C._magma_init_(magma) # optional - magma
717
'Conic([_sage_ref...|GF(41)!40,GF(41)!2,GF(41)!5,GF(41)!0,GF(41)!0,GF(41)!0])'
718
sage: F.<a> = GF(25)
719
sage: C = Conic([3,0,1,4,a,2])
720
sage: C
721
Projective Conic Curve over Finite Field in a of size 5^2 defined by -2*x^2 - y^2 + x*z + (a)*y*z + 2*z^2
722
sage: magma(C) # optional - magma
723
Conic over GF(5^2) defined by
724
3*X^2 + 4*Y^2 + X*Z + a*Y*Z + 2*Z^2
725
sage: magma(Conic([1/2,2/3,-4/5,6/7,8/9,-10/11])) # optional - magma
726
Conic over Rational Field defined by
727
1/2*X^2 + 2/3*X*Y + 6/7*Y^2 - 4/5*X*Z + 8/9*Y*Z - 10/11*Z^2
728
sage: R.<x> = Frac(QQ['x'])
729
sage: magma(Conic([x,1+x,1-x])) # optional - magma
730
Conic over Univariate rational function field over Rational Field defined by
731
x*X^2 + (x + 1)*Y^2 + (-x + 1)*Z^2
732
sage: P.<x> = QQ[]
733
sage: K.<b> = NumberField(x^3+x+1)
734
sage: magma(Conic([b,1,2])) # optional - magma
735
Conic over Number Field with defining polynomial x^3 + x + 1 over the Rational Field defined by
736
b*X^2 + Y^2 + 2*Z^2
737
"""
738
kmn = magma(self.base_ring())._ref()
739
coeffs = self.coefficients()
740
magma_coeffs = [coeffs[i]._magma_init_(magma) for i in [0, 3, 5, 1, 4, 2]]
741
return 'Conic([%s|%s])' % (kmn,','.join(magma_coeffs))
742
743
744
def matrix(self):
745
r"""
746
Returns a matrix `M` such that `(x, y, z) M (x, y, z)^t`
747
is the defining equation of ``self``.
748
749
The matrix `M` is upper triangular if the base field has
750
characteristic `2` and symmetric otherwise.
751
752
EXAMPLES::
753
754
sage: R.<x, y, z> = QQ[]
755
sage: C = Conic(x^2 + x*y + y^2 + z^2)
756
sage: C.matrix()
757
[ 1 1/2 0]
758
[1/2 1 0]
759
[ 0 0 1]
760
761
sage: R.<x, y, z> = GF(2)[]
762
sage: C = Conic(x^2 + x*y + y^2 + x*z + z^2)
763
sage: C.matrix()
764
[1 1 1]
765
[0 1 0]
766
[0 0 1]
767
"""
768
if self.base_ring().characteristic() == 2:
769
return self.upper_triangular_matrix()
770
return self.symmetric_matrix()
771
772
_matrix_ = matrix
773
774
def parametrization(self, point=None, morphism=True):
775
r"""
776
Return a parametrization `f` of ``self`` together with the
777
inverse of `f`.
778
779
If ``point`` is specified, then that point is used
780
for the parametrization. Otherwise, use ``self.rational_point()``
781
to find a point.
782
783
If ``morphism`` is True, then `f` is returned in the form
784
of a Scheme morphism. Otherwise, it is a tuple of polynomials
785
that gives the parametrization.
786
787
EXAMPLES:
788
789
An example over a finite field ::
790
791
sage: c = Conic(GF(2), [1,1,1,1,1,0])
792
sage: c.parametrization()
793
(Scheme morphism:
794
From: Projective Space of dimension 1 over Finite Field of size 2
795
To: Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y
796
+ y^2 + x*z + y*z
797
Defn: Defined on coordinates by sending (x : y) to
798
(x*y + y^2 : x^2 + x*y : x^2 + x*y + y^2),
799
Scheme morphism:
800
From: Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y
801
+ y^2 + x*z + y*z
802
To: Projective Space of dimension 1 over Finite Field of size 2
803
Defn: Defined on coordinates by sending (x : y : z) to
804
(y : x))
805
806
An example with ``morphism = False`` ::
807
808
sage: R.<x,y,z> = QQ[]
809
sage: C = Curve(7*x^2 + 2*y*z + z^2)
810
sage: (p, i) = C.parametrization(morphism = False); (p, i)
811
([-2*x*y, 7*x^2 + y^2, -2*y^2], [-1/2*x, -1/2*z])
812
sage: C.defining_polynomial()(p)
813
0
814
sage: i[0](p) / i[1](p)
815
x/y
816
817
A ``ValueError`` is raised if ``self`` has no rational point ::
818
819
sage: C = Conic(x^2 + y^2 + 7*z^2)
820
sage: C.parametrization()
821
Traceback (most recent call last):
822
...
823
ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + y^2 + 7*z^2 has no rational points over Rational Field!
824
825
A ``ValueError`` is raised if ``self`` is not smooth ::
826
827
sage: C = Conic(x^2 + y^2)
828
sage: C.parametrization()
829
Traceback (most recent call last):
830
...
831
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.
832
"""
833
if (not self._parametrization is None) and not point:
834
par = self._parametrization
835
else:
836
if not self.is_smooth():
837
raise ValueError, "The conic self (=%s) is not smooth, hence does not have a parametrization." % self
838
if point == None:
839
point = self.rational_point()
840
point = Sequence(point)
841
B = self.base_ring()
842
Q = PolynomialRing(B, 'x,y')
843
[x, y] = Q.gens()
844
gens = self.ambient_space().gens()
845
P = PolynomialRing(B, 4, ['X', 'Y', 'T0', 'T1'])
846
[X, Y, T0, T1] = P.gens()
847
c3 = [j for j in range(2,-1,-1) if point[j] != 0][0]
848
c1 = [j for j in range(3) if j != c3][0]
849
c2 = [j for j in range(3) if j != c3 and j != c1][0]
850
L = [0,0,0]
851
L[c1] = Y*T1*point[c1] + Y*T0
852
L[c2] = Y*T1*point[c2] + X*T0
853
L[c3] = Y*T1*point[c3]
854
bezout = P(self.defining_polynomial()(L) / T0)
855
t = [bezout([x,y,0,-1]),bezout([x,y,1,0])]
856
par = (tuple([Q(p([x,y,t[0],t[1]])/y) for p in L]),
857
tuple([gens[m]*point[c3]-gens[c3]*point[m]
858
for m in [c2,c1]]))
859
if self._parametrization is None:
860
self._parametrization = par
861
if not morphism:
862
return par
863
P1 = ProjectiveSpace(self.base_ring(), 1, 'x,y')
864
return P1.hom(par[0],self), self.Hom(P1)(par[1], check = False)
865
866
def point(self, v, check=True):
867
r"""
868
Constructs a point on ``self`` corresponding to the input ``v``.
869
870
If ``check`` is True, then checks if ``v`` defines a valid
871
point on ``self``.
872
873
If no rational point on ``self`` is known yet, then also caches the point
874
for use by ``self.rational_point()`` and ``self.parametrization()``.
875
876
EXAMPLES ::
877
878
sage: c = Conic([1, -1, 1])
879
sage: c.point([15, 17, 8])
880
(15/8 : 17/8 : 1)
881
sage: c.rational_point()
882
(15/8 : 17/8 : 1)
883
sage: d = Conic([1, -1, 1])
884
sage: d.rational_point()
885
(1 : 1 : 0)
886
"""
887
if is_Vector(v):
888
v = Sequence(v)
889
p = ProjectiveCurve_generic.point(self, v, check=check)
890
if self._rational_point is None:
891
self._rational_point = p
892
return p
893
894
895
def random_rational_point(self, *args1, **args2):
896
r"""
897
Return a random rational point of the conic ``self``.
898
899
ALGORITHM:
900
901
1. Compute a parametrization `f` of ``self`` using
902
``self.parametrization()``.
903
2. Computes a random point `(x:y)` on the projective
904
line.
905
3. Output `f(x:y)`.
906
907
The coordinates x and y are computed using
908
``B.random_element``, where ``B`` is the base field of
909
``self`` and additional arguments to ``random_rational_point``
910
are passed to ``random_element``.
911
912
If the base field is a finite field, then the
913
output is uniformly distributed over the points of self.
914
915
EXAMPLES ::
916
917
sage: c = Conic(GF(2), [1,1,1,1,1,0])
918
sage: [c.random_rational_point() for i in range(10)] # output is random
919
[(1 : 0 : 1), (1 : 0 : 1), (1 : 0 : 1), (0 : 1 : 1), (1 : 0 : 1), (0 : 0 : 1), (1 : 0 : 1), (1 : 0 : 1), (0 : 0 : 1), (1 : 0 : 1)]
920
921
sage: d = Conic(QQ, [1, 1, -1])
922
sage: d.random_rational_point(den_bound = 1, num_bound = 5) # output is random
923
(-24/25 : 7/25 : 1)
924
925
sage: Conic(QQ, [1, 1, 1]).random_rational_point()
926
Traceback (most recent call last):
927
...
928
ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2 has no rational points over Rational Field!
929
930
"""
931
if not self.is_smooth():
932
raise NotImplementedError, "Sorry, random points not implemented " \
933
"for non-smooth conics"
934
par = self.parametrization()
935
x = 0
936
y = 0
937
B = self.base_ring()
938
while x == 0 and y == 0:
939
x = B.random_element(*args1, **args2)
940
y = B.random_element(*args1, **args2)
941
return par[0]([x,y])
942
943
944
def rational_point(self, algorithm = 'default', read_cache = True):
945
r"""
946
Return a point on ``self`` defined over the base field.
947
948
Raises ``ValueError`` if no rational point exists.
949
950
See ``self.has_rational_point`` for the algorithm used
951
and for the use of the parameters ``algorithm`` and ``read_cache``.
952
953
EXAMPLES:
954
955
Examples over `\QQ` ::
956
957
sage: R.<x,y,z> = QQ[]
958
sage: C = Conic(7*x^2 + 2*y*z + z^2)
959
sage: C.rational_point()
960
(0 : 1 : 0)
961
962
sage: C = Conic(x^2 + 2*y^2 + z^2)
963
sage: C.rational_point()
964
Traceback (most recent call last):
965
...
966
ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + z^2 has no rational points over Rational Field!
967
968
sage: C = Conic(x^2 + y^2 + 7*z^2)
969
sage: C.rational_point(algorithm = 'rnfisnorm')
970
Traceback (most recent call last):
971
...
972
ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + y^2 + 7*z^2 has no rational points over Rational Field!
973
974
Examples over number fields ::
975
976
sage: P.<x> = QQ[]
977
sage: L.<b> = NumberField(x^3-5)
978
sage: C = Conic(L, [3, 2, -5])
979
sage: p = C.rational_point(algorithm = 'rnfisnorm')
980
sage: p # output is random
981
(60*b^2 - 196*b + 161 : -120*b^2 - 6*b + 361 : 1)
982
sage: C.defining_polynomial()(list(p))
983
0
984
985
sage: K.<i> = QuadraticField(-1)
986
sage: D = Conic(K, [3, 2, 5])
987
sage: D.rational_point(algorithm = 'rnfisnorm') # output is random
988
(-3 : 4*i : 1)
989
990
sage: L.<s> = QuadraticField(2)
991
sage: Conic(QQ, [1, 1, -3]).has_rational_point()
992
False
993
sage: E = Conic(L, [1, 1, -3])
994
sage: E.rational_point() # output is random
995
(-1 : -s : 1)
996
997
Currently Magma is better at solving conics over number fields than
998
Sage, so it helps to use the algorithm 'magma' if Magma is installed::
999
1000
sage: q = C.rational_point(algorithm = 'magma', read_cache=False) # optional - magma
1001
sage: q # output is random, optional - magma
1002
(-1 : -1 : 1)
1003
sage: C.defining_polynomial()(list(p)) # optional - magma
1004
0
1005
sage: len(str(p)) / len(str(q)) > 2 # optional - magma
1006
True
1007
1008
sage: D.rational_point(algorithm = 'magma', read_cache=False) # random, optional - magma
1009
(1 : 2*i : 1)
1010
1011
sage: E.rational_point(algorithm='magma', read_cache=False) # random, optional - magma
1012
(-s : 1 : 1)
1013
1014
sage: F = Conic([L.gen(), 30, -20])
1015
sage: q = F.rational_point(algorithm='magma') # optional - magma
1016
sage: q # output is random, optional - magma
1017
(-10/7*s + 40/7 : 5/7*s - 6/7 : 1)
1018
sage: p = F.rational_point(read_cache=False)
1019
sage: p # output is random
1020
(788210*s - 1114700 : -171135*s + 242022 : 1)
1021
sage: len(str(p)) > len(str(q)) # optional - magma
1022
True
1023
1024
sage: Conic([L.gen(), 30, -21]).has_rational_point(algorithm='magma') # optional - magma
1025
False
1026
1027
Examples over finite fields ::
1028
1029
sage: F.<a> = FiniteField(7^20)
1030
sage: C = Conic([1, a, -5]); C
1031
Projective Conic Curve over Finite Field in a of size 7^20 defined by x^2 + (a)*y^2 + 2*z^2
1032
sage: C.rational_point() # output is random
1033
(4*a^19 + 5*a^18 + 4*a^17 + a^16 + 6*a^15 + 3*a^13 + 6*a^11 + a^9 + 3*a^8 + 2*a^7 + 4*a^6 + 3*a^5 + 3*a^4 + a^3 + a + 6 : 5*a^18 + a^17 + a^16 + 6*a^15 + 4*a^14 + a^13 + 5*a^12 + 5*a^10 + 2*a^9 + 6*a^8 + 6*a^7 + 6*a^6 + 2*a^4 + 3 : 1)
1034
1035
Examples over `\RR` and `\CC` ::
1036
1037
sage: Conic(CC, [1, 2, 3]).rational_point()
1038
(0 : 1.22474487139159*I : 1)
1039
1040
sage: Conic(RR, [1, 1, 1]).rational_point()
1041
Traceback (most recent call last):
1042
...
1043
ValueError: Conic Projective Conic Curve over Real Field with 53 bits of precision defined by x^2 + y^2 + z^2 has no rational points over Real Field with 53 bits of precision!
1044
"""
1045
bl,pt = self.has_rational_point(point = True, algorithm = algorithm,
1046
read_cache = read_cache)
1047
if bl:
1048
return pt
1049
raise ValueError, "Conic %s has no rational points over %s!" % \
1050
(self, self.ambient_space().base_ring())
1051
1052
1053
def singular_point(self):
1054
r"""
1055
Returns a singular rational point of ``self``
1056
1057
EXAMPLES:
1058
1059
::
1060
1061
sage: Conic(GF(2), [1,1,1,1,1,1]).singular_point()
1062
(1 : 1 : 1)
1063
1064
``ValueError`` is raised if the conic has no rational singular point
1065
1066
::
1067
1068
sage: Conic(QQ, [1,1,1,1,1,1]).singular_point()
1069
Traceback (most recent call last):
1070
...
1071
ValueError: The conic self (= Projective Conic Curve over Rational Field defined by x^2 + x*y + y^2 + x*z + y*z + z^2) has no rational singular point
1072
"""
1073
b = self.has_singular_point(point = True)
1074
if not b[0]:
1075
raise ValueError, "The conic self (= %s) has no rational " \
1076
"singular point" % self
1077
return b[1]
1078
1079
def symmetric_matrix(self):
1080
r"""
1081
The symmetric matrix `M` such that `(x y z) M (x y z)^t`
1082
is the defining equation of ``self``.
1083
1084
EXAMPLES ::
1085
1086
sage: R.<x, y, z> = QQ[]
1087
sage: C = Conic(x^2 + x*y/2 + y^2 + z^2)
1088
sage: C.symmetric_matrix()
1089
[ 1 1/4 0]
1090
[1/4 1 0]
1091
[ 0 0 1]
1092
1093
sage: C = Conic(x^2 + 2*x*y + y^2 + 3*x*z + z^2)
1094
sage: v = vector([x, y, z])
1095
sage: v * C.symmetric_matrix() * v
1096
x^2 + 2*x*y + y^2 + 3*x*z + z^2
1097
"""
1098
[a,b,c,d,e,f] = self.coefficients()
1099
if self.base_ring().characteristic() == 2:
1100
if b == 0 and c == 0 and e == 0:
1101
return matrix([[a,0,0],[0,d,0],[0,0,f]])
1102
raise ValueError, "The conic self (= %s) has no symmetric matrix " \
1103
"because the base field has characteristic 2" % \
1104
self
1105
from sage.matrix.constructor import matrix
1106
return matrix([[ a , b/2, c/2 ],
1107
[ b/2, d , e/2 ],
1108
[ c/2, e/2, f ]])
1109
1110
1111
def upper_triangular_matrix(self):
1112
r"""
1113
The upper-triangular matrix `M` such that `(x y z) M (x y z)^t`
1114
is the defining equation of ``self``.
1115
1116
EXAMPLES::
1117
1118
sage: R.<x, y, z> = QQ[]
1119
sage: C = Conic(x^2 + x*y + y^2 + z^2)
1120
sage: C.upper_triangular_matrix()
1121
[1 1 0]
1122
[0 1 0]
1123
[0 0 1]
1124
1125
sage: C = Conic(x^2 + 2*x*y + y^2 + 3*x*z + z^2)
1126
sage: v = vector([x, y, z])
1127
sage: v * C.upper_triangular_matrix() * v
1128
x^2 + 2*x*y + y^2 + 3*x*z + z^2
1129
"""
1130
from sage.matrix.constructor import matrix
1131
[a,b,c,d,e,f] = self.coefficients()
1132
return matrix([[ a, b, c ],
1133
[ 0, d, e ],
1134
[ 0, 0, f ]])
1135
1136
def variable_names(self):
1137
r"""
1138
Returns the variable names of the defining polynomial
1139
of ``self``.
1140
1141
EXAMPLES:
1142
1143
::
1144
1145
sage: c=Conic([1,1,0,1,0,1], 'x,y,z')
1146
sage: c.variable_names()
1147
('x', 'y', 'z')
1148
sage: c.variable_name()
1149
'x'
1150
1151
The function ``variable_names()`` is required
1152
for the following construction:
1153
1154
::
1155
1156
sage: C.<p,q,r> = Conic(QQ, [1, 1, 1])
1157
sage: C
1158
Projective Conic Curve over Rational Field defined by p^2 + q^2 + r^2
1159
1160
"""
1161
return self.defining_polynomial().parent().variable_names()
1162
1163
1164
1165