Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/quadratic_forms/ternary_qf.py
8817 views
1
"""
2
Ternary Quadratic Form with integer coefficients.
3
4
AUTHOR:
5
6
- Gustavo Rama
7
8
Based in code of Gonzalo Tornaria
9
10
The form `a*x^2 + b*y^2 + c*z^2 + r*yz + s*xz + t*xy` is stored as a tuple (a, b, c, r, s, t) of integers.
11
12
"""
13
14
#*****************************************************************************
15
# Copyright (C) 2012 Gustavo Rama
16
#
17
# Distributed under the terms of the GNU General Public License (GPL)
18
#
19
# This code is distributed in the hope that it will be useful,
20
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22
# General Public License for more details.
23
#
24
# The full text of the GPL is available at:
25
#
26
# http://www.gnu.org/licenses/
27
#*****************************************************************************
28
29
30
from sage.structure.sage_object import SageObject
31
from sage.rings.all import ZZ
32
from sage.rings.arith import gcd, inverse_mod, kronecker_symbol
33
from sage.quadratic_forms.quadratic_form import QuadraticForm
34
from sage.matrix.constructor import matrix, identity_matrix
35
from sage.matrix.matrix import Matrix, is_Matrix
36
from sage.structure.element import is_Vector
37
from sage.quadratic_forms.ternary import _reduced_ternary_form_eisenstein_with_matrix
38
from sage.quadratic_forms.ternary import _reduced_ternary_form_eisenstein_without_matrix, _find_zeros_mod_p_odd, _find_zeros_mod_p_2, _find_p_neighbor_from_vec, _basic_lemma
39
from sage.quadratic_forms.ternary import _find_all_ternary_qf_by_level_disc, _find_a_ternary_qf_by_level_disc
40
from sage.misc.prandom import randint
41
from sage.rings.finite_rings.integer_mod import mod
42
from sage.modules.free_module_element import vector
43
from sage.rings.ring import is_Ring
44
from sage.rings.rational_field import QQ
45
from sage.rings.polynomial.polynomial_ring import polygen, polygens
46
47
class TernaryQF(SageObject):
48
"""
49
The ``TernaryQF`` class represents a quadratic form in 3 variables with coefficients in Z.
50
51
INPUT:
52
- `v` -- a list or tuple of 6 entries: [a,b,c,r,s,t]
53
54
OUTPUT:
55
- the ternary quadratic form a*x^2 + b*y^2 + c*z^2 + r*y*z + s*x*z + t*x*y.
56
57
EXAMPLES::
58
59
sage: Q = TernaryQF([1, 2, 3, 4, 5, 6])
60
sage: Q
61
Ternary quadratic form with integer coefficients:
62
[1 2 3]
63
[4 5 6]
64
sage: A = matrix(ZZ, 3, [1, -7, 1, 0, -2, 1, 0, -1, 0])
65
sage: Q(A)
66
Ternary quadratic form with integer coefficients:
67
[1 187 9]
68
[-85 8 -31]
69
sage: TestSuite(TernaryQF).run()
70
71
72
"""
73
74
75
__slots__ = ['_a', '_b', '_c', '_r', '_s', '_t', '_automorphisms', '_number_of_automorphisms']
76
77
possible_automorphisms = None
78
79
def __init__(self,v):
80
"""
81
Creates the ternary quadratic form `a*x^2 + b*y^2 + c*z^2 + r*y*z + s*x*z + t*x*y.` from the
82
tuple v=[a,b,c,r,s,t] over `\ZZ`.
83
84
INPUT:
85
86
- ``v`` -- 6-tuple of integers
87
88
EXAMPLES::
89
90
sage: Q = TernaryQF([1, 2, 3, 4, 5, 6])
91
sage: Q
92
Ternary quadratic form with integer coefficients:
93
[1 2 3]
94
[4 5 6]
95
96
97
"""
98
99
if len(v) != 6:
100
# Check we have six coefficients
101
raise ValueError, "Ternary quadratic form must be given by a list of six coefficients"
102
self._a, self._b, self._c, self._r, self._s, self._t = [ZZ(x) for x in v]
103
self._automorphisms = None
104
self._number_of_automorphisms = None
105
106
107
def coefficients(self):
108
"""
109
Return the list coefficients of the ternary quadratic form.
110
111
EXAMPLES::
112
113
sage: Q = TernaryQF([1, 2, 3, 4, 5, 6])
114
sage: Q
115
Ternary quadratic form with integer coefficients:
116
[1 2 3]
117
[4 5 6]
118
sage: Q.coefficients()
119
(1, 2, 3, 4, 5, 6)
120
121
"""
122
123
return self._a, self._b, self._c, self._r, self._s, self._t
124
125
def coefficient(self,n):
126
"""
127
Return the n-th coefficient of the ternary quadratic form, with 0<=n<=5.
128
129
EXAMPLES::
130
131
sage: Q = TernaryQF([1, 2, 3, 4, 5, 6])
132
sage: Q
133
Ternary quadratic form with integer coefficients:
134
[1 2 3]
135
[4 5 6]
136
sage: Q.coefficient(2)
137
3
138
sage: Q.coefficient(5)
139
6
140
141
"""
142
143
return self.coefficients()[n]
144
145
def polynomial(self,names='x,y,z'):
146
"""
147
Return the polynomial associated to the ternary quadratic form.
148
149
EXAMPLES::
150
151
sage: Q = TernaryQF([1, 1, 0, 2, -3, -1])
152
sage: Q
153
Ternary quadratic form with integer coefficients:
154
[1 1 0]
155
[2 -3 -1]
156
sage: p = Q.polynomial()
157
sage: p
158
x^2 - x*y + y^2 - 3*x*z + 2*y*z
159
sage: p.parent()
160
Multivariate Polynomial Ring in x, y, z over Integer Ring
161
162
"""
163
(x,y,z) = polygens(ZZ,names)
164
return self._a * x**2 + self._b* y**2 + self._c * z**2 + self._t * x*y + self._s * x*z + self._r * y*z
165
166
167
def _repr_(self):
168
"""
169
Display the quadratic form.
170
171
EXAMPLES::
172
173
sage: Q = TernaryQF([1, 1, 0, 2, -3, -1])
174
sage: print Q._repr_()
175
Ternary quadratic form with integer coefficients:
176
[1 1 0]
177
[2 -3 -1]
178
sage: Q = TernaryQF([0, 0, 0, 0, 0, 0]); Q
179
Ternary quadratic form with integer coefficients:
180
[0 0 0]
181
[0 0 0]
182
183
184
"""
185
rep = 'Ternary quadratic form with integer coefficients:\n'
186
rep+= '[' + str(self._a) + ' ' + str(self._b) + ' ' + str(self._c) + ']\n'
187
rep+= '[' + str(self._r) + ' ' + str(self._s) + ' ' + str(self._t) + ']'
188
return rep
189
190
def __call__(self, v):
191
"""
192
Evaluate this ternary quadratic form Q on a vector of 3 elements, or matrix of elements in Z, with 3 rows. If a vector is given then the output will be an integer Q(`v`), but if a matrix is given the output will be a ternary quadratic form if the matrix has 3 columns, or a quadratic form if not. The quadratic form in matrix notation will be:
193
194
.. math::
195
Q' = v^t * Q * v.
196
197
EXAMPLES::
198
199
sage: Q = TernaryQF([1, 1, 1, -1, -2, -3])
200
sage: Q((1, 1, 1))
201
-3
202
sage: M = matrix(ZZ, 3, 2, [358, 6, 2, 0, 0, 4])
203
sage: Q(M)
204
Quadratic form in 2 variables over Integer Ring with coefficients:
205
[ 126020 1388 ]
206
[ * 4 ]
207
sage: M = matrix(ZZ, 3, 3, [1, 3, 0, -1, 4, 2, 1, -1, -1])
208
sage: M
209
[ 1 3 0]
210
[-1 4 2]
211
[ 1 -1 -1]
212
sage: Q(M)
213
Ternary quadratic form with integer coefficients:
214
[5 0 7]
215
[12 -13 -16]
216
217
"""
218
if is_Matrix(v):
219
## Check that v has 3 rows
220
if v.nrows() != 3:
221
raise TypeError, "Oops! The matrix must have 3 rows."
222
## Check if v has 3 cols
223
if v.ncols() == 3:
224
M = v.transpose() * self.matrix() * v
225
return TernaryQF([M[0,0]//2, M[1,1]//2, M[2,2]//2, M[1,2], M[0,2], M[0,1]])
226
else:
227
return QuadraticForm(ZZ, v.transpose() * self.matrix() * v)
228
elif (is_Vector(v) or isinstance(v, (list, tuple))):
229
## Check that v has lenght 3
230
if not (len(v) == 3):
231
raise TypeError, "Oops! Your vector needs to have length 3"
232
v0, v1, v2 = v
233
a, b, c, r, s, t = self.coefficients()
234
return a*v0**2 + b*v1**2 + c*v2**2 + r*v1*v2 + s*v0*v2 + t*v0*v1
235
else:
236
raise TypeError, "Oops! Presently we can only evaluate a quadratic form on a list, tuple, vector ot matrix"
237
238
239
def quadratic_form(self):
240
"""
241
Return the object QuadraticForm with the same coefficients as Q over ZZ.
242
243
EXAMPLES::
244
245
sage: Q = TernaryQF([1, 2, 3, 1, 1, 1])
246
sage: QF1 = Q.quadratic_form()
247
sage: QF1
248
Quadratic form in 3 variables over Integer Ring with coefficients:
249
[ 1 1 1 ]
250
[ * 2 1 ]
251
[ * * 3 ]
252
sage: QF2 = QuadraticForm(ZZ, 3, [1, 1, 1, 2, 1, 3])
253
sage: bool(QF1 == QF2)
254
True
255
"""
256
257
258
return QuadraticForm(ZZ, 3, [self._a, self._t, self._s, self._b, self._r, self._c])
259
260
def matrix(self):
261
"""
262
Return the Hessian matrix associated to the ternary quadratic form.
263
That is, if Q is a ternary quadratic form, Q(x,y,z) = a*x^2 + b*y^2 + c*z^2 + r*y*z + s*x*z + t*x*y,
264
then the Hessian matrix associated to Q is
265
::
266
267
[2*a t s]
268
[t 2*b r]
269
[s r 2*c]
270
271
EXAMPLES::
272
273
sage: Q = TernaryQF([1,1,2,0,-1,4])
274
sage: Q
275
Ternary quadratic form with integer coefficients:
276
[1 1 2]
277
[0 -1 4]
278
sage: M = Q.matrix()
279
sage: M
280
[ 2 4 -1]
281
[ 4 2 0]
282
[-1 0 4]
283
sage: v = vector((1, 2, 3))
284
sage: Q(v)
285
28
286
sage: (v*M*v.column())[0]//2
287
28
288
289
"""
290
291
M = matrix(ZZ, 3, [2*self._a, self._t, self._s, self._t, 2*self._b, self._r, self._s, self._r, 2*self._c])
292
return M
293
294
def disc(self):
295
"""
296
Return the discriminant of the ternary quadratic form, this is the determinant of the matrix divided by 2.
297
298
EXAMPLES::
299
300
sage: Q = TernaryQF([1, 1, 2, 0, -1, 4])
301
sage: Q.disc()
302
-25
303
sage: Q.matrix().det()
304
-50
305
306
"""
307
308
return 4*self._a*self._b*self._c + self._r*self._s*self._t - self._a*self._r**2 - self._b*self._s**2 - self._c*self._t**2
309
310
def is_definite(self):
311
"""
312
Determines if the ternary quadratic form is definite.
313
314
EXAMPLES::
315
316
sage: Q = TernaryQF([10, 10, 1, -1, 2, 3])
317
sage: Q.is_definite()
318
True
319
sage: (-Q).is_definite()
320
True
321
sage: Q = TernaryQF([1, 1, 2, -3, 0, -1])
322
sage: Q.is_definite()
323
False
324
325
"""
326
327
d1 = self._a
328
if d1 == 0:
329
return False
330
d2 = 4*self._a*self._b-self._t**2
331
if d2 == 0:
332
return False
333
d3 = self.disc()
334
if d3 == 0:
335
return False
336
if d1 > 0:
337
if d2 > 0:
338
if d3 > 0:
339
return True
340
else:
341
return False
342
else:
343
return False
344
else:
345
if d2 > 0:
346
if d3 < 0:
347
return True
348
else:
349
return False
350
else:
351
return False
352
353
def is_positive_definite(self):
354
"""
355
Determines if the ternary quadratic form is positive definite.
356
357
EXAMPLES::
358
359
sage: Q = TernaryQF([10, 10, 1, -1, 2, 3])
360
sage: Q.is_positive_definite()
361
True
362
sage: (-Q).is_positive_definite()
363
False
364
sage: Q = TernaryQF([1, 1, 0, 0, 0, 0])
365
sage: Q.is_positive_definite()
366
False
367
sage: Q = TernaryQF([1, 1, 1, -1, -2, -3])
368
sage: Q((1,1,1))
369
-3
370
sage: Q.is_positive_definite()
371
False
372
373
"""
374
375
d1 = self._a
376
if d1 == 0:
377
return False
378
d2 = 4*self._a*self._b-self._t**2
379
if d2 == 0:
380
return False
381
d3 = self.disc()
382
if d3 == 0:
383
return False
384
if d1 > 0:
385
if d2 > 0:
386
if d3 > 0:
387
return True
388
else:
389
return False
390
else:
391
return False
392
else:
393
return False
394
395
def is_negative_definite(self):
396
"""
397
Determines if the ternary quadratic form is negatice definite.
398
399
EXAMPLES::
400
401
sage: Q = TernaryQF([-8, -9, -10, 1, 9, -3])
402
sage: Q.is_negative_definite()
403
True
404
sage: Q = TernaryQF([-4, -1, 6, -5, 1, -5])
405
sage: Q((0, 0, 1))
406
6
407
sage: Q.is_negative_definite()
408
False
409
410
"""
411
412
d1 = self._a
413
if d1 == 0:
414
return False
415
d2 = 4*self._a*self._b-self._t**2
416
if d2 == 0:
417
return False
418
d3 = self.disc()
419
if d3 == 0:
420
return False
421
if d1 < 0:
422
if d2 > 0:
423
if d3 < 0:
424
return True
425
else:
426
return False
427
else:
428
return False
429
else:
430
return False
431
432
def __neg__(self):
433
"""
434
Returns the ternary quadratic form with coefficients negatives of self.
435
436
EXAMPLES::
437
438
sage: Q = TernaryQF([1, 1, 2, -2, 0, -1])
439
sage: Q
440
Ternary quadratic form with integer coefficients:
441
[1 1 2]
442
[-2 0 -1]
443
sage: -Q
444
Ternary quadratic form with integer coefficients:
445
[-1 -1 -2]
446
[2 0 1]
447
sage: Q = TernaryQF([0, 0, 0, 0, 0, 0])
448
sage: Q==-Q
449
True
450
451
"""
452
453
return TernaryQF([-a for a in self.coefficients()])
454
455
def is_primitive(self):
456
"""
457
Determines if the ternary quadratic form is primitive, i.e. the greatest common divisor of the coefficients of the form is 1.
458
459
EXAMPLES::
460
461
sage: Q = TernaryQF([1, 2, 3, 4, 5, 6])
462
sage: Q.is_primitive()
463
True
464
sage: Q.content()
465
1
466
sage: Q = TernaryQF([10, 10, 10, 5, 5, 5])
467
sage: Q.content()
468
5
469
sage: Q.is_primitive()
470
False
471
"""
472
473
return self.content() == 1
474
475
def primitive(self):
476
"""
477
Returns the primitive version of the ternary quadratic form.
478
479
EXAMPLES::
480
481
sage: Q = TernaryQF([2, 2, 2, 1, 1, 1])
482
sage: Q.is_primitive()
483
True
484
sage: Q.primitive()
485
Ternary quadratic form with integer coefficients:
486
[2 2 2]
487
[1 1 1]
488
sage: Q.primitive() == Q
489
True
490
sage: Q = TernaryQF([10, 10, 10, 5, 5, 5])
491
sage: Q.primitive()
492
Ternary quadratic form with integer coefficients:
493
[2 2 2]
494
[1 1 1]
495
496
"""
497
498
l = self.coefficients()
499
g = gcd(l)
500
return TernaryQF([a//g for a in l])
501
502
def scale_by_factor(self, k):
503
"""
504
Scale the values of the ternary quadratic form by the number c, if c times the content of the ternary quadratic form is an integer it returns a ternary quadratic form, otherwise returns a quadratic form of dimension 3.
505
506
EXAMPLES::
507
508
sage: Q = TernaryQF([2, 2, 4, 0, -2, 8])
509
sage: Q
510
Ternary quadratic form with integer coefficients:
511
[2 2 4]
512
[0 -2 8]
513
sage: Q.scale_by_factor(5)
514
Ternary quadratic form with integer coefficients:
515
[10 10 20]
516
[0 -10 40]
517
sage: Q.scale_by_factor(1/2)
518
Ternary quadratic form with integer coefficients:
519
[1 1 2]
520
[0 -1 4]
521
sage: Q.scale_by_factor(1/3)
522
Quadratic form in 3 variables over Rational Field with coefficients:
523
[ 2/3 8/3 -2/3 ]
524
[ * 2/3 0 ]
525
[ * * 4/3 ]
526
527
"""
528
529
if k*self.content() in ZZ:
530
531
return TernaryQF([ZZ(k*self._a), ZZ(k*self._b), ZZ(k*self._c), ZZ(k*self._r), ZZ(k*self._s), ZZ(k*self._t)])
532
533
else:
534
#arreglar con un try?
535
R = k.parent()
536
if is_Ring(R):
537
538
return QuadraticForm(R, 3, [k*self._a, k*self._t, k*self._s, k*self._b, k*self._r, k*self._c])
539
540
else:
541
542
raise TypeError, "Oops! " + k.__repr__() + " doesn't belongs to a Ring"
543
544
def reciprocal(self):
545
"""
546
Gives the reciprocal quadratic form associated to the given form. This is defined as the multiple of the primitive adjoint with the same content as the given form.
547
548
EXAMPLES::
549
550
sage: Q = TernaryQF([2, 2, 14, 0, 0, 0])
551
sage: Q.reciprocal()
552
Ternary quadratic form with integer coefficients:
553
[14 14 2]
554
[0 0 0]
555
sage: Q.content()
556
2
557
sage: Q.reciprocal().content()
558
2
559
sage: Q.adjoint().content()
560
16
561
562
563
"""
564
565
return self.adjoint().primitive().scale_by_factor( self.content() )
566
567
def reciprocal_reduced(self):
568
"""
569
Returns the reduced form of the reciprocal form of the given ternary quadratic form.
570
571
EXAMPLES::
572
573
sage: Q = TernaryQF([1, 1, 3, 0, -1, 0])
574
sage: Qrr = Q.reciprocal_reduced()
575
sage: Qrr
576
Ternary quadratic form with integer coefficients:
577
[4 11 12]
578
[0 -4 0]
579
sage: Q.is_eisenstein_reduced()
580
True
581
sage: Qr = Q.reciprocal()
582
sage: Qr.reduced_form_eisenstein(matrix = False) == Qrr
583
True
584
585
"""
586
587
return self.reciprocal().reduced_form_eisenstein(matrix = False)
588
589
def divisor(self):
590
"""
591
Returns the content of the adjoint form associated to the given form.
592
593
EXAMPLES::
594
595
sage: Q = TernaryQF([1, 1, 17, 0, 0, 0])
596
sage: Q.divisor()
597
4
598
"""
599
600
A11 = 4*self._b*self._c - self._r**2
601
A22 = 4*self._a*self._c - self._s**2
602
A33 = 4*self._a*self._b - self._t**2
603
A23 = self._s*self._t - 2*self._a*self._r
604
A13 = self._r*self._t - 2*self._b*self._s
605
A12 = self._r*self._s - 2*self._c*self._t
606
m = gcd([A11, A22, A33, 2*A12, 2*A13, 2*A23])
607
return m
608
609
def __eq__(self,right):
610
"""
611
Determines if two ternary quadratic forms are equal.
612
613
EXAMPLES::
614
615
sage: Q = TernaryQF([1, 2, 3, 1, 2, 3])
616
sage: Q == Q
617
True
618
sage: Q1 = TernaryQF([1, 2, 3, 1, 2, 2])
619
sage: Q == Q1
620
False
621
622
"""
623
624
if not isinstance(right, TernaryQF):
625
return False
626
return self.coefficients() == right.coefficients()
627
628
def adjoint(self):
629
"""
630
Returns the adjoint form associated to the given ternary quadratic form.
631
That is, the Hessian matrix of the adjoint form is twice the adjoint matrix of the Hessian matrix of the given form.
632
633
EXAMPLES::
634
635
sage: Q = TernaryQF([1, 1, 17, 0, 0, 1])
636
sage: Q.adjoint()
637
Ternary quadratic form with integer coefficients:
638
[68 68 3]
639
[0 0 -68]
640
sage: Q.adjoint().matrix() == 2*Q.matrix().adjoint()
641
True
642
643
"""
644
645
A11 = 4*self._b*self._c - self._r**2
646
A22 = 4*self._a*self._c - self._s**2
647
A33 = 4*self._a*self._b - self._t**2
648
A23 = self._s*self._t - 2*self._a*self._r
649
A13 = self._r*self._t - 2*self._b*self._s
650
A12 = self._r*self._s - 2*self._c*self._t
651
return TernaryQF([A11, A22, A33, 2*A23, 2*A13, 2*A12])
652
653
def content(self):
654
"""
655
Returns the greatest common divisor of the coefficients of the given ternary quadratic form.
656
657
EXAMPLES::
658
659
sage: Q = TernaryQF([1, 1, 2, 0, 0, 0])
660
sage: Q.content()
661
1
662
sage: Q = TernaryQF([2, 4, 6, 0, 0, 0])
663
sage: Q.content()
664
2
665
sage: Q.scale_by_factor(100).content()
666
200
667
668
"""
669
return gcd(self.coefficients())
670
671
def omega(self):
672
"""
673
Returns the content of the adjoint of the primitive associated
674
ternary quadratic form.
675
676
EXAMPLES::
677
678
sage: Q = TernaryQF([4, 11, 12, 0, -4, 0])
679
sage: Q.omega()
680
176
681
sage: Q.primitive().adjoint().content()
682
176
683
684
"""
685
686
return self.primitive().adjoint().content()
687
688
def delta(self):
689
"""
690
Returns the omega of the adjoint of the given ternary quadratic form,
691
which is the same as the omega of the reciprocal form.
692
693
EXAMPLES::
694
695
sage: Q = TernaryQF([1, 2, 2, -1, 0, -1])
696
sage: Q.delta()
697
208
698
sage: Q.adjoint().omega()
699
208
700
sage: Q = TernaryQF([1, -1, 1, 0, 0, 0])
701
sage: Q.delta()
702
4
703
sage: Q.omega()
704
4
705
706
"""
707
708
return self.adjoint().omega()
709
710
def level(self):
711
"""
712
Returns the level of the ternary quadratic form, which is 4 times the discriminant divided by the divisor.
713
714
EXAMPLES::
715
716
sage: Q = TernaryQF([1, 2, 2, -1, 0, -1])
717
sage: Q.level()
718
52
719
sage: 4*Q.disc()/Q.divisor()
720
52
721
722
"""
723
724
return 4*self.disc()//self.divisor()
725
726
def is_eisenstein_reduced(self):
727
"""
728
Determines if the ternary quadratic form is Eisenstein reduced.
729
That is, if we have a ternary quadratic form:
730
::
731
732
[a b c]
733
[r s t]
734
735
then
736
737
::
738
739
1- a<=b<=c;
740
2- r, s, and t are all positive or all nonpositive;
741
3- a>=|t|; a>=|s|; b>=|r|;
742
4- a+b+r+s+t>=0;
743
5- a=t implies s<=2*r; a=s implies t<=2*r; b=r implies t<=2*s;
744
6- a=-t implies s=0; a=-s implies t=0; b=-r implies t=0;
745
7- a+b+r+s+t=0 implies 2*a+2*s+t<=0;
746
8- a=b implies |r|<=|s|; b=c implies |s|<=|t|.
747
748
EXAMPLES::
749
750
sage: Q = TernaryQF([1, 1, 1, 0, 0, 0])
751
sage: Q.is_eisenstein_reduced()
752
True
753
sage: Q = TernaryQF([34, 14, 44, 12, 25, -22])
754
sage: Q.is_eisenstein_reduced()
755
False
756
757
"""
758
759
760
[a,b,c,r,s,t]=[self._a,self._b,self._c,self._r,self._s,self._t]
761
762
# cond 2
763
if not (r > 0 and t > 0 and s > 0):
764
if not (r <= 0 and s <= 0 and t <= 0):
765
return False
766
767
# cond 1 & 4
768
if not (a <= b <= c and 0 <= a+b+r+s+t):
769
return False
770
771
# cond 3
772
if not (a >= abs(s) and a >= abs(t) and b >= abs(r)):
773
return False
774
775
# cond 8
776
if a == b and abs(r) > abs(s):
777
return False
778
if b == c and abs(s) > abs(t):
779
return False
780
if a+b+r+s+t == 0 and 2*a+2*s+t > 0:
781
return False
782
783
# cond 6
784
# r, s, t <= 0
785
if r<=0:
786
if a == -t and s != 0:
787
return False
788
if a == -s and t != 0:
789
return False
790
if b == -r and t != 0:
791
return False
792
793
# cond 7
794
# r, s, t > 0
795
if a == t and s > 2*r:
796
return False
797
if a == s and t > 2*r:
798
return False
799
if b == r and t > 2*s:
800
return False
801
802
return True
803
804
def reduced_form_eisenstein(self, matrix=True):
805
"""
806
Returns the eisenstein reduced form equivalent to the given positive ternary quadratic form,
807
which is unique.
808
809
EXAMPLES::
810
811
sage: Q = TernaryQF([293, 315, 756, 908, 929, 522])
812
sage: Qr, m = Q.reduced_form_eisenstein()
813
sage: Qr
814
Ternary quadratic form with integer coefficients:
815
[1 2 2]
816
[-1 0 -1]
817
sage: Qr.is_eisenstein_reduced()
818
True
819
sage: m
820
[ -54 137 -38]
821
[ -23 58 -16]
822
[ 47 -119 33]
823
sage: m.det()
824
1
825
sage: Q(m) == Qr
826
True
827
sage: Q = TernaryQF([12,36,3,14,-7,-19])
828
sage: Q.reduced_form_eisenstein(matrix = False)
829
Ternary quadratic form with integer coefficients:
830
[3 8 20]
831
[3 2 1]
832
833
"""
834
835
if matrix:
836
[v,M] = _reduced_ternary_form_eisenstein_with_matrix(self._a,self._b,self._c,self._r,self._s,self._t)
837
return TernaryQF(v), M
838
else:
839
v = _reduced_ternary_form_eisenstein_without_matrix(self._a,self._b,self._c,self._r,self._s,self._t)
840
return TernaryQF(v)
841
842
def pseudorandom_primitive_zero_mod_p(self,p):
843
"""
844
Returns a tuple of the form v = (a, b, 1) such that is a zero of the given ternary quadratic
845
positive definite form modulo an odd prime p, where p doesn't divides the discriminant of the form.
846
847
EXAMPLES::
848
849
sage: Q = TernaryQF([1, 1, 11, 0, -1, 0])
850
sage: Q.disc()
851
43
852
sage: Q.pseudorandom_primitive_zero_mod_p(3) ## RANDOM
853
(1, 2, 1)
854
sage: Q((1, 2, 1))
855
15
856
sage: v = Q.pseudorandom_primitive_zero_mod_p(1009)
857
sage: Q(v) % 1009
858
0
859
sage: v[2]
860
1
861
"""
862
863
[a,b,c,r,s,t] = self.coefficients()
864
while True:
865
866
r1=randint(0,p-1)
867
r2=randint(0,p-1)
868
alpha=(b*r1**2+t*r1+a)%p
869
if alpha != 0:
870
871
beta=(2*b*r1*r2+t*r2+r*r1+s)%p
872
gamma=(b*r2**2+r*r2+c)%p
873
disc=beta**2-4*alpha*gamma
874
if mod(disc,p).is_square():
875
876
z=(-beta+mod(disc,p).sqrt().lift())*(2*alpha).inverse_mod(p)
877
#return vector((z,r1*z+r2,1))%p
878
return z%p, (r1*z+r2)%p, 1
879
880
881
def find_zeros_mod_p(self, p):
882
"""
883
Find the zeros of the given ternary quadratic positive definite form modulo a prime p, where p doesn't divides the discriminant of the form.
884
885
EXAMPLES::
886
887
sage: Q = TernaryQF([4, 7, 8, -4, -1, -3])
888
sage: Q.is_positive_definite()
889
True
890
sage: Q.disc().factor()
891
3 * 13 * 19
892
sage: Q.find_zeros_mod_p(2)
893
[(1, 0, 0), (1, 1, 0), (0, 0, 1)]
894
sage: zeros_17 = Q.find_zeros_mod_p(17)
895
sage: len(zeros_17)
896
18
897
sage: [Q(v)%17 for v in zeros_17]
898
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
899
900
901
"""
902
903
if p==2:
904
905
return _find_zeros_mod_p_2(self._a, self._b, self._c, self._r, self._s, self._t)
906
907
else:
908
909
v = self.pseudorandom_primitive_zero_mod_p(p)
910
[a, b, c, r, s, t] = self.coefficients()
911
return _find_zeros_mod_p_odd(a, b, c, r, s, t, p, v)
912
913
914
def find_p_neighbor_from_vec(self, p, v, mat = False):
915
"""
916
Finds the reduced equivalent of the p-neighbor of this ternary quadratic form associated to a given
917
vector v satisfying:
918
919
1. Q(v) = 0 mod p
920
921
2. v is a non-singular point of the conic Q(v) = 0 mod p.
922
923
Reference: Gonzalo Tornaria's Thesis, Thrm 3.5, p34.
924
925
EXAMPLES::
926
927
sage: Q = TernaryQF([1, 3, 3, -2, 0, -1])
928
sage: Q
929
Ternary quadratic form with integer coefficients:
930
[1 3 3]
931
[-2 0 -1]
932
sage: Q.disc()
933
29
934
sage: v = (9, 7, 1)
935
sage: v in Q.find_zeros_mod_p(11)
936
True
937
sage: Q11, M = Q.find_p_neighbor_from_vec(11, v, mat = True)
938
sage: Q11
939
Ternary quadratic form with integer coefficients:
940
[1 2 4]
941
[-1 -1 0]
942
sage: M
943
[ -1 -5/11 7/11]
944
[ 0 -10/11 3/11]
945
[ 0 -3/11 13/11]
946
sage: Q(M) == Q11
947
True
948
949
"""
950
951
if mat:
952
q, M = _find_p_neighbor_from_vec(self._a, self._b, self._c, self._r, self._s, self._t, p, v, mat)
953
M = matrix(3,M)
954
return TernaryQF(q), M*M.det()
955
else:
956
return TernaryQF(_find_p_neighbor_from_vec(self._a, self._b, self._c, self._r, self._s, self._t, p, v, mat))
957
958
def find_p_neighbors(self, p, mat = False):
959
"""
960
Find a list with all the reduced equivalent of the p-neighbors of this ternary quadratic form, given by the zeros mod p of the form.
961
See find_p_neighbor_from_vec for more information.
962
963
EXAMPLES::
964
965
sage: Q0 = TernaryQF([1, 3, 3, -2, 0, -1])
966
sage: Q0
967
Ternary quadratic form with integer coefficients:
968
[1 3 3]
969
[-2 0 -1]
970
sage: neig = Q0.find_p_neighbors(5)
971
sage: len(neig)
972
6
973
sage: Q1 = TernaryQF([1, 1, 10, 1, 1, 1])
974
sage: Q2 = TernaryQF([1, 2, 4, -1, -1, 0])
975
sage: neig.count(Q0)
976
2
977
sage: neig.count(Q1)
978
1
979
sage: neig.count(Q2)
980
3
981
982
"""
983
984
z = self.find_zeros_mod_p(p)
985
return [self.find_p_neighbor_from_vec(p, v, mat) for v in z]
986
987
988
def basic_lemma(self, p):
989
"""
990
Finds a number represented by self and coprime to the prime p.
991
992
EXAMPLES::
993
994
sage: Q = TernaryQF([3, 3, 3, -2, 0, -1])
995
sage: Q.basic_lemma(3)
996
4
997
"""
998
999
return _basic_lemma(self._a, self._b, self._c, self._r, self._s, self._t, p)
1000
1001
def xi(self, p):
1002
"""
1003
Return the value of the genus characters Xi_p... which may be
1004
missing one character. We allow -1 as a prime.
1005
1006
Reference: Dickson's "Studies in the Theory of Numbers"
1007
1008
EXAMPLES::
1009
1010
sage: Q1 = TernaryQF([26, 42, 53, -36, -17, -3])
1011
sage: Q2 = Q1.find_p_neighbors(2)[1]
1012
sage: Q1.omega()
1013
3
1014
sage: Q1.xi(3), Q2.xi(3)
1015
(-1, -1)
1016
1017
"""
1018
1019
if p == 4:
1020
p = -1
1021
if p == 8:
1022
p = 2
1023
1024
if self.omega() % p != 0:
1025
raise ValueError, "not a valid character"
1026
1027
if p == -1 and self.omega() % 2**4 != 0:
1028
raise ValueError, "not a valid character"
1029
1030
if p == 2 and self.omega() % 2**5 != 0:
1031
raise ValueError, "not a valid character"
1032
1033
if (p == -1) or (p == 2):
1034
return kronecker_symbol(p, self.basic_lemma(2))
1035
1036
return kronecker_symbol(self.basic_lemma(p), p)
1037
1038
1039
1040
def xi_rec(self, p):
1041
"""
1042
Returns Xi(p) for the reciprocal form.
1043
1044
EXAMPLES::
1045
1046
sage: Q1 = TernaryQF([1, 1, 7, 0, 0, 0])
1047
sage: Q2 = Q1.find_p_neighbors(3)[0]
1048
sage: Q1.delta()
1049
28
1050
sage: Q1.xi_rec(7), Q2.xi_rec(7)
1051
(1, 1)
1052
1053
1054
"""
1055
1056
return self.reciprocal().xi(p)
1057
1058
1059
def symmetry(self, v):
1060
"""
1061
Returns A the automorphism of the ternary quadratic form such that:
1062
::
1063
- A*v = -v.
1064
- A*u = 0, if u is orthogonal to v.
1065
where v is a given vector.
1066
1067
EXAMPLES::
1068
1069
sage: Q = TernaryQF([4, 5, 8, 5, 2, 2])
1070
sage: v = vector((1,1,1))
1071
sage: M = Q.symmetry(v)
1072
sage: M
1073
[ 7/13 -17/26 -23/26]
1074
[ -6/13 9/26 -23/26]
1075
[ -6/13 -17/26 3/26]
1076
sage: M.det()
1077
-1
1078
sage: M*v
1079
(-1, -1, -1)
1080
sage: v1 = vector((23, 0, -12))
1081
sage: v2 = vector((0, 23, -17))
1082
sage: v1*Q.matrix()*v
1083
0
1084
sage: v2*Q.matrix()*v
1085
0
1086
sage: M*v1 == v1
1087
True
1088
sage: M*v2 == v2
1089
True
1090
1091
1092
"""
1093
1094
return identity_matrix(3) - v.column()*matrix(v)*self.matrix()/self(v)
1095
1096
1097
def automorphism_symmetries(self, A):
1098
"""
1099
Given the automorphism A, returns two vectors v1, v2 if A is not the identity. Such that the product of the symmetries of the ternary quadratic form given by the two vectors is A.
1100
1101
EXAMPLES::
1102
1103
sage: Q = TernaryQF([9, 12, 30, -26, -28, 20])
1104
sage: A = matrix(ZZ, 3, [9, 10, -10, -6, -7, 6, 2, 2, -3])
1105
sage: Q(A) == Q
1106
True
1107
sage: v1, v2 = Q.automorphism_symmetries(A)
1108
sage: v1, v2
1109
((8, -6, 2), (1, -5/4, -1/4))
1110
sage: A1 = Q.symmetry(v1)
1111
sage: A1
1112
[ 9 9 -13]
1113
[ -6 -23/4 39/4]
1114
[ 2 9/4 -9/4]
1115
sage: A2 = Q.symmetry(v2)
1116
sage: A2
1117
[ 1 1 3]
1118
[ 0 -1/4 -15/4]
1119
[ 0 -1/4 1/4]
1120
sage: A1*A2 == A
1121
True
1122
sage: Q.automorphism_symmetries(identity_matrix(ZZ,3))
1123
[]
1124
1125
"""
1126
1127
if A == identity_matrix(3):
1128
return []
1129
else:
1130
bs = (A - 1).columns()
1131
for b1 in bs:
1132
if b1 != 0:
1133
break
1134
A1 = self.symmetry(b1)*A
1135
bs = (A1 - 1).columns()
1136
for b2 in bs:
1137
if b2 != 0:
1138
break
1139
return [b1, b2]
1140
1141
def automorphism_spin_norm(self,A):
1142
"""
1143
Return the spin norm of the automorphism A.
1144
1145
EXAMPLES::
1146
1147
sage: Q = TernaryQF([9, 12, 30, -26, -28, 20])
1148
sage: A = matrix(ZZ, 3, [9, 10, -10, -6, -7, 6, 2, 2, -3])
1149
sage: A.det()
1150
1
1151
sage: Q(A) == Q
1152
True
1153
sage: Q.automorphism_spin_norm(A)
1154
7
1155
1156
"""
1157
1158
if A == identity_matrix(ZZ,3):
1159
return 1
1160
bs = self.automorphism_symmetries(A)
1161
s = self(bs[0]) * self(bs[1])
1162
return s.squarefree_part()
1163
1164
1165
return [(1, 0, 0, 0, 1, 0, 0, 0, 1)]
1166
1167
def _border(self,n):
1168
"""
1169
Auxiliar function to find the automorphisms of a positive definite ternary quadratic form.
1170
It return a boolean whether the n-condition is true. If Q = TernaryQF([a,b,c,r,s,t]), the conditions are:
1171
::
1172
1- a = t, s = 2r.
1173
2- a = s, t = 2r.
1174
3- b = r, t = 2s.
1175
4- a = -t.
1176
5- a = -s.
1177
6- b = -r.
1178
7- a + b + r + s + t = 0, 2a + 2s + t = 0.
1179
8- a = b, r = s.
1180
9- b = c, s = t.
1181
10- r = s, r = 0.
1182
11- r = t, r = 0.
1183
12- s = t, s = 0.
1184
13- r = s, s = t, t = a.
1185
14- a = s, a = t.
1186
15- a = b, a + b + r + s + t = 0.
1187
16- a = b, b = c, a + b + r + s + t = 0.
1188
1189
EXAMPLES::
1190
1191
sage: Q01 = TernaryQF([5, 5, 9, 2, 4, 5])
1192
sage: Q01._border(1)
1193
True
1194
sage: Q02 = TernaryQF([6, 7, 8, 2, 6, 4])
1195
sage: Q02._border(2)
1196
True
1197
sage: Q03 = TernaryQF([6, 9, 9, 9, 3, 6])
1198
sage: Q03._border(3)
1199
True
1200
sage: Q04 = TernaryQF([1, 2, 3, -1, 0, -1])
1201
sage: Q04._border(4)
1202
True
1203
sage: Q05 = TernaryQF([2, 3, 5, -1, -2, 0])
1204
sage: Q05._border(5)
1205
True
1206
sage: Q06 = TernaryQF([1, 5, 7, -5, 0, 0])
1207
sage: Q06._border(6)
1208
True
1209
sage: Q07 = TernaryQF([1, 1, 7, -1, -1, 0])
1210
sage: Q07._border(7)
1211
True
1212
sage: Q08 = TernaryQF([2, 2, 5, -1, -1, -1])
1213
sage: Q08._border(8)
1214
True
1215
sage: Q09 = TernaryQF([3, 8, 8, 6, 2, 2])
1216
sage: Q09._border(9)
1217
True
1218
sage: Q10 = TernaryQF([1, 3, 4, 0, 0, 0])
1219
sage: Q10._border(10)
1220
True
1221
sage: Q11 = TernaryQF([3, 5, 8, 0, -1, 0])
1222
sage: Q11._border(11)
1223
True
1224
sage: Q12 = TernaryQF([2, 6, 7, -5, 0, 0])
1225
sage: Q12._border(12)
1226
True
1227
sage: Q13 = TernaryQF([1, 1, 2, 1, 1, 1])
1228
sage: Q13._border(13)
1229
True
1230
sage: Q14 = TernaryQF([1, 3, 4, 3, 1, 1])
1231
sage: Q14._border(14)
1232
True
1233
sage: Q15 = TernaryQF([3, 3, 6, -3, -3, 0])
1234
sage: Q15._border(15)
1235
True
1236
sage: Q16 = TernaryQF([4, 4, 4, -2, -3, -3])
1237
sage: Q16._border(16)
1238
True
1239
1240
1241
"""
1242
1243
a, b, c, r, s, t = self.coefficients()
1244
if n == 1:
1245
return (a == t) and (s == 2*r)
1246
elif n == 2:
1247
return (a == s) and (t == 2*r)
1248
elif n == 3:
1249
return (b == r) and (t == 2*s)
1250
elif n == 4:
1251
return (a == -t)
1252
elif n == 5:
1253
return (a == -s)
1254
elif n == 6:
1255
return (b == -r)
1256
elif n == 7:
1257
return (a + b + r + s + t == 0) and (2*a + 2*s + t == 0)
1258
elif n == 8:
1259
return (a == b) and (r == s)
1260
elif n == 9:
1261
return (b == c) and (s == t)
1262
elif n == 10:
1263
return (r == s) and (r == 0)
1264
elif n == 11:
1265
return (r == t) and (r == 0)
1266
elif n == 12:
1267
return (s == t) and (s == 0)
1268
elif n == 13:
1269
return (r == s) and (s == t) and (t == a)
1270
elif n == 14:
1271
return (a == s) and (a == t)
1272
elif n == 15:
1273
return (a == b) and (a + b + r + s + t == 0)
1274
elif n == 16:
1275
return (a == b) and (b == c) and (a + b + r + s + t == 0)
1276
1277
def _borders(self):
1278
"""
1279
Return the borders that the ternary quadratic form meet.
1280
1281
See: TernaryQF._border
1282
1283
EXAMPLES::
1284
1285
sage: Q01 = TernaryQF([5, 5, 9, 2, 4, 5])
1286
sage: Q01._borders()
1287
(1,)
1288
sage: Q02 = TernaryQF([6, 7, 8, 2, 6, 4])
1289
sage: Q02._borders()
1290
(2,)
1291
sage: Q03 = TernaryQF([6, 9, 9, 9, 3, 6])
1292
sage: Q03._borders()
1293
(3,)
1294
sage: Q04 = TernaryQF([1, 2, 3, -1, 0, -1])
1295
sage: Q04._borders()
1296
(4,)
1297
sage: Q05 = TernaryQF([2, 3, 5, -1, -2, 0])
1298
sage: Q05._borders()
1299
(5,)
1300
sage: Q06 = TernaryQF([1, 5, 7, -5, 0, 0])
1301
sage: Q06._borders()
1302
(6, 12)
1303
sage: Q07 = TernaryQF([1, 1, 7, -1, -1, 0])
1304
sage: Q07._borders()
1305
(5, 6, 7, 8, 15)
1306
sage: Q08 = TernaryQF([2, 2, 5, -1, -1, -1])
1307
sage: Q08._borders()
1308
(8,)
1309
sage: Q09 = TernaryQF([3, 8, 8, 6, 2, 2])
1310
sage: Q09._borders()
1311
(9,)
1312
sage: Q10 = TernaryQF([1, 3, 4, 0, 0, 0])
1313
sage: Q10._borders()
1314
(10, 11, 12)
1315
sage: Q11 = TernaryQF([3, 5, 8, 0, -1, 0])
1316
sage: Q11._borders()
1317
(11,)
1318
sage: Q12 = TernaryQF([2, 6, 7, -5, 0, 0])
1319
sage: Q12._borders()
1320
(12,)
1321
sage: Q13 = TernaryQF([1, 1, 2, 1, 1, 1])
1322
sage: Q13._borders()
1323
(8, 13, 14)
1324
sage: Q14 = TernaryQF([1, 3, 4, 3, 1, 1])
1325
sage: Q14._borders()
1326
(14,)
1327
sage: Q15 = TernaryQF([3, 3, 6, -3, -3, 0])
1328
sage: Q15._borders()
1329
(5, 6, 7, 8, 15)
1330
sage: Q16 = TernaryQF([4, 4, 4, -2, -3, -3])
1331
sage: Q16._borders()
1332
(9, 15, 16)
1333
1334
"""
1335
1336
return tuple(n for n in range(1,17) if self._border(n))
1337
1338
def _automorphisms_reduced_fast(self):
1339
"""
1340
Return the coefficients of the matrices of the automorphisms of the reduced ternary quadratic form.
1341
1342
EXAMPLES::
1343
1344
sage: Q = TernaryQF([1, 1, 7, 0, 0, 0])
1345
sage: Q.is_eisenstein_reduced()
1346
True
1347
sage: auts = Q._automorphisms_reduced_fast()
1348
sage: len(auts)
1349
8
1350
sage: A = matrix(3, auts[randint(0,7)])
1351
sage: Q(A) == Q
1352
True
1353
sage: Q = TernaryQF([3, 4, 5, 3, 3, 2])
1354
sage: Q._automorphisms_reduced_fast()
1355
[(1, 0, 0, 0, 1, 0, 0, 0, 1)]
1356
1357
1358
"""
1359
1360
if self._border(1):
1361
if self._border(2):
1362
if self._border(14):
1363
if self._border(9):
1364
# borders 1, 2, 9, 14
1365
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1366
(-1, -1, -1, 0, 0, 1, 0, 1, 0),
1367
(-1, -1, 0, 0, 1, 0, 0, 0, -1),
1368
(-1, 0, -1, 0, -1, 0, 0, 0, 1),
1369
(-1, 0, 0, 0, 0, -1, 0, -1, 0),
1370
(1, 0, 1, 0, 0, -1, 0, 1, 0),
1371
(1, 1, 0, 0, 0, 1, 0, -1, 0),
1372
(1, 1, 1, 0, -1, 0, 0, 0, -1)]
1373
else:
1374
# borders 1, 2, 14
1375
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1376
(-1, -1, 0, 0, 1, 0, 0, 0, -1),
1377
(-1, 0, -1, 0, -1, 0, 0, 0, 1),
1378
(1, 1, 1, 0, -1, 0, 0, 0, -1)]
1379
else:
1380
# borders 1
1381
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1382
(-1, -1, 0, 0, 1, 0, 0, 0, -1)]
1383
1384
if self._border(2):
1385
# borders 2
1386
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1387
(-1, 0, -1, 0, -1, 0, 0, 0, 1)]
1388
1389
if self._border(3):
1390
# borders 3
1391
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1392
(-1, 0, 0, 0, -1, -1, 0, 0, 1)]
1393
1394
if self._border(4):
1395
if self._border(10):
1396
if self._border(8):
1397
# borders 4, 8, 10
1398
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1399
(-1, 0, 0, -1, 1, 0, 0, 0, -1),
1400
(-1, 0, 0, 0, -1, 0, 0, 0, 1),
1401
(-1, 1, 0, -1, 0, 0, 0, 0, 1),
1402
(-1, 1, 0, 0, 1, 0, 0, 0, -1),
1403
(0, -1, 0, -1, 0, 0, 0, 0, -1),
1404
(0, -1, 0, 1, -1, 0, 0, 0, 1),
1405
(0, 1, 0, -1, 1, 0, 0, 0, 1),
1406
(0, 1, 0, 1, 0, 0, 0, 0, -1),
1407
(1, -1, 0, 0, -1, 0, 0, 0, -1),
1408
(1, -1, 0, 1, 0, 0, 0, 0, 1),
1409
(1, 0, 0, 1, -1, 0, 0, 0, -1)]
1410
else:
1411
# borders 4, 10
1412
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1413
(-1, 0, 0, 0, -1, 0, 0, 0, 1),
1414
(-1, 1, 0, 0, 1, 0, 0, 0, -1),
1415
(1, -1, 0, 0, -1, 0, 0, 0, -1)]
1416
else:
1417
# borders 4
1418
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1419
(1, -1, 0, 0, -1, 0, 0, 0, -1)]
1420
1421
if self._border(5):
1422
if self._border(6):
1423
if self._border(7):
1424
if self._border(8):
1425
if self._border(15):
1426
# borders 5, 6, 7, 8, 15
1427
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1428
(-1, 0, 0, 0, 1, -1, 0, 0, -1),
1429
(-1, 0, 1, 0, -1, 1, 0, 0, 1),
1430
(0, -1, 0, -1, 0, 0, 0, 0, -1),
1431
(0, -1, 1, 1, 0, 0, 0, 0, 1),
1432
(0, 1, -1, 1, 0, -1, 0, 0, -1),
1433
(0, 1, 0, -1, 0, 1, 0, 0, 1),
1434
(1, 0, -1, 0, -1, 0, 0, 0, -1)]
1435
else:
1436
# borders 5, 6, 7
1437
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1438
(-1, 0, 0, 0, 1, -1, 0, 0, -1),
1439
(-1, 0, 1, 0, -1, 1, 0, 0, 1),
1440
(1, 0, -1, 0, -1, 0, 0, 0, -1)]
1441
elif self._border(11):
1442
# borders 5, 11
1443
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1444
(-1, 0, 0, 0, 1, 0, 0, 0, -1),
1445
(-1, 0, 1, 0, -1, 0, 0, 0, 1),
1446
(1, 0, -1, 0, -1, 0, 0, 0, -1)]
1447
else:
1448
# borders 5
1449
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1450
(1, 0, -1, 0, -1, 0, 0, 0, -1)]
1451
1452
if self._border(6):
1453
if self._border(12):
1454
if self._border(9):
1455
# borders 6, 9, 12
1456
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1457
(-1, 0, 0, 0, -1, 0, 0, -1, 1),
1458
(-1, 0, 0, 0, -1, 1, 0, 0, 1),
1459
(-1, 0, 0, 0, 0, -1, 0, -1, 0),
1460
(-1, 0, 0, 0, 0, 1, 0, 1, 0),
1461
(-1, 0, 0, 0, 1, -1, 0, 0, -1),
1462
(-1, 0, 0, 0, 1, 0, 0, 1, -1),
1463
(1, 0, 0, 0, -1, 0, 0, 0, -1),
1464
(1, 0, 0, 0, -1, 1, 0, -1, 0),
1465
(1, 0, 0, 0, 0, -1, 0, 1, -1),
1466
(1, 0, 0, 0, 0, 1, 0, -1, 1),
1467
(1, 0, 0, 0, 1, -1, 0, 1, 0)]
1468
else:
1469
# borders 6, 12
1470
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1471
(-1, 0, 0, 0, -1, 1, 0, 0, 1),
1472
(-1, 0, 0, 0, 1, -1, 0, 0, -1),
1473
(1, 0, 0, 0, -1, 0, 0, 0, -1)]
1474
else:
1475
# borders 6
1476
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1477
(-1, 0, 0, 0, 1, -1, 0, 0, -1)]
1478
1479
if self._border(7):
1480
if self._border(8) and self._border(15):
1481
if self._border(16):
1482
if self._border(9):
1483
# borders 7, 8, 9, 15, 16
1484
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1485
(-1, 0, 0, -1, 0, 1, -1, 1, 0),
1486
(-1, 0, 0, 0, 0, -1, 0, -1, 0),
1487
(-1, 0, 1, -1, 1, 0, -1, 0, 0),
1488
(-1, 0, 1, 0, -1, 1, 0, 0, 1),
1489
(-1, 1, 0, -1, 0, 0, -1, 0, 1),
1490
(-1, 1, 0, 0, 1, 0, 0, 1, -1),
1491
(0, -1, 0, -1, 0, 0, 0, 0, -1),
1492
(0, -1, 0, 1, -1, 0, 0, -1, 1),
1493
(0, -1, 1, 0, -1, 0, 1, -1, 0),
1494
(0, -1, 1, 0, 0, 1, -1, 0, 1),
1495
(0, 0, -1, 0, -1, 0, -1, 0, 0),
1496
(0, 0, -1, 0, 1, -1, 1, 0, -1),
1497
(0, 0, 1, -1, 0, 1, 0, -1, 1),
1498
(0, 0, 1, 1, 0, 0, 0, 1, 0),
1499
(0, 1, -1, -1, 1, 0, 0, 1, 0),
1500
(0, 1, -1, 1, 0, -1, 0, 0, -1),
1501
(0, 1, 0, 0, 0, 1, 1, 0, 0),
1502
(0, 1, 0, 0, 1, -1, -1, 1, 0),
1503
(1, -1, 0, 0, -1, 1, 0, -1, 0),
1504
(1, -1, 0, 1, 0, -1, 1, 0, 0),
1505
(1, 0, -1, 0, 0, -1, 0, 1, -1),
1506
(1, 0, -1, 1, 0, 0, 1, -1, 0),
1507
(1, 0, 0, 1, -1, 0, 1, 0, -1)]
1508
else:
1509
# borders 7, 8, 15, 16
1510
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1511
(-1, 0, 0, -1, 0, 1, -1, 1, 0),
1512
(-1, 0, 1, 0, -1, 1, 0, 0, 1),
1513
(0, -1, 0, -1, 0, 0, 0, 0, -1),
1514
(0, -1, 1, 0, -1, 0, 1, -1, 0),
1515
(0, 1, -1, 1, 0, -1, 0, 0, -1),
1516
(0, 1, 0, 0, 1, -1, -1, 1, 0),
1517
(1, 0, -1, 1, 0, 0, 1, -1, 0)]
1518
else:
1519
# borders 7, 8, 15
1520
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1521
(-1, 0, 1, 0, -1, 1, 0, 0, 1),
1522
(0, -1, 0, -1, 0, 0, 0, 0, -1),
1523
(0, 1, -1, 1, 0, -1, 0, 0, -1)]
1524
elif self._border(9):
1525
# borders 7, 9
1526
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1527
(-1, 0, 0, 0, 0, -1, 0, -1, 0),
1528
(-1, 0, 1, 0, -1, 1, 0, 0, 1),
1529
(-1, 1, 0, 0, 1, 0, 0, 1, -1),
1530
(1, -1, 0, 0, -1, 1, 0, -1, 0),
1531
(1, 0, -1, 0, 0, -1, 0, 1, -1)]
1532
else:
1533
# borders 7
1534
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1535
(-1, 0, 1, 0, -1, 1, 0, 0, 1)]
1536
1537
1538
if self._border(8):
1539
if self._border(9):
1540
if self._border(10) and self._border(11) and self._border(12):
1541
# borders 8, 9, 10, 11, 12
1542
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1543
(-1, 0, 0, 0, -1, 0, 0, 0, 1),
1544
(-1, 0, 0, 0, 0, -1, 0, -1, 0),
1545
(-1, 0, 0, 0, 0, 1, 0, 1, 0),
1546
(-1, 0, 0, 0, 1, 0, 0, 0, -1),
1547
(0, -1, 0, -1, 0, 0, 0, 0, -1),
1548
(0, -1, 0, 0, 0, -1, 1, 0, 0),
1549
(0, -1, 0, 0, 0, 1, -1, 0, 0),
1550
(0, -1, 0, 1, 0, 0, 0, 0, 1),
1551
(0, 0, -1, -1, 0, 0, 0, 1, 0),
1552
(0, 0, -1, 0, -1, 0, -1, 0, 0),
1553
(0, 0, -1, 0, 1, 0, 1, 0, 0),
1554
(0, 0, -1, 1, 0, 0, 0, -1, 0),
1555
(0, 0, 1, -1, 0, 0, 0, -1, 0),
1556
(0, 0, 1, 0, -1, 0, 1, 0, 0),
1557
(0, 0, 1, 0, 1, 0, -1, 0, 0),
1558
(0, 0, 1, 1, 0, 0, 0, 1, 0),
1559
(0, 1, 0, -1, 0, 0, 0, 0, 1),
1560
(0, 1, 0, 0, 0, -1, -1, 0, 0),
1561
(0, 1, 0, 0, 0, 1, 1, 0, 0),
1562
(0, 1, 0, 1, 0, 0, 0, 0, -1),
1563
(1, 0, 0, 0, -1, 0, 0, 0, -1),
1564
(1, 0, 0, 0, 0, -1, 0, 1, 0),
1565
(1, 0, 0, 0, 0, 1, 0, -1, 0)]
1566
elif self._border(13) and self._border(14):
1567
# borders 8, 9, 13, 14
1568
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1569
(-1, -1, -1, 0, 0, 1, 0, 1, 0),
1570
(-1, -1, -1, 0, 1, 0, 1, 0, 0),
1571
(-1, -1, -1, 1, 0, 0, 0, 0, 1),
1572
(-1, 0, 0, 0, -1, 0, 1, 1, 1),
1573
(-1, 0, 0, 0, 0, -1, 0, -1, 0),
1574
(-1, 0, 0, 1, 1, 1, 0, 0, -1),
1575
(0, -1, 0, -1, 0, 0, 0, 0, -1),
1576
(0, -1, 0, 0, 0, -1, 1, 1, 1),
1577
(0, -1, 0, 1, 1, 1, -1, 0, 0),
1578
(0, 0, -1, -1, 0, 0, 1, 1, 1),
1579
(0, 0, -1, 0, -1, 0, -1, 0, 0),
1580
(0, 0, -1, 1, 1, 1, 0, -1, 0),
1581
(0, 0, 1, -1, -1, -1, 1, 0, 0),
1582
(0, 0, 1, 0, 1, 0, -1, -1, -1),
1583
(0, 0, 1, 1, 0, 0, 0, 1, 0),
1584
(0, 1, 0, -1, -1, -1, 0, 0, 1),
1585
(0, 1, 0, 0, 0, 1, 1, 0, 0),
1586
(0, 1, 0, 1, 0, 0, -1, -1, -1),
1587
(1, 0, 0, -1, -1, -1, 0, 1, 0),
1588
(1, 0, 0, 0, 0, 1, -1, -1, -1),
1589
(1, 1, 1, -1, 0, 0, 0, -1, 0),
1590
(1, 1, 1, 0, -1, 0, 0, 0, -1),
1591
(1, 1, 1, 0, 0, -1, -1, 0, 0)]
1592
else:
1593
# borders 8, 9
1594
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1595
(-1, 0, 0, 0, 0, -1, 0, -1, 0),
1596
(0, -1, 0, -1, 0, 0, 0, 0, -1),
1597
(0, 0, -1, 0, -1, 0, -1, 0, 0),
1598
(0, 0, 1, 1, 0, 0, 0, 1, 0),
1599
(0, 1, 0, 0, 0, 1, 1, 0, 0)]
1600
elif self._border(10):
1601
if self._border(11) and self._border(12):
1602
# borders 8, 10, 11, 12
1603
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1604
(-1, 0, 0, 0, -1, 0, 0, 0, 1),
1605
(-1, 0, 0, 0, 1, 0, 0, 0, -1),
1606
(0, -1, 0, -1, 0, 0, 0, 0, -1),
1607
(0, -1, 0, 1, 0, 0, 0, 0, 1),
1608
(0, 1, 0, -1, 0, 0, 0, 0, 1),
1609
(0, 1, 0, 1, 0, 0, 0, 0, -1),
1610
(1, 0, 0, 0, -1, 0, 0, 0, -1)]
1611
else:
1612
# borders 8, 10
1613
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1614
(-1, 0, 0, 0, -1, 0, 0, 0, 1),
1615
(0, -1, 0, -1, 0, 0, 0, 0, -1),
1616
(0, 1, 0, 1, 0, 0, 0, 0, -1)]
1617
elif self._border(14):
1618
# borders 8, 13, 14
1619
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1620
(-1, -1, -1, 1, 0, 0, 0, 0, 1),
1621
(-1, 0, 0, 1, 1, 1, 0, 0, -1),
1622
(0, -1, 0, -1, 0, 0, 0, 0, -1),
1623
(0, 1, 0, -1, -1, -1, 0, 0, 1),
1624
(1, 1, 1, 0, -1, 0, 0, 0, -1)]
1625
else:
1626
# borders 8
1627
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1628
(0, -1, 0, -1, 0, 0, 0, 0, -1)]
1629
1630
if self._border(9):
1631
if self._border(12):
1632
if self._border(10) and self._border(11):
1633
# borders 9, 10, 11, 12
1634
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1635
(-1, 0, 0, 0, -1, 0, 0, 0, 1),
1636
(-1, 0, 0, 0, 0, -1, 0, -1, 0),
1637
(-1, 0, 0, 0, 0, 1, 0, 1, 0),
1638
(-1, 0, 0, 0, 1, 0, 0, 0, -1),
1639
(1, 0, 0, 0, -1, 0, 0, 0, -1),
1640
(1, 0, 0, 0, 0, -1, 0, 1, 0),
1641
(1, 0, 0, 0, 0, 1, 0, -1, 0)]
1642
else:
1643
# borders 9, 12
1644
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1645
(-1, 0, 0, 0, 0, -1, 0, -1, 0),
1646
(-1, 0, 0, 0, 0, 1, 0, 1, 0),
1647
(1, 0, 0, 0, -1, 0, 0, 0, -1)]
1648
elif self._border(14):
1649
if self._border(13):
1650
# borders 9, 13, 14
1651
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1652
(-1, -1, -1, 0, 0, 1, 0, 1, 0),
1653
(-1, 0, 0, 0, 0, -1, 0, -1, 0),
1654
(1, 1, 1, 0, -1, 0, 0, 0, -1)]
1655
else:
1656
# borders 9, 14
1657
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1658
(-1, -1, -1, 0, 0, 1, 0, 1, 0),
1659
(-1, 0, 0, 0, 0, -1, 0, -1, 0),
1660
(1, 1, 1, 0, -1, 0, 0, 0, -1)]
1661
elif self._border(15):
1662
# borders 9, 15, 16
1663
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1664
(-1, 0, 0, -1, 0, 1, -1, 1, 0),
1665
(-1, 0, 0, 0, 0, -1, 0, -1, 0),
1666
(0, -1, 1, 0, -1, 0, 1, -1, 0),
1667
(0, -1, 1, 0, 0, 1, -1, 0, 1),
1668
(0, 1, -1, -1, 1, 0, 0, 1, 0),
1669
(0, 1, -1, 1, 0, -1, 0, 0, -1),
1670
(1, 0, 0, 1, -1, 0, 1, 0, -1)]
1671
else:
1672
# borders 9
1673
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1674
(-1, 0, 0, 0, 0, -1, 0, -1, 0)]
1675
1676
if self._border(10):
1677
if self._border(11) and self._border(12):
1678
# borders 10, 11, 12
1679
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1680
(-1, 0, 0, 0, -1, 0, 0, 0, 1),
1681
(-1, 0, 0, 0, 1, 0, 0, 0, -1),
1682
(1, 0, 0, 0, -1, 0, 0, 0, -1)]
1683
else:
1684
# borders 10
1685
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1686
(-1, 0, 0, 0, -1, 0, 0, 0, 1)]
1687
1688
if self._border(11):
1689
# borders 11
1690
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1691
(-1, 0, 0, 0, 1, 0, 0, 0, -1)]
1692
1693
if self._border(12):
1694
# border 12
1695
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1696
(1, 0, 0, 0, -1, 0, 0, 0, -1)]
1697
1698
if self._border(13) and self._border(14):
1699
# border 13, 14
1700
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1701
(1, 1, 1, 0, -1, 0, 0, 0, -1)]
1702
1703
if self._border(14):
1704
# border 14
1705
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1706
(1, 1, 1, 0, -1, 0, 0, 0, -1)]
1707
1708
if self._border(15):
1709
if self._border(16):
1710
# borders 15, 16
1711
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1712
(-1, 0, 0, -1, 0, 1, -1, 1, 0),
1713
(0, -1, 1, 0, -1, 0, 1, -1, 0),
1714
(0, 1, -1, 1, 0, -1, 0, 0, -1)]
1715
else:
1716
# borders 15
1717
return [(1, 0, 0, 0, 1, 0, 0, 0, 1),
1718
(0, 1, -1, 1, 0, -1, 0, 0, -1)]
1719
1720
return [(1, 0, 0, 0, 1, 0, 0, 0, 1)]
1721
1722
1723
def _automorphisms_reduced_slow(self):
1724
"""
1725
Return the automorphisms of the reduced ternary quadratic form.
1726
It searches over all 3x3 matrices with coefficients -1, 0, 1,
1727
determinant 1 and finite order, because Eisenstein reduced forms
1728
are Minkowski reduced. See Cassels.
1729
1730
EXAMPLES::
1731
1732
sage: Q = TernaryQF([1, 1, 7, 0, 0, 0])
1733
sage: Q.is_eisenstein_reduced()
1734
True
1735
sage: auts = Q._automorphisms_reduced_slow() # long time (3s on sage.math, 2014)
1736
sage: len(auts) # long time
1737
8
1738
sage: A = auts[randint(0,7)] # long time
1739
sage: Q(A) == Q # long time
1740
True
1741
sage: Q = TernaryQF([3, 4, 5, 3, 3, 2])
1742
sage: Q._automorphisms_reduced_slow() # long time
1743
[
1744
[1 0 0]
1745
[0 1 0]
1746
[0 0 1]
1747
]
1748
1749
"""
1750
1751
if TernaryQF.possible_automorphisms == None:
1752
1753
I = [-1, 0, 1]
1754
auts = [matrix(ZZ, 3, [a, b, c, d, e, f, g, h, i]) for a in I for b in I for c in I for d in I for e in I for f in I for g in I for h in I for i in I]
1755
auts = [m for m in auts if m.det() == 1]
1756
auts = [m for m in auts if m**2 in auts]
1757
auts = [m for m in auts if m**2 in auts]
1758
auts = [m for m in auts if m**2 in auts]
1759
TernaryQF.possible_automorphisms = auts
1760
1761
return [m for m in TernaryQF.possible_automorphisms if self(m) == self]
1762
1763
1764
def automorphisms(self, slow = True):
1765
"""
1766
Returns a list with the automorphisms of the definite ternary quadratic form.
1767
1768
EXAMPLES::
1769
1770
sage: Q = TernaryQF([1, 1, 7, 0, 0, 0])
1771
sage: auts = Q.automorphisms()
1772
sage: auts
1773
[
1774
[-1 0 0] [-1 0 0] [ 0 -1 0] [ 0 -1 0] [ 0 1 0] [ 0 1 0]
1775
[ 0 -1 0] [ 0 1 0] [-1 0 0] [ 1 0 0] [-1 0 0] [ 1 0 0]
1776
[ 0 0 1], [ 0 0 -1], [ 0 0 -1], [ 0 0 1], [ 0 0 1], [ 0 0 -1],
1777
[ 1 0 0] [1 0 0]
1778
[ 0 -1 0] [0 1 0]
1779
[ 0 0 -1], [0 0 1]
1780
]
1781
sage: all(Q == Q(A) for A in auts)
1782
True
1783
sage: Q = TernaryQF([3, 4, 5, 3, 3, 2])
1784
sage: Q.automorphisms(slow = False)
1785
[
1786
[1 0 0]
1787
[0 1 0]
1788
[0 0 1]
1789
]
1790
sage: Q = TernaryQF([4, 2, 4, 3, -4, -5])
1791
sage: auts = Q.automorphisms(slow = False)
1792
sage: auts
1793
[
1794
[1 0 0] [ 2 -1 -1]
1795
[0 1 0] [ 3 -2 -1]
1796
[0 0 1], [ 0 0 -1]
1797
]
1798
sage: A = auts[1]
1799
sage: Q(A) == Q
1800
True
1801
sage: Qr, M_red = Q.reduced_form_eisenstein()
1802
sage: Qr
1803
Ternary quadratic form with integer coefficients:
1804
[1 2 3]
1805
[-1 0 -1]
1806
sage: Q(A*M_red) == Qr
1807
True
1808
1809
"""
1810
1811
if not self.is_definite():
1812
raise ValueError, "Oops, only implemented for definite forms."
1813
1814
if self._automorphisms != None:
1815
return self._automorphisms
1816
1817
if self.is_positive_definite():
1818
if self.is_eisenstein_reduced():
1819
if slow:
1820
self._automorphisms = self._automorphisms_reduced_slow()
1821
else:
1822
auts = self._automorphisms_reduced_fast()
1823
self._automorphisms = [matrix(ZZ, 3, A) for A in auts]
1824
else:
1825
[Qr, M] = self.reduced_form_eisenstein()
1826
auts = Qr.automorphisms(slow)
1827
M_inv = M.inverse()
1828
self._automorphisms = [M*m*M_inv for m in auts]
1829
else:
1830
self._automorphisms = (-self).automorphisms()
1831
return self._automorphisms
1832
1833
1834
1835
def _number_of_automorphisms_reduced(self):
1836
"""
1837
Return the number of automorphisms of the reduced definite ternary quadratic form.
1838
1839
EXAMPLES::
1840
1841
sage: Q = TernaryQF([1, 1, 7, 0, 0, 0])
1842
sage: Q._number_of_automorphisms_reduced()
1843
8
1844
sage: len(Q.automorphisms(slow = False))
1845
8
1846
sage: Q = TernaryQF([3, 4, 5, 3, 3, 2])
1847
sage: Q._number_of_automorphisms_reduced()
1848
1
1849
1850
"""
1851
1852
if self._border(1):
1853
if self._border(2):
1854
if self._border(14):
1855
if self._border(9):
1856
# borders 1, 2, 9, 14
1857
return 8
1858
else:
1859
# borders 1, 2, 14
1860
return 4
1861
else:
1862
# borders 1
1863
return 2
1864
1865
if self._border(2):
1866
# borders 2
1867
return 2
1868
1869
if self._border(3):
1870
# borders 3
1871
return 2
1872
1873
if self._border(4):
1874
if self._border(10):
1875
if self._border(8):
1876
# borders 4, 8, 10
1877
return 12
1878
else:
1879
# borders 4, 10
1880
return 4
1881
else:
1882
# borders 4
1883
return 2
1884
1885
if self._border(5):
1886
if self._border(6):
1887
if self._border(7):
1888
if self._border(8):
1889
if self._border(15):
1890
# borders 5, 6, 7, 8, 15
1891
return 8
1892
else:
1893
# borders 5, 6, 7
1894
return 4
1895
elif self._border(11):
1896
# borders 5, 11
1897
return 4
1898
else:
1899
# borders 5
1900
return 2
1901
1902
if self._border(6):
1903
if self._border(12):
1904
if self._border(9):
1905
# borders 6, 9, 12
1906
return 12
1907
else:
1908
# borders 6, 12
1909
return 4
1910
else:
1911
# borders 6
1912
return 2
1913
1914
if self._border(7):
1915
if self._border(8) and self._border(15):
1916
if self._border(16):
1917
if self._border(9):
1918
# borders 7, 8, 9, 15, 16
1919
return 24
1920
else:
1921
# borders 7, 8, 15, 16
1922
return 8
1923
else:
1924
# borders 7, 8, 15
1925
return 4
1926
elif self._border(9):
1927
# borders 7, 9
1928
return 6
1929
else:
1930
# borders 7
1931
return 2
1932
1933
1934
if self._border(8):
1935
if self._border(9):
1936
if self._border(10) and self._border(11) and self._border(12):
1937
# borders 8, 9, 10, 11, 12
1938
return 24
1939
elif self._border(13) and self._border(14):
1940
# borders 8, 9, 13, 14
1941
return 24
1942
else:
1943
# borders 8, 9
1944
return 6
1945
elif self._border(10):
1946
if self._border(11) and self._border(12):
1947
# borders 8, 10, 11, 12
1948
return 8
1949
else:
1950
# borders 8, 10
1951
return 4
1952
elif self._border(14):
1953
# borders 8, 13, 14
1954
return 6
1955
else:
1956
# borders 8
1957
return 2
1958
1959
if self._border(9):
1960
if self._border(12):
1961
if self._border(10) and self._border(11):
1962
# borders 9, 10, 11, 12
1963
return 8
1964
else:
1965
# borders 9, 12
1966
return 4
1967
elif self._border(14):
1968
if self._border(13):
1969
# borders 9, 13, 14
1970
return 4
1971
else:
1972
# borders 9, 14
1973
return 4
1974
elif self._border(15):
1975
# borders 9, 15, 16
1976
return 8
1977
else:
1978
# borders 9
1979
return 2
1980
1981
if self._border(10):
1982
if self._border(11) and self._border(12):
1983
# borders 10, 11, 12
1984
return 4
1985
else:
1986
# borders 10
1987
return 2
1988
1989
if self._border(11):
1990
# borders 11
1991
return 2
1992
1993
if self._border(12):
1994
# border 12
1995
return 2
1996
1997
if self._border(13) and self._border(14):
1998
# border 13, 14
1999
return 2
2000
2001
if self._border(14):
2002
# border 14
2003
return 2
2004
2005
if self._border(15):
2006
if self._border(16):
2007
# borders 15, 16
2008
return 4
2009
else:
2010
# borders 15
2011
return 2
2012
2013
return 1
2014
2015
2016
2017
def number_of_automorphisms(self, slow = True):
2018
"""
2019
Return the number of automorphisms of the definite ternary quadratic form.
2020
2021
EXAMPLES::
2022
2023
sage: Q = TernaryQF([1, 1, 7, 0, 0, 0])
2024
sage: A = matrix(ZZ, 3, [0, 1, 0, -1, 5, 0, -8, -1, 1])
2025
sage: A.det()
2026
1
2027
sage: Q1 = Q(A)
2028
sage: Q1
2029
Ternary quadratic form with integer coefficients:
2030
[449 33 7]
2031
[-14 -112 102]
2032
sage: Q1.number_of_automorphisms()
2033
8
2034
sage: Q = TernaryQF([-19, -7, -6, -12, 20, 23])
2035
sage: Q.is_negative_definite()
2036
True
2037
sage: Q.number_of_automorphisms(slow = False)
2038
24
2039
2040
"""
2041
2042
if not self.is_definite():
2043
raise ValueError, "Oops, only implemented for definite forms."
2044
2045
if self._number_of_automorphisms != None:
2046
return self._number_of_automorphisms
2047
2048
if slow:
2049
self._number_of_automorphisms = len(self.automorphisms())
2050
else:
2051
if self.is_negative_definite():
2052
self._number_of_automorphisms = (-self).reduced_form_eisenstein(False)._number_of_automorphisms_reduced()
2053
else:
2054
self._number_of_automorphisms = self.reduced_form_eisenstein(False)._number_of_automorphisms_reduced()
2055
2056
return self._number_of_automorphisms
2057
2058
2059
def find_all_ternary_qf_by_level_disc(N, d):
2060
"""
2061
Find the coefficients of all the reduced ternary quadratic forms given its discriminant d and level N.
2062
If N|4d and d|N^2, then it may be some forms with that discriminant and level.
2063
2064
EXAMPLES::
2065
2066
sage: find_all_ternary_qf_by_level_disc(44, 11)
2067
[Ternary quadratic form with integer coefficients:
2068
[1 1 3]
2069
[0 -1 0], Ternary quadratic form with integer coefficients:
2070
[1 1 4]
2071
[1 1 1]]
2072
sage: find_all_ternary_qf_by_level_disc(44, 11^2 * 16)
2073
[Ternary quadratic form with integer coefficients:
2074
[3 15 15]
2075
[-14 -2 -2], Ternary quadratic form with integer coefficients:
2076
[4 11 12]
2077
[0 -4 0]]
2078
sage: Q = TernaryQF([1, 1, 3, 0, -1, 0])
2079
sage: Q.is_eisenstein_reduced()
2080
True
2081
sage: Q.reciprocal_reduced()
2082
Ternary quadratic form with integer coefficients:
2083
[4 11 12]
2084
[0 -4 0]
2085
sage: find_all_ternary_qf_by_level_disc(44, 22)
2086
[]
2087
sage: find_all_ternary_qf_by_level_disc(44, 33)
2088
Traceback (most recent call last):
2089
...
2090
ValueError: There are no ternary forms of this level and discriminant
2091
2092
2093
"""
2094
2095
return map(TernaryQF, _find_all_ternary_qf_by_level_disc(N, d))
2096
2097
def find_a_ternary_qf_by_level_disc(N, d):
2098
"""
2099
Find a reduced ternary quadratic form given its discriminant d and level N.
2100
If N|4d and d|N^2, then it may be a form with that discriminant and level.
2101
2102
EXAMPLES::
2103
2104
sage: Q1 = find_a_ternary_qf_by_level_disc(44, 11)
2105
sage: Q1
2106
Ternary quadratic form with integer coefficients:
2107
[1 1 3]
2108
[0 -1 0]
2109
sage: Q2 = find_a_ternary_qf_by_level_disc(44, 11^2 * 16)
2110
sage: Q2
2111
Ternary quadratic form with integer coefficients:
2112
[3 15 15]
2113
[-14 -2 -2]
2114
sage: Q1.is_eisenstein_reduced()
2115
True
2116
sage: Q1.level()
2117
44
2118
sage: Q1.disc()
2119
11
2120
sage: find_a_ternary_qf_by_level_disc(44, 22)
2121
sage: find_a_ternary_qf_by_level_disc(44, 33)
2122
Traceback (most recent call last):
2123
...
2124
ValueError: There are no ternary forms of this level and discriminant
2125
2126
"""
2127
2128
q = _find_a_ternary_qf_by_level_disc(N, d)
2129
if q != None:
2130
return TernaryQF(q)
2131
2132