Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/quadratic_forms/quadratic_form.py
8817 views
1
"""
2
Quadratic Forms Overview
3
4
AUTHORS:
5
6
- Jon Hanke (2007-06-19)
7
- Anna Haensch (2010-07-01): Formatting and ReSTification
8
"""
9
10
#*****************************************************************************
11
# Copyright (C) 2007 William Stein and Jonathan Hanke
12
#
13
# Distributed under the terms of the GNU General Public License (GPL)
14
#
15
# This code is distributed in the hope that it will be useful,
16
# but WITHOUT ANY WARRANTY; without even the implied warranty of
17
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
# General Public License for more details.
19
#
20
# The full text of the GPL is available at:
21
#
22
# http://www.gnu.org/licenses/
23
#*****************************************************************************
24
25
from warnings import warn
26
from copy import deepcopy
27
28
from sage.matrix.constructor import matrix
29
from sage.matrix.matrix_space import MatrixSpace
30
from sage.matrix.matrix import is_Matrix
31
from sage.rings.integer_ring import IntegerRing, ZZ
32
from sage.rings.ring import Ring
33
from sage.misc.functional import ideal, denominator, is_even, is_field
34
from sage.rings.arith import GCD, LCM
35
from sage.rings.principal_ideal_domain import is_PrincipalIdealDomain
36
from sage.rings.ring import is_Ring
37
from sage.matrix.matrix import is_Matrix
38
from sage.structure.sage_object import SageObject
39
from sage.structure.element import is_Vector
40
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
41
from sage.modules.free_module_element import vector
42
43
from sage.quadratic_forms.quadratic_form__evaluate import QFEvaluateVector, QFEvaluateMatrix
44
45
46
47
def QuadraticForm__constructor(R, n=None, entries=None):
48
"""
49
Wrapper for the QuadraticForm class constructor. This is meant
50
for internal use within the QuadraticForm class code only. You
51
should instead directly call QuadraticForm().
52
53
EXAMPLES::
54
55
sage: from sage.quadratic_forms.quadratic_form import QuadraticForm__constructor
56
sage: QuadraticForm__constructor(ZZ, 3) ## Makes a generic quadratic form over the integers
57
Quadratic form in 3 variables over Integer Ring with coefficients:
58
[ 0 0 0 ]
59
[ * 0 0 ]
60
[ * * 0 ]
61
62
"""
63
return QuadraticForm(R, n, entries)
64
65
66
def is_QuadraticForm(Q):
67
"""
68
Determines if the object Q is an element of the QuadraticForm class.
69
70
EXAMPLES::
71
72
sage: Q = QuadraticForm(ZZ, 2, [1,2,3])
73
sage: is_QuadraticForm(Q) ##random -- deprecated
74
True
75
sage: is_QuadraticForm(2) ##random -- deprecated
76
False
77
78
"""
79
return isinstance(Q, QuadraticForm)
80
81
82
83
class QuadraticForm(SageObject):
84
r"""
85
The ``QuadraticForm`` class represents a quadratic form in n variables with
86
coefficients in the ring R.
87
88
INPUT:
89
90
The constructor may be called in any of the following ways.
91
92
#. ``QuadraticForm(R, n, entries)``, where
93
94
- `R` -- ring for which the quadratic form is defined
95
- `n` -- an integer >= 0
96
- ``entries`` -- a list of `n(n+1)/2` coefficients of the quadratic form
97
in `R` (given lexographically, or equivalently, by rows of the matrix)
98
99
#. ``QuadraticForm(R, n)``, where
100
101
- `R` -- a ring
102
- `n` -- a symmetric `n \times n` matrix with even diagonal (relative to
103
`R`)
104
105
#. ``QuadraticForm(R)``, where
106
107
- `R` -- a symmetric `n \times n` matrix with even diagonal (relative to
108
its base ring)
109
110
If the keyword argument ``unsafe_initialize`` is True, then the subsequent
111
fields may by used to force the external initialization of various fields
112
of the quadratic form. Currently the only fields which can be set are:
113
114
- ``number_of_automorphisms``
115
- ``determinant``
116
117
118
OUTPUT:
119
120
quadratic form
121
122
EXAMPLES::
123
124
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
125
sage: Q
126
Quadratic form in 3 variables over Integer Ring with coefficients:
127
[ 1 2 3 ]
128
[ * 4 5 ]
129
[ * * 6 ]
130
131
::
132
133
sage: Q = QuadraticForm(QQ, 3, [1,2,3,4/3 ,5,6])
134
sage: Q
135
Quadratic form in 3 variables over Rational Field with coefficients:
136
[ 1 2 3 ]
137
[ * 4/3 5 ]
138
[ * * 6 ]
139
sage: Q[0,0]
140
1
141
sage: Q[0,0].parent()
142
Rational Field
143
144
::
145
146
sage: Q = QuadraticForm(QQ, 7, range(28))
147
sage: Q
148
Quadratic form in 7 variables over Rational Field with coefficients:
149
[ 0 1 2 3 4 5 6 ]
150
[ * 7 8 9 10 11 12 ]
151
[ * * 13 14 15 16 17 ]
152
[ * * * 18 19 20 21 ]
153
[ * * * * 22 23 24 ]
154
[ * * * * * 25 26 ]
155
[ * * * * * * 27 ]
156
157
::
158
159
sage: Q = QuadraticForm(QQ, 2, range(1,4))
160
sage: A = Matrix(ZZ,2,2,[-1,0,0,1])
161
sage: Q(A)
162
Quadratic form in 2 variables over Rational Field with coefficients:
163
[ 1 -2 ]
164
[ * 3 ]
165
166
::
167
168
sage: m = matrix(2,2,[1,2,3,4])
169
sage: m + m.transpose()
170
[2 5]
171
[5 8]
172
sage: QuadraticForm(m + m.transpose())
173
Quadratic form in 2 variables over Integer Ring with coefficients:
174
[ 1 5 ]
175
[ * 4 ]
176
177
::
178
179
sage: QuadraticForm(ZZ, m + m.transpose())
180
Quadratic form in 2 variables over Integer Ring with coefficients:
181
[ 1 5 ]
182
[ * 4 ]
183
184
::
185
186
sage: QuadraticForm(QQ, m + m.transpose())
187
Quadratic form in 2 variables over Rational Field with coefficients:
188
[ 1 5 ]
189
[ * 4 ]
190
"""
191
192
## Import specialized methods:
193
## ---------------------------
194
195
## Routines to compute the p-adic local normal form
196
from sage.quadratic_forms.quadratic_form__local_normal_form import \
197
find_entry_with_minimal_scale_at_prime, \
198
local_normal_form, \
199
jordan_blocks_by_scale_and_unimodular, \
200
jordan_blocks_in_unimodular_list_by_scale_power
201
202
## Routines to perform elementary variable substitutions
203
from sage.quadratic_forms.quadratic_form__variable_substitutions import \
204
swap_variables, \
205
multiply_variable, \
206
divide_variable, \
207
scale_by_factor, \
208
extract_variables, \
209
elementary_substitution, \
210
add_symmetric
211
212
## Routines to compute p-adic field invariants
213
from sage.quadratic_forms.quadratic_form__local_field_invariants import \
214
rational_diagonal_form, \
215
signature_vector, \
216
signature, \
217
hasse_invariant, \
218
hasse_invariant__OMeara, \
219
is_hyperbolic, \
220
is_anisotropic, \
221
is_isotropic, \
222
anisotropic_primes, \
223
compute_definiteness, \
224
compute_definiteness_string_by_determinants, \
225
is_positive_definite, \
226
is_negative_definite, \
227
is_indefinite, \
228
is_definite
229
230
## Routines to compute local densities by the reduction procedure
231
from sage.quadratic_forms.quadratic_form__local_density_congruence import \
232
count_modp_solutions__by_Gauss_sum, \
233
local_good_density_congruence_odd, \
234
local_good_density_congruence_even, \
235
local_good_density_congruence, \
236
local_zero_density_congruence, \
237
local_badI_density_congruence, \
238
local_badII_density_congruence, \
239
local_bad_density_congruence, \
240
local_density_congruence, \
241
local_primitive_density_congruence
242
243
## Routines to compute local densities by counting solutions of various types
244
from sage.quadratic_forms.quadratic_form__count_local_2 import \
245
count_congruence_solutions_as_vector, \
246
count_congruence_solutions, \
247
count_congruence_solutions__good_type, \
248
count_congruence_solutions__zero_type, \
249
count_congruence_solutions__bad_type, \
250
count_congruence_solutions__bad_type_I, \
251
count_congruence_solutions__bad_type_II
252
253
## Routines to be called by the user to compute local densities
254
from sage.quadratic_forms.quadratic_form__local_density_interfaces import \
255
local_density, \
256
local_primitive_density
257
258
## Routines for computing with ternary forms
259
from sage.quadratic_forms.quadratic_form__ternary_Tornaria import \
260
disc, \
261
content, \
262
adjoint, \
263
antiadjoint, \
264
is_adjoint, \
265
reciprocal, \
266
omega, \
267
delta, \
268
level__Tornaria, \
269
discrec, \
270
hasse_conductor, \
271
clifford_invariant, \
272
clifford_conductor, \
273
basiclemma, \
274
basiclemmavec, \
275
xi, \
276
xi_rec, \
277
lll, \
278
representation_number_list, \
279
representation_vector_list, \
280
is_zero, \
281
is_zero_nonsingular, \
282
is_zero_singular
283
284
## Routines to compute the theta function
285
from sage.quadratic_forms.quadratic_form__theta import \
286
theta_series, \
287
theta_series_degree_2, \
288
theta_by_pari, \
289
theta_by_cholesky
290
291
## Routines to compute the product of all local densities
292
from sage.quadratic_forms.quadratic_form__siegel_product import \
293
siegel_product
294
295
## Routines to compute p-neighbors
296
from sage.quadratic_forms.quadratic_form__neighbors import \
297
find_primitive_p_divisible_vector__random, \
298
find_primitive_p_divisible_vector__next, \
299
find_p_neighbor_from_vec
300
301
## Routines to reduce a given quadratic form
302
from sage.quadratic_forms.quadratic_form__reduction_theory import \
303
reduced_binary_form1, \
304
reduced_ternary_form__Dickson, \
305
reduced_binary_form, \
306
minkowski_reduction, \
307
minkowski_reduction_for_4vars__SP
308
## Wrappers for Conway-Sloane genus routines (in ./genera/)
309
from sage.quadratic_forms.quadratic_form__genus import \
310
global_genus_symbol, \
311
local_genus_symbol, \
312
CS_genus_symbol_list
313
314
315
## Routines to compute local masses for ZZ.
316
from sage.quadratic_forms.quadratic_form__mass import \
317
shimura_mass__maximal, \
318
GHY_mass__maximal
319
from sage.quadratic_forms.quadratic_form__mass__Siegel_densities import \
320
mass__by_Siegel_densities, \
321
Pall_mass_density_at_odd_prime, \
322
Watson_mass_at_2, \
323
Kitaoka_mass_at_2, \
324
mass_at_two_by_counting_mod_power
325
from sage.quadratic_forms.quadratic_form__mass__Conway_Sloane_masses import \
326
parity, \
327
is_even, \
328
is_odd, \
329
conway_species_list_at_odd_prime, \
330
conway_species_list_at_2, \
331
conway_octane_of_this_unimodular_Jordan_block_at_2, \
332
conway_diagonal_factor, \
333
conway_cross_product_doubled_power, \
334
conway_type_factor, \
335
conway_p_mass, \
336
conway_standard_p_mass, \
337
conway_standard_mass, \
338
conway_mass
339
# conway_generic_mass, \
340
# conway_p_mass_adjustment
341
342
## Routines to check local representability of numbers
343
from sage.quadratic_forms.quadratic_form__local_representation_conditions import \
344
local_representation_conditions, \
345
is_locally_universal_at_prime, \
346
is_locally_universal_at_all_primes, \
347
is_locally_universal_at_all_places, \
348
is_locally_represented_number_at_place, \
349
is_locally_represented_number
350
351
## Routines to make a split local covering of the given quadratic form.
352
from sage.quadratic_forms.quadratic_form__split_local_covering import \
353
cholesky_decomposition, \
354
vectors_by_length, \
355
complementary_subform_to_vector, \
356
split_local_cover
357
358
## Routines to make automorphisms of the given quadratic form.
359
from sage.quadratic_forms.quadratic_form__automorphisms import \
360
basis_of_short_vectors, \
361
short_vector_list_up_to_length, \
362
short_primitive_vector_list_up_to_length, \
363
automorphisms, \
364
number_of_automorphisms, \
365
number_of_automorphisms__souvigner, \
366
set_number_of_automorphisms
367
368
## Routines to test the local and global equivalence/isometry of two quadratic forms.
369
from sage.quadratic_forms.quadratic_form__equivalence_testing import \
370
is_globally_equivalent__souvigner, \
371
is_globally_equivalent_to, \
372
is_locally_equivalent_to, \
373
has_equivalent_Jordan_decomposition_at_prime
374
375
def __init__(self, R, n=None, entries=None, unsafe_initialization=False, number_of_automorphisms=None, determinant=None):
376
"""
377
EXAMPLES::
378
379
sage: s = QuadraticForm(ZZ, 4, range(10))
380
sage: s == loads(dumps(s))
381
True
382
"""
383
## Deal with: QuadraticForm(ring, matrix)
384
matrix_init_flag = False
385
if isinstance(R, Ring):
386
if is_Matrix(n):
387
## Test if n is symmetric and has even diagonal
388
if not self._is_even_symmetric_matrix_(n, R):
389
raise TypeError, "Oops! The matrix is not a symmetric with even diagonal defined over R."
390
391
## Rename the matrix and ring
392
M = n
393
M_ring = R
394
matrix_init_flag = True
395
396
397
## Deal with: QuadraticForm(matrix)
398
if is_Matrix(R) and (n == None):
399
400
## Test if R is symmetric and has even diagonal
401
if not self._is_even_symmetric_matrix_(R):
402
raise TypeError, "Oops! The matrix is not a symmetric with even diagonal."
403
404
## Rename the matrix and ring
405
M = R
406
M_ring = R.base_ring()
407
matrix_init_flag = True
408
409
## Perform the quadratic form initialization
410
if matrix_init_flag == True:
411
self.__n = M.nrows()
412
self.__base_ring = M_ring
413
self.__coeffs = []
414
for i in range(M.nrows()):
415
for j in range(i, M.nrows()):
416
if (i == j):
417
self.__coeffs += [ M_ring(M[i,j] / 2) ]
418
else:
419
self.__coeffs += [ M_ring(M[i,j]) ]
420
421
return
422
423
## -----------------------------------------------------------
424
425
## Verify the size of the matrix is an integer >= 0
426
try:
427
n = int(n)
428
except Exception:
429
raise TypeError, "Oops! The size " + str(n) + " must be an integer."
430
if (n < 0):
431
raise TypeError, "Oops! The size " + str(n) + " must be a non-negative integer."
432
433
## TODO: Verify that R is a ring...
434
435
## Store the relevant variables
436
N = int(n*(n+1))/2
437
self.__n = int(n)
438
self.__base_ring = R
439
self.__coeffs = [self.__base_ring(0) for i in range(N)]
440
441
## Check if entries is a list for the current size, and if so, write the upper-triangular matrix
442
if isinstance(entries, list) and (len(entries) == N):
443
for i in range(N):
444
self.__coeffs[i] = self.__base_ring(entries[i])
445
elif (entries != None):
446
raise TypeError, "Oops! The entries " + str(entries) + "must be a list of size n(n+1)/2."
447
448
## -----------------------------------------------------------
449
450
## Process possible forced initialization of various fields
451
self._external_initialization_list = []
452
if unsafe_initialization:
453
454
## Set the number of automorphisms
455
if number_of_automorphisms != None:
456
self.set_number_of_automorphisms(number_of_automorphisms)
457
#self.__number_of_automorphisms = number_of_automorphisms
458
#self.__external_initialization_list.append('number_of_automorphisms')
459
460
## Set the determinant
461
if determinant != None:
462
self.__det = determinant
463
self._external_initialization_list.append('determinant')
464
465
466
def list_external_initializations(self):
467
"""
468
Returns a list of the fields which were set externally at
469
creation, and not created through the usual QuadraticForm
470
methods. These fields are as good as the external process
471
that made them, and are thus not guaranteed to be correct.
472
473
EXAMPLES::
474
475
sage: Q = QuadraticForm(ZZ, 2, [1,0,5])
476
sage: Q.list_external_initializations()
477
[]
478
sage: T = Q.theta_series()
479
sage: Q.list_external_initializations()
480
[]
481
sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=False, number_of_automorphisms=3, determinant=0)
482
sage: Q.list_external_initializations()
483
[]
484
485
::
486
487
sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=False, number_of_automorphisms=3, determinant=0)
488
sage: Q.list_external_initializations()
489
[]
490
sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=True, number_of_automorphisms=3, determinant=0)
491
sage: Q.list_external_initializations()
492
['number_of_automorphisms', 'determinant']
493
"""
494
return deepcopy(self._external_initialization_list)
495
496
497
def _pari_(self):
498
"""
499
Return a PARI-formatted Hessian matrix for Q.
500
501
EXAMPLES::
502
503
sage: Q = QuadraticForm(ZZ, 2, [1,0,5])
504
sage: Q._pari_()
505
[2, 0; 0, 10]
506
507
"""
508
return self.matrix()._pari_()
509
510
def _pari_init_(self):
511
"""
512
Return a PARI-formatted Hessian matrix for Q, as string.
513
514
EXAMPLES::
515
516
sage: Q = QuadraticForm(ZZ, 2, [1,0,5])
517
sage: Q._pari_init_()
518
'Mat([2,0;0,10])'
519
520
"""
521
return self.matrix()._pari_init_()
522
523
524
def _repr_(self):
525
"""
526
Give a text representation for the quadratic form given as an upper-triangular matrix of coefficients.
527
528
EXAMPLES::
529
530
sage: QuadraticForm(ZZ, 2, [1,3,5])
531
Quadratic form in 2 variables over Integer Ring with coefficients:
532
[ 1 3 ]
533
[ * 5 ]
534
535
"""
536
n = self.dim()
537
out_str = "Quadratic form in " + str(n) + " variables over " + str(self.base_ring()) + " with coefficients: \n"
538
for i in range(n):
539
if i > 0:
540
out_str += '\n'
541
out_str += "[ "
542
for j in range(n):
543
if (i > j):
544
out_str += "* "
545
else:
546
out_str += str(self[i,j]) + " "
547
out_str += "]"
548
return out_str
549
550
551
def _latex_(self):
552
"""
553
Give a LaTeX representation for the quadratic form given as an upper-triangular matrix of coefficients.
554
555
EXAMPLES::
556
557
sage: Q = QuadraticForm(ZZ, 2, [2,3,5])
558
sage: Q._latex_()
559
'Quadratic form in 2 variables over Integer Ring with coefficients: \\newline\\left[ \\begin{array}{cc}2 & 3 & * & 5 & \\end{array} \\right]'
560
561
"""
562
n = self.dim()
563
out_str = ""
564
out_str += "Quadratic form in " + str(n) + " variables over " + str(self.base_ring())
565
out_str += " with coefficients: \\newline"
566
out_str += "\\left[ \\begin{array}{" + n * "c" + "}"
567
for i in range(n):
568
for j in range(n):
569
if (i > j):
570
out_str += " * & "
571
else:
572
out_str += str(self[i,j]) + " & "
573
# if i < (n-1):
574
# out_str += "\\"
575
out_str += "\\end{array} \\right]"
576
return out_str
577
578
579
580
def __getitem__(self, ij):
581
"""
582
Return the coefficient `a_{ij}` of `x_i * x_j`.
583
584
EXAMPLES::
585
586
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
587
sage: matrix(ZZ, 3, 3, [Q[i,j] for i in range(3) for j in range(3)])
588
[1 2 3]
589
[2 4 5]
590
[3 5 6]
591
592
"""
593
## Unpack the list of indices
594
i, j = ij
595
i = int(i)
596
j = int(j)
597
598
## Ensure we're using upper-triangular coordinates
599
if i > j:
600
tmp = i
601
i = j
602
j = tmp
603
604
return self.__coeffs[i*self.__n - i*(i-1)/2 + j - i]
605
606
607
def __setitem__(self, ij, coeff):
608
"""
609
Set the coefficient `a_{ij}` in front of `x_i * x_j`.
610
611
EXAMPLES::
612
613
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
614
sage: Q
615
Quadratic form in 3 variables over Integer Ring with coefficients:
616
[ 1 2 3 ]
617
[ * 4 5 ]
618
[ * * 6 ]
619
sage: Q[2,1] = 17
620
sage: Q
621
Quadratic form in 3 variables over Integer Ring with coefficients:
622
[ 1 2 3 ]
623
[ * 4 17 ]
624
[ * * 6 ]
625
626
"""
627
## Unpack the list of indices
628
i, j = ij
629
i = int(i)
630
j = int(j)
631
632
## TO DO: Verify that 0 <= i, j <= (n-1)
633
634
## Ensure we're using upper-triangular coordinates
635
if i > j:
636
tmp = i
637
i = j
638
j = tmp
639
640
## Set the entry
641
try:
642
self.__coeffs[i*self.__n - i*(i-1)/2 + j -i] = self.__base_ring(coeff)
643
except Exception:
644
raise RuntimeError, "Oops! This coefficient can't be coerced to an element of the base ring for the quadratic form."
645
646
647
######################################
648
# TO DO: def __cmp__(self, other):
649
######################################
650
651
def __eq__(self, right):
652
"""
653
Determines if two quadratic forms are equal.
654
655
EXAMPLES::
656
657
sage: Q = QuadraticForm(ZZ, 2, [1,4,10])
658
sage: Q == Q
659
True
660
661
sage: Q1 = QuadraticForm(QQ, 2, [1,4,10])
662
sage: Q == Q1
663
False
664
665
sage: Q2 = QuadraticForm(ZZ, 2, [1,4,-10])
666
sage: Q == Q1
667
False
668
sage: Q == Q2
669
False
670
sage: Q1 == Q2
671
False
672
673
"""
674
if not isinstance(right, QuadraticForm):
675
return False
676
return (self.__base_ring == right.__base_ring) and (self.__coeffs == right.__coeffs)
677
678
679
def __add__(self, right):
680
"""
681
Returns the direct sum of two quadratic forms.
682
683
EXAMPLES::
684
sage: Q = QuadraticForm(ZZ, 2, [1,4,10])
685
sage: Q
686
Quadratic form in 2 variables over Integer Ring with coefficients:
687
[ 1 4 ]
688
[ * 10 ]
689
sage: Q2 = QuadraticForm(ZZ, 2, [1,4,-10])
690
sage: Q + Q2
691
Quadratic form in 4 variables over Integer Ring with coefficients:
692
[ 1 4 0 0 ]
693
[ * 10 0 0 ]
694
[ * * 1 4 ]
695
[ * * * -10 ]
696
697
"""
698
if not isinstance(right, QuadraticForm):
699
raise TypeError, "Oops! Can't add these objects since they're not both quadratic forms. =("
700
elif (self.base_ring() != right.base_ring()):
701
raise TypeError, "Oops! Can't add these since the quadratic forms don't have the same base rings... =("
702
else:
703
Q = QuadraticForm(self.base_ring(), self.dim() + right.dim())
704
n = self.dim()
705
m = right.dim()
706
707
for i in range(n):
708
for j in range(i,n):
709
Q[i,j] = self[i,j]
710
711
for i in range(m):
712
for j in range(i,m):
713
Q[n+i,n+j] = right[i,j]
714
715
return Q
716
717
718
def sum_by_coefficients_with(self, right):
719
"""
720
Returns the sum (on coefficients) of two quadratic forms of the same size.
721
722
EXAMPLES::
723
724
sage: Q = QuadraticForm(ZZ, 2, [1,4,10])
725
sage: Q
726
Quadratic form in 2 variables over Integer Ring with coefficients:
727
[ 1 4 ]
728
[ * 10 ]
729
sage: Q+Q
730
Quadratic form in 4 variables over Integer Ring with coefficients:
731
[ 1 4 0 0 ]
732
[ * 10 0 0 ]
733
[ * * 1 4 ]
734
[ * * * 10 ]
735
736
sage: Q2 = QuadraticForm(ZZ, 2, [1,4,-10])
737
sage: Q.sum_by_coefficients_with(Q2)
738
Quadratic form in 2 variables over Integer Ring with coefficients:
739
[ 2 8 ]
740
[ * 0 ]
741
742
"""
743
if not isinstance(right, QuadraticForm):
744
raise TypeError, "Oops! Can't add these objects since they're not both quadratic forms. =("
745
elif (self.__n != right.__n):
746
raise TypeError, "Oops! Can't add these since the quadratic forms don't have the same sizes... =("
747
elif (self.__base_ring != right.__base_ring):
748
raise TypeError, "Oops! Can't add these since the quadratic forms don't have the same base rings... =("
749
else:
750
return QuadraticForm(self.__base_ring, self.__n, [self.__coeffs[i] + right.__coeffs[i] for i in range(len(self.__coeffs))])
751
752
753
## ======================== CHANGE THIS TO A TENSOR PRODUCT?!? Even in Characteristic 2?!? =======================
754
# def __mul__(self, right):
755
# """
756
# Multiply (on the right) the quadratic form Q by an element of the ring that Q is defined over.
757
#
758
# EXAMPLES::
759
# sage: Q = QuadraticForm(ZZ, 2, [1,4,10])
760
# sage: Q*2
761
# Quadratic form in 2 variables over Integer Ring with coefficients:
762
# [ 2 8 ]
763
# [ * 20 ]
764
#
765
# sage: Q+Q == Q*2
766
# True
767
#
768
# """
769
# try:
770
# c = self.base_ring()(right)
771
# except Exception:
772
# raise TypeError, "Oh no! The multiplier cannot be coerced into the base ring of the quadratic form. =("
773
#
774
# return QuadraticForm(self.base_ring(), self.dim(), [c * self.__coeffs[i] for i in range(len(self.__coeffs))])
775
# =========================================================================================================================
776
777
778
779
def __call__(self, v):
780
"""
781
Evaluate this quadratic form Q on a vector or matrix of elements
782
coercible to the base ring of the quadratic form. If a vector
783
is given then the output will be the ring element Q(`v`), but if a
784
matrix is given then the output will be the quadratic form Q'
785
which in matrix notation is given by:
786
787
.. math::
788
Q' = v^t * Q * v.
789
790
791
EXAMPLES::
792
793
## Evaluate a quadratic form at a vector:
794
## --------------------------------------
795
sage: Q = QuadraticForm(QQ, 3, range(6))
796
sage: Q
797
Quadratic form in 3 variables over Rational Field with coefficients:
798
[ 0 1 2 ]
799
[ * 3 4 ]
800
[ * * 5 ]
801
sage: Q([1,2,3])
802
89
803
sage: Q([1,0,0])
804
0
805
sage: Q([1,1,1])
806
15
807
808
::
809
810
## Evaluate a quadratic form using a column matrix:
811
## ------------------------------------------------
812
sage: Q = QuadraticForm(QQ, 2, range(1,4))
813
sage: A = Matrix(ZZ,2,2,[-1,0,0,1])
814
sage: Q(A)
815
Quadratic form in 2 variables over Rational Field with coefficients:
816
[ 1 -2 ]
817
[ * 3 ]
818
sage: Q([1,0])
819
1
820
sage: type(Q([1,0]))
821
<type 'sage.rings.rational.Rational'>
822
sage: Q = QuadraticForm(QQ, 2, range(1,4))
823
sage: Q(matrix(2, [1,0]))
824
Quadratic form in 1 variables over Rational Field with coefficients:
825
[ 1 ]
826
827
::
828
829
## Simple 2x2 change of variables:
830
## -------------------------------
831
sage: Q = QuadraticForm(ZZ, 2, [1,0,1])
832
sage: Q
833
Quadratic form in 2 variables over Integer Ring with coefficients:
834
[ 1 0 ]
835
[ * 1 ]
836
sage: M = Matrix(ZZ, 2, 2, [1,1,0,1])
837
sage: M
838
[1 1]
839
[0 1]
840
sage: Q(M)
841
Quadratic form in 2 variables over Integer Ring with coefficients:
842
[ 1 2 ]
843
[ * 2 ]
844
845
::
846
847
## Some more tests:
848
## ----------------
849
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1])
850
sage: Q([1,2,3])
851
14
852
sage: v = vector([1,2,3])
853
sage: Q(v)
854
14
855
sage: t = tuple([1,2,3])
856
sage: Q(v)
857
14
858
sage: M = Matrix(ZZ, 3, [1,2,3])
859
sage: Q(M)
860
Quadratic form in 1 variables over Integer Ring with coefficients:
861
[ 14 ]
862
863
"""
864
## If we are passed a matrix A, return the quadratic form Q(A(x))
865
## (In matrix notation: A^t * Q * A)
866
n = self.dim()
867
868
if is_Matrix(v):
869
## Check that v has the correct number of rows
870
if v.nrows() != n:
871
raise TypeError, "Oops! The matrix must have " + str(n) + " rows. =("
872
873
## Create the new quadratic form
874
m = v.ncols()
875
Q2 = QuadraticForm(self.base_ring(), m)
876
return QFEvaluateMatrix(self, v, Q2)
877
878
elif (is_Vector(v) or isinstance(v, (list, tuple))):
879
## Check the vector/tuple/list has the correct length
880
if not (len(v) == n):
881
raise TypeError, "Oops! Your vector needs to have length " + str(n) + " ."
882
883
## TO DO: Check that the elements can be coerced into the base ring of Q -- on first elt.
884
if len(v) > 0:
885
try:
886
x = self.base_ring()(v[0])
887
except Exception:
888
raise TypeError, "Oops! Your vector is not coercible to the base ring of the quadratic form... =("
889
890
## Attempt to evaluate Q[v]
891
return QFEvaluateVector(self, v)
892
893
else:
894
raise(TypeError, "Oops! Presently we can only evaluate a quadratic form on a list, tuple, vector or matrix.")
895
896
897
898
899
## =====================================================================================================
900
901
def _is_even_symmetric_matrix_(self, A, R=None):
902
"""
903
Tests if a matrix is symmetric, defined over R, and has even diagonal in R.
904
905
INPUT:
906
A -- matrix
907
908
R -- ring
909
910
EXAMPLES::
911
912
sage: Q = QuadraticForm(ZZ, 2, [2,3,5])
913
sage: A = Q.matrix()
914
sage: A
915
[ 4 3]
916
[ 3 10]
917
sage: Q._is_even_symmetric_matrix_(A)
918
True
919
sage: A[0,0] = 1
920
sage: Q._is_even_symmetric_matrix_(A)
921
False
922
923
"""
924
if not is_Matrix(A):
925
raise TypeError, "A is not a matrix."
926
927
ring_coerce_test = True
928
if R == None: ## This allows us to omit the ring from the variables, and take it from the matrix
929
R = A.base_ring()
930
ring_coerce_test = False
931
932
if not isinstance(R, Ring):
933
raise TypeError, "R is not a ring."
934
935
if not A.is_square():
936
return False
937
938
## Test that the matrix is symmetric
939
n = A.nrows()
940
for i in range(n):
941
for j in range(i+1, n):
942
if A[i,j] != A[j,i]:
943
return False
944
945
## Test that all entries coerce to R
946
if not ((A.base_ring() == R) or (ring_coerce_test == True)):
947
try:
948
for i in range(n):
949
for j in range(i, n):
950
x = R(A[i,j])
951
except Exception:
952
return False
953
954
## Test that the diagonal is even (if 1/2 isn't in R)
955
if not R(2).is_unit():
956
for i in range(n):
957
if not is_even(R(A[i,i])):
958
return False
959
960
return True
961
962
963
## =====================================================================================================
964
965
def matrix(self):
966
"""
967
Returns the Hessian matrix A for which Q(X) = `(1/2) * X^t * A * X`.
968
969
EXAMPLES::
970
971
sage: Q = QuadraticForm(ZZ, 3, range(6))
972
sage: Q.matrix()
973
[ 0 1 2]
974
[ 1 6 4]
975
[ 2 4 10]
976
977
"""
978
return self.Hessian_matrix()
979
980
981
def Hessian_matrix(self):
982
"""
983
Returns the Hessian matrix A for which Q(X) = `(1/2) * X^t * A * X`.
984
985
EXAMPLES::
986
987
sage: Q = QuadraticForm(QQ, 2, range(1,4))
988
sage: Q
989
Quadratic form in 2 variables over Rational Field with coefficients:
990
[ 1 2 ]
991
[ * 3 ]
992
sage: Q.Hessian_matrix()
993
[2 2]
994
[2 6]
995
sage: Q.matrix().base_ring()
996
Rational Field
997
998
"""
999
mat_entries = []
1000
for i in range(self.dim()):
1001
for j in range(self.dim()):
1002
if (i == j):
1003
mat_entries += [ 2 * self[i,j] ]
1004
else:
1005
mat_entries += [ self[i,j] ]
1006
1007
return matrix(self.base_ring(), self.dim(), self.dim(), mat_entries)
1008
1009
1010
def Gram_matrix_rational(self):
1011
"""
1012
Returns a (symmetric) Gram matrix A for the quadratic form Q,
1013
meaning that
1014
1015
.. math::
1016
1017
Q(x) = x^t * A * x,
1018
1019
defined over the fraction field of the base ring.
1020
1021
EXAMPLES::
1022
1023
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
1024
sage: A = Q.Gram_matrix_rational(); A
1025
[1 0 0 0]
1026
[0 3 0 0]
1027
[0 0 5 0]
1028
[0 0 0 7]
1029
sage: A.base_ring()
1030
Rational Field
1031
1032
"""
1033
return (ZZ(1) / ZZ(2)) * self.matrix()
1034
1035
1036
def Gram_matrix(self):
1037
"""
1038
Returns a (symmetric) Gram matrix A for the quadratic form Q,
1039
meaning that
1040
1041
.. math::
1042
1043
Q(x) = x^t * A * x,
1044
1045
defined over the base ring of Q. If this is not possible,
1046
then a TypeError is raised.
1047
1048
EXAMPLES::
1049
1050
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
1051
sage: A = Q.Gram_matrix(); A
1052
[1 0 0 0]
1053
[0 3 0 0]
1054
[0 0 5 0]
1055
[0 0 0 7]
1056
sage: A.base_ring()
1057
Integer Ring
1058
1059
"""
1060
A = (ZZ(1) / ZZ(2)) * self.matrix()
1061
n = self.dim()
1062
1063
## Test to see if it has an integral Gram matrix
1064
Int_flag = True
1065
for i in range(n):
1066
for j in range(i,n):
1067
Int_flag = Int_flag and A[i,j] in self.base_ring()
1068
1069
## Return the Gram matrix, or an error
1070
if Int_flag:
1071
return MatrixSpace(self.base_ring(), n, n)(A)
1072
else:
1073
raise TypeError, "Oops! This form does not have an integral Gram matrix. =("
1074
1075
1076
def has_integral_Gram_matrix(self):
1077
"""
1078
Returns whether the quadratic form has an integral Gram matrix (with respect to its base ring).
1079
1080
A warning is issued if the form is defined over a field, since in that case the return is trivially true.
1081
1082
EXAMPLES::
1083
1084
sage: Q = QuadraticForm(ZZ, 2, [7,8,9])
1085
sage: Q.has_integral_Gram_matrix()
1086
True
1087
1088
::
1089
1090
sage: Q = QuadraticForm(ZZ, 2, [4,5,6])
1091
sage: Q.has_integral_Gram_matrix()
1092
False
1093
1094
"""
1095
## Warning over fields
1096
if is_field(self.base_ring()):
1097
warn("Warning -- A quadratic form over a field always has integral Gram matrix. Do you really want to do this?!?")
1098
1099
## Determine integrality of the Gram matrix
1100
flag = True
1101
try:
1102
self.Gram_matrix()
1103
except Exception:
1104
flag = False
1105
1106
return flag
1107
1108
1109
def gcd(self):
1110
"""
1111
Returns the greatest common divisor of the coefficients of the
1112
quadratic form (as a polynomial).
1113
1114
EXAMPLES::
1115
1116
sage: Q = QuadraticForm(ZZ, 4, range(1, 21, 2))
1117
sage: Q.gcd()
1118
1
1119
1120
::
1121
1122
sage: Q = QuadraticForm(ZZ, 4, range(0, 20, 2))
1123
sage: Q.gcd()
1124
2
1125
"""
1126
if self.base_ring() != ZZ:
1127
raise TypeError, "Oops! The given quadratic form must be defined over ZZ."
1128
1129
return GCD(self.coefficients())
1130
1131
1132
def polynomial(self,names='x'):
1133
r"""
1134
Returns the polynomial in 'n' variables of the quadratic form in the ring 'R[names].'
1135
1136
INPUT:
1137
1138
-'self' - a quadratic form over a commatitive ring.
1139
-'names' - the name of the variables. Digits will be appended to the name for each different canonical
1140
variable e.g x1, x2, x3 etc.
1141
1142
OUTPUT:
1143
1144
The polynomial form of the quadratic form.
1145
1146
EXAMPLES::
1147
1148
sage: Q = DiagonalQuadraticForm(QQ,[1, 3, 5, 7])
1149
sage: P = Q.polynomial(); P
1150
2*x0^2 + 6*x1^2 + 10*x2^2 + 14*x3^2
1151
1152
::
1153
1154
sage: F.<a> = NumberField(x^2 - 5)
1155
sage: Z = F.ring_of_integers()
1156
sage: Q = QuadraticForm(Z,3,[2*a, 3*a, 0 , 1 - a, 0, 2*a + 4])
1157
sage: P = Q.polynomial(names='y'); P
1158
4*a*y0^2 + 6*a*y0*y1 + (-2*a + 2)*y1^2 + (4*a + 8)*y2^2
1159
sage: Q = QuadraticForm(F,4,[a, 3*a, 0, 1 - a, a - 3, 0, 2*a + 4, 4 + a, 0, 1])
1160
sage: Q.polynomial(names='z')
1161
(2*a)*z0^2 + (6*a)*z0*z1 + (2*a - 6)*z1^2 + (2*a + 8)*z2^2 + (-2*a + 2)*z0*z3 + (4*a + 8)*z1*z3 + 2*z3^2
1162
sage: B.<i,j,k> = QuaternionAlgebra(F,-1,-1)
1163
sage: Q = QuadraticForm(B, 3, [2*a, 3*a, i, 1 - a, 0, 2*a + 4])
1164
sage: Q.polynomial()
1165
Traceback (most recent call last):
1166
...
1167
ValueError: Can only create polynomial rings over commutative rings.
1168
1169
"""
1170
M = self.matrix()
1171
n = self.dim()
1172
B = self.base_ring()
1173
try:
1174
R = PolynomialRing(self.base_ring(),names,n)
1175
except Exception:
1176
raise ValueError, 'Can only create polynomial rings over commutative rings.'
1177
V = vector(R.gens())
1178
P = (V*M).dot_product(V)
1179
return P
1180
1181
1182
1183
1184
def is_primitive(self):
1185
"""
1186
Determines if the given integer-valued form is primitive
1187
(i.e. not an integer (>1) multiple of another integer-valued
1188
quadratic form).
1189
1190
EXAMPLES::
1191
1192
sage: Q = QuadraticForm(ZZ, 2, [2,3,4])
1193
sage: Q.is_primitive()
1194
True
1195
sage: Q = QuadraticForm(ZZ, 2, [2,4,8])
1196
sage: Q.is_primitive()
1197
False
1198
1199
"""
1200
return (self.gcd() == 1)
1201
1202
1203
def primitive(self):
1204
"""
1205
Returns a primitive version of an integer-valued quadratic form, defined over `ZZ`.
1206
1207
EXAMPLES::
1208
1209
sage: Q = QuadraticForm(ZZ, 2, [2,3,4])
1210
sage: Q.primitive()
1211
Quadratic form in 2 variables over Integer Ring with coefficients:
1212
[ 2 3 ]
1213
[ * 4 ]
1214
sage: Q = QuadraticForm(ZZ, 2, [2,4,8])
1215
sage: Q.primitive()
1216
Quadratic form in 2 variables over Integer Ring with coefficients:
1217
[ 1 2 ]
1218
[ * 4 ]
1219
1220
"""
1221
if self.base_ring() != ZZ:
1222
raise TypeError, "Oops! The given quadratic form must be defined over ZZ."
1223
1224
g = self.gcd()
1225
return QuadraticForm(self.base_ring(), self.dim(), [ZZ(x/g) for x in self.coefficients()])
1226
1227
1228
1229
def adjoint_primitive(self):
1230
"""
1231
Returns the primitive adjoint of the quadratic form, which is
1232
the smallest discriminant integer-valued quadratic form whose
1233
matrix is a scalar multiple of the inverse of the matrix of
1234
the given quadratic form.
1235
1236
EXAMPLES::
1237
1238
sage: Q = QuadraticForm(ZZ, 2, [1,2,3])
1239
sage: Q.adjoint_primitive()
1240
Quadratic form in 2 variables over Integer Ring with coefficients:
1241
[ 3 -2 ]
1242
[ * 1 ]
1243
1244
"""
1245
return QuadraticForm(self.Hessian_matrix().adjoint()).primitive()
1246
1247
1248
1249
def dim(self):
1250
"""
1251
Gives the number of variables of the quadratic form.
1252
1253
EXAMPLES::
1254
1255
sage: Q = QuadraticForm(ZZ, 2, [1,2,3])
1256
sage: Q.dim()
1257
2
1258
1259
"""
1260
return self.__n
1261
1262
1263
def base_ring(self):
1264
"""
1265
Gives the ring over which the quadratic form is defined.
1266
1267
EXAMPLES::
1268
1269
sage: Q = QuadraticForm(ZZ, 2, [1,2,3])
1270
sage: Q.base_ring()
1271
Integer Ring
1272
1273
"""
1274
return self.__base_ring
1275
1276
1277
def coefficients(self):
1278
"""
1279
Gives the matrix of upper triangular coefficients,
1280
by reading across the rows from the main diagonal.
1281
1282
EXAMPLES::
1283
1284
sage: Q = QuadraticForm(ZZ, 2, [1,2,3])
1285
sage: Q.coefficients()
1286
[1, 2, 3]
1287
1288
"""
1289
return self.__coeffs
1290
1291
1292
def det(self):
1293
"""
1294
Gives the determinant of the Gram matrix of 2*Q, or
1295
equivalently the determinant of the Hessian matrix of Q.
1296
1297
(Note: This is always defined over the same ring as the
1298
quadratic form.)
1299
1300
EXAMPLES::
1301
1302
sage: Q = QuadraticForm(ZZ, 2, [1,2,3])
1303
sage: Q.det()
1304
8
1305
1306
"""
1307
try:
1308
return self.__det
1309
except AttributeError:
1310
## Compute the determinant
1311
if self.dim() == 0:
1312
new_det = self.base_ring()(1)
1313
else:
1314
new_det = self.matrix().det()
1315
1316
## Cache and return the determinant
1317
self.__det = new_det
1318
return new_det
1319
1320
1321
def Gram_det(self):
1322
"""
1323
Gives the determinant of the Gram matrix of Q.
1324
1325
(Note: This is defined over the fraction field of the ring of
1326
the quadratic form, but is often not defined over the same
1327
ring as the quadratic form.)
1328
1329
EXAMPLES::
1330
1331
sage: Q = QuadraticForm(ZZ, 2, [1,2,3])
1332
sage: Q.Gram_det()
1333
2
1334
1335
"""
1336
return self.det() / ZZ(2**self.dim())
1337
1338
1339
def base_change_to(self, R):
1340
"""
1341
Alters the quadratic form to have all coefficients
1342
defined over the new base_ring R. Here R must be
1343
coercible to from the current base ring.
1344
1345
Note: This is preferable to performing an explicit
1346
coercion through the base_ring() method, which does
1347
not affect the individual coefficients. This is
1348
particularly useful for performing fast modular
1349
arithmetic evaluations.
1350
1351
INPUT:
1352
R -- a ring
1353
1354
OUTPUT:
1355
quadratic form
1356
1357
EXAMPLES::
1358
1359
sage: Q = DiagonalQuadraticForm(ZZ,[1,1]); Q
1360
Quadratic form in 2 variables over Integer Ring with coefficients:
1361
[ 1 0 ]
1362
[ * 1 ]
1363
1364
::
1365
1366
sage: Q1 = Q.base_change_to(IntegerModRing(5)); Q1
1367
Quadratic form in 2 variables over Ring of integers modulo 5 with coefficients:
1368
[ 1 0 ]
1369
[ * 1 ]
1370
1371
sage: Q1([35,11])
1372
1
1373
1374
"""
1375
## Check that a canonical coercion is possible
1376
if not is_Ring(R):
1377
raise TypeError, "Oops! R is not a ring. =("
1378
if not R.has_coerce_map_from(self.base_ring()):
1379
raise TypeError, "Oops! There is no canonical coercion from " + str(self.base_ring()) + " to R."
1380
1381
## Return the coerced form
1382
return QuadraticForm(R, self.dim(), [R(x) for x in self.coefficients()])
1383
1384
1385
def level(self):
1386
r"""
1387
Determines the level of the quadratic form over a PID, which is a
1388
generator for the smallest ideal `N` of `R` such that N * (the matrix of
1389
2*Q)^(-1) is in R with diagonal in 2*R.
1390
1391
Over `\ZZ` this returns a non-negative number.
1392
1393
(Caveat: This always returns the unit ideal when working over a field!)
1394
1395
EXAMPLES::
1396
1397
sage: Q = QuadraticForm(ZZ, 2, range(1,4))
1398
sage: Q.level()
1399
8
1400
1401
sage: Q1 = QuadraticForm(QQ, 2, range(1,4))
1402
sage: Q1.level() # random
1403
UserWarning: Warning -- The level of a quadratic form over a field is always 1. Do you really want to do this?!?
1404
1
1405
1406
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
1407
sage: Q.level()
1408
420
1409
1410
"""
1411
## Try to return the cached level
1412
try:
1413
return self.__level
1414
except AttributeError:
1415
1416
## Check that the base ring is a PID
1417
if not is_PrincipalIdealDomain(self.base_ring()):
1418
raise TypeError, "Oops! The level (as a number) is only defined over a Principal Ideal Domain. Try using level_ideal()."
1419
1420
1421
## Warn the user if the form is defined over a field!
1422
if self.base_ring().is_field():
1423
warn("Warning -- The level of a quadratic form over a field is always 1. Do you really want to do this?!?")
1424
#raise RuntimeError, "Warning -- The level of a quadratic form over a field is always 1. Do you really want to do this?!?"
1425
1426
1427
## Check invertibility and find the inverse
1428
try:
1429
mat_inv = self.matrix()**(-1)
1430
except ZeroDivisionError:
1431
raise TypeError, "Oops! The quadratic form is degenerate (i.e. det = 0). =("
1432
1433
## Compute the level
1434
inv_denoms = []
1435
for i in range(self.dim()):
1436
for j in range(i, self.dim()):
1437
if (i == j):
1438
inv_denoms += [denominator(mat_inv[i,j] / 2)]
1439
else:
1440
inv_denoms += [denominator(mat_inv[i,j])]
1441
lvl = LCM(inv_denoms)
1442
lvl = ideal(self.base_ring()(lvl)).gen()
1443
##############################################################
1444
## To do this properly, the level should be the inverse of the
1445
## fractional ideal (over R) generated by the entries whose
1446
## denominators we take above. =)
1447
##############################################################
1448
1449
## Normalize the result over ZZ
1450
if self.base_ring() == IntegerRing():
1451
lvl = abs(lvl)
1452
1453
## Cache and return the level
1454
self.__level = lvl
1455
return lvl
1456
1457
1458
1459
def level_ideal(self):
1460
"""
1461
Determines the level of the quadratic form (over R), which is the
1462
smallest ideal N of R such that N * (the matrix of 2*Q)^(-1) is
1463
in R with diagonal in 2*R.
1464
(Caveat: This always returns the principal ideal when working over a field!)
1465
1466
WARNING: THIS ONLY WORKS OVER A PID RING OF INTEGERS FOR NOW!
1467
(Waiting for Sage fractional ideal support.)
1468
1469
EXAMPLES::
1470
1471
sage: Q = QuadraticForm(ZZ, 2, range(1,4))
1472
sage: Q.level_ideal()
1473
Principal ideal (8) of Integer Ring
1474
1475
::
1476
1477
sage: Q1 = QuadraticForm(QQ, 2, range(1,4))
1478
sage: Q1.level_ideal()
1479
Principal ideal (1) of Rational Field
1480
1481
::
1482
1483
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
1484
sage: Q.level_ideal()
1485
Principal ideal (420) of Integer Ring
1486
1487
"""
1488
##############################################################
1489
## To do this properly, the level should be the inverse of the
1490
## fractional ideal (over R) generated by the entries whose
1491
## denominators we take above. =)
1492
##############################################################
1493
1494
return ideal(self.base_ring()(self.level()))
1495
1496
def bilinear_map(self,v,w):
1497
r"""
1498
Returns the value of the associated bilinear map on two vectors
1499
1500
Given a quadratic form `Q` over some base ring `R` with
1501
characteristic not equal to 2, this gives the image of two
1502
vectors with coefficients in `R` under the associated bilinear
1503
map `B`, given by the relation `2 B(v,w) = Q(v) + Q(w) - Q(v+w)`.
1504
1505
INPUT:
1506
1507
`v, w` -- two vectors
1508
1509
OUTPUT:
1510
1511
an element of the base ring `R`.
1512
1513
EXAMPLES:
1514
1515
First, an example over `\ZZ`::
1516
1517
sage: Q = QuadraticForm(ZZ,3,[1,4,0,1,4,1])
1518
sage: v = vector(ZZ,(1,2,0))
1519
sage: w = vector(ZZ,(0,1,1))
1520
sage: Q.bilinear_map(v,w)
1521
8
1522
1523
This also works over `\QQ`::
1524
1525
sage: Q = QuadraticForm(QQ,2,[1/2,2,1])
1526
sage: v = vector(QQ,(1,1))
1527
sage: w = vector(QQ,(1/2,2))
1528
sage: Q.bilinear_map(v,w)
1529
19/4
1530
1531
The vectors must have the correct length::
1532
1533
sage: Q = DiagonalQuadraticForm(ZZ,[1,7,7])
1534
sage: v = vector((1,2))
1535
sage: w = vector((1,1,1))
1536
sage: Q.bilinear_map(v,w)
1537
Traceback (most recent call last):
1538
...
1539
TypeError: vectors must have length 3
1540
1541
This does not work if the characteristic is 2::
1542
1543
sage: Q = DiagonalQuadraticForm(GF(2),[1,1,1])
1544
sage: v = vector((1,1,1))
1545
sage: w = vector((1,1,1))
1546
sage: Q.bilinear_map(v,w)
1547
Traceback (most recent call last):
1548
...
1549
TypeError: not defined for rings of characteristic 2
1550
"""
1551
if len(v) != self.dim() or len(w) != self.dim():
1552
raise TypeError("vectors must have length " + str(self.dim()))
1553
if self.base_ring().characteristic() == 2:
1554
raise TypeError("not defined for rings of characteristic 2")
1555
return (self(v+w) - self(v) - self(w))/2
1556
1557
1558
## =====================================================================================================
1559
1560
def DiagonalQuadraticForm(R, diag):
1561
"""
1562
Returns a quadratic form over `R` which is a sum of squares.
1563
1564
INPUT:
1565
1566
- `R` -- ring
1567
- ``diag`` -- list/tuple of elements coercible to R
1568
1569
OUTPUT:
1570
1571
quadratic form
1572
1573
EXAMPLES::
1574
1575
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
1576
sage: Q
1577
Quadratic form in 4 variables over Integer Ring with coefficients:
1578
[ 1 0 0 0 ]
1579
[ * 3 0 0 ]
1580
[ * * 5 0 ]
1581
[ * * * 7 ]
1582
"""
1583
Q = QuadraticForm(R, len(diag))
1584
for i in range(len(diag)):
1585
Q[i,i] = diag[i]
1586
return Q
1587
1588