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