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