Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/matrix/matrix_cyclo_dense.pyx
8815 views
1
"""
2
Matrices over Cyclotomic Fields
3
4
The underlying matrix for a Matrix_cyclo_dense object is stored as
5
follows: given an n x m matrix over a cyclotomic field of degree d, we
6
store a d x (nm) matrix over QQ, each column of which corresponds to
7
an element of the original matrix. This can be retrieved via the
8
_rational_matrix method. Here is an example illustrating this:
9
10
EXAMPLES::
11
12
sage: F.<zeta> = CyclotomicField(5)
13
sage: M = Matrix(F, 2, 3, [zeta, 3, zeta**4+5, (zeta+1)**4, 0, 1])
14
sage: M
15
[ zeta 3 -zeta^3 - zeta^2 - zeta + 4]
16
[3*zeta^3 + 5*zeta^2 + 3*zeta 0 1]
17
18
sage: M._rational_matrix()
19
[ 0 3 4 0 0 1]
20
[ 1 0 -1 3 0 0]
21
[ 0 0 -1 5 0 0]
22
[ 0 0 -1 3 0 0]
23
24
25
AUTHORS:
26
* William Stein
27
* Craig Citro
28
"""
29
30
######################################################################
31
# Copyright (C) 2008 William Stein
32
# Distributed under the terms of the GNU General Public License (GPL)
33
# The full text of the GPL is available at:
34
# http://www.gnu.org/licenses/
35
######################################################################
36
37
include "sage/ext/interrupt.pxi"
38
# include "sage/ext/stdsage.pxi"
39
include "sage/ext/cdefs.pxi"
40
include "sage/ext/gmp.pxi"
41
include "sage/ext/random.pxi"
42
include "sage/libs/ntl/decl.pxi"
43
44
from sage.structure.element cimport ModuleElement, RingElement, Element, Vector
45
from sage.misc.randstate cimport randstate, current_randstate
46
47
from constructor import matrix
48
from matrix_space import MatrixSpace
49
from matrix cimport Matrix
50
import matrix_dense
51
from matrix_integer_dense import _lift_crt
52
from sage.structure.element cimport Matrix as baseMatrix
53
from misc import matrix_integer_dense_rational_reconstruction
54
55
from sage.rings.rational_field import QQ
56
from sage.rings.integer_ring import ZZ
57
from sage.rings.arith import previous_prime, binomial
58
from sage.rings.all import RealNumber
59
from sage.rings.integer cimport Integer
60
from sage.rings.rational cimport Rational
61
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
62
from sage.rings.number_field.number_field import NumberField_quadratic
63
from sage.rings.number_field.number_field_element cimport NumberFieldElement
64
from sage.rings.number_field.number_field_element_quadratic cimport NumberFieldElement_quadratic
65
66
from sage.structure.proof.proof import get_flag as get_proof_flag
67
from sage.misc.misc import verbose
68
import math
69
70
from sage.matrix.matrix_modn_dense_double import MAX_MODULUS as MAX_MODULUS_modn_dense_double
71
from sage.ext.multi_modular import MAX_MODULUS as MAX_MODULUS_multi_modular
72
MAX_MODULUS = min(MAX_MODULUS_modn_dense_double, MAX_MODULUS_multi_modular)
73
74
# parameters for tuning
75
echelon_primes_increment = 15
76
echelon_verbose_level = 1
77
78
cdef class Matrix_cyclo_dense(matrix_dense.Matrix_dense):
79
########################################################################
80
# LEVEL 1 functionality
81
# x * __cinit__
82
# x * __dealloc__ (not needed)
83
# x * __init__
84
# x * set_unsafe
85
# x * get_unsafe
86
# x * _pickle
87
# x * _unpickle
88
########################################################################
89
90
def __cinit__(self, parent, entries, coerce, copy):
91
"""
92
Create a new dense cyclotomic matrix.
93
94
INPUT:
95
parent -- a matrix space over a cyclotomic field
96
entries -- a list of entries or scalar
97
coerce -- bool; if true entries are coerced to base ring
98
copy -- bool; ignored due to underlying data structure
99
100
EXAMPLES::
101
102
sage: from sage.matrix.matrix_cyclo_dense import Matrix_cyclo_dense
103
sage: A = Matrix_cyclo_dense.__new__(Matrix_cyclo_dense, MatrixSpace(CyclotomicField(3),2), [0,1,2,3], True, True)
104
sage: type(A)
105
<type 'sage.matrix.matrix_cyclo_dense.Matrix_cyclo_dense'>
106
107
Note that the entries of A haven't even been set yet above; that doesn't
108
happen until init is called::
109
110
sage: A[0,0]
111
Traceback (most recent call last):
112
...
113
ValueError: matrix entries not yet initialized
114
"""
115
Matrix.__init__(self, parent)
116
self._degree = self._base_ring.degree()
117
self._n = int(self._base_ring._n())
118
119
# This is not necessary, since we do not (yet) explicitly allocate
120
# any memory.
121
#def __dealloc__(self):
122
# pass
123
124
def __init__(self, parent, entries=None, copy=True, coerce=True):
125
"""
126
Initialize a newly created cyclotomic matrix.
127
128
INPUT:
129
130
- ``parent`` -- a matrix space over a cyclotomic field
131
132
- ``entries`` -- a list of entries or scalar
133
134
- ``coerce`` -- boolean; if true entries are coerced to base
135
ring
136
137
- ``copy`` -- boolean; ignored due to underlying data
138
structure
139
140
EXAMPLES:
141
142
This function is called implicitly when you create new
143
cyclotomic dense matrices::
144
145
sage: W.<a> = CyclotomicField(100)
146
sage: A = matrix(2, 3, [1, 1/a, 1-a,a, -2/3*a, a^19])
147
sage: A
148
[ 1 -a^39 + a^29 - a^19 + a^9 -a + 1]
149
[ a -2/3*a a^19]
150
sage: TestSuite(A).run()
151
152
TESTS::
153
154
sage: matrix(W, 2, 1, a)
155
Traceback (most recent call last):
156
...
157
TypeError: nonzero scalar matrix must be square
158
159
We call __init__ explicitly below::
160
161
sage: from sage.matrix.matrix_cyclo_dense import Matrix_cyclo_dense
162
sage: A = Matrix_cyclo_dense.__new__(Matrix_cyclo_dense, MatrixSpace(CyclotomicField(3),2), [0,1,2,3], True, True)
163
sage: A.__init__(MatrixSpace(CyclotomicField(3),2), [0,1,2,3], True, True)
164
sage: A
165
[0 1]
166
[2 3]
167
168
"""
169
cdef int i
170
z = None
171
if (entries is None) or (entries == 0):
172
pass
173
elif isinstance(entries, list):
174
# This code could be made much faster using Cython, etc.
175
if coerce:
176
K = parent.base_ring()
177
entries = [K(a) for a in entries]
178
entries = sum([a.list() for a in entries], [])
179
else:
180
K = self._base_ring
181
z = K(entries)
182
entries = 0
183
184
self._n = int(self._base_ring._n())
185
self._matrix = Matrix_rational_dense(MatrixSpace(QQ, self._nrows*self._ncols, self._degree),
186
entries, copy=False, coerce=False).transpose()
187
# This could also be made much faster.
188
if z is not None:
189
if self._nrows != self._ncols:
190
raise TypeError, "nonzero scalar matrix must be square"
191
for i in range(self._nrows):
192
self.set_unsafe(i,i,z)
193
194
cdef set_unsafe(self, Py_ssize_t i, Py_ssize_t j, value):
195
"""
196
Set the ij-th entry of self.
197
198
WARNING: This function does no bounds checking whatsoever, as
199
the name suggests. It also assumes certain facts about the
200
internal representation of cyclotomic fields. This is intended
201
for internal use only.
202
203
EXAMPLES::
204
205
sage: K.<z> = CyclotomicField(11) ; M = Matrix(K,2,range(4))
206
sage: M[0,1] = z ; M
207
[0 z]
208
[2 3]
209
210
sage: K.<z> = CyclotomicField(3) ; M = Matrix(K,2,range(4))
211
sage: M[1,1] = z+1 ; M
212
[ 0 1]
213
[ 2 z + 1]
214
215
TESTS:
216
217
Since separate code exists for each quadratic field, we need
218
doctests for each.::
219
220
sage: K.<z> = CyclotomicField(4) ; M = Matrix(K,2,range(4))
221
sage: M[1,1] = z+1 ; M
222
[ 0 1]
223
[ 2 z + 1]
224
sage: K.<z> = CyclotomicField(6) ; M = Matrix(K,2,range(4))
225
sage: M[1,1] = z+1 ; M
226
[ 0 1]
227
[ 2 z + 1]
228
"""
229
# NEW FAST VERSION -- makes assumptions about how the
230
# cyclotomic field is implemented.
231
cdef Py_ssize_t k, c
232
cdef NumberFieldElement v
233
cdef mpz_t numer, denom
234
235
# The i,j entry is the (i * self._ncols + j)'th column.
236
c = i * self._ncols + j
237
238
if PY_TYPE_CHECK_EXACT(value, NumberFieldElement_quadratic):
239
# Must be coded differently, since elements of
240
# quadratic number fields are stored differently.
241
if self._n == 4:
242
mpz_set(mpq_numref(self._matrix._matrix[0][c]),
243
(<NumberFieldElement_quadratic>value).a)
244
mpz_set(mpq_denref(self._matrix._matrix[0][c]),
245
(<NumberFieldElement_quadratic>value).denom)
246
mpq_canonicalize(self._matrix._matrix[0][c])
247
248
mpz_set(mpq_numref(self._matrix._matrix[1][c]),
249
(<NumberFieldElement_quadratic>value).b)
250
mpz_set(mpq_denref(self._matrix._matrix[1][c]),
251
(<NumberFieldElement_quadratic>value).denom)
252
mpq_canonicalize(self._matrix._matrix[1][c])
253
elif self._n == 3:
254
mpz_set(mpq_numref(self._matrix._matrix[0][c]),
255
(<NumberFieldElement_quadratic>value).a)
256
mpz_add(mpq_numref(self._matrix._matrix[0][c]),
257
mpq_numref(self._matrix._matrix[0][c]),
258
(<NumberFieldElement_quadratic>value).b)
259
mpz_set(mpq_denref(self._matrix._matrix[0][c]),
260
(<NumberFieldElement_quadratic>value).denom)
261
mpq_canonicalize(self._matrix._matrix[0][c])
262
263
mpz_set(mpq_numref(self._matrix._matrix[1][c]),
264
(<NumberFieldElement_quadratic>value).b)
265
mpz_mul_si(mpq_numref(self._matrix._matrix[1][c]),
266
mpq_numref(self._matrix._matrix[1][c]), 2)
267
mpz_set(mpq_denref(self._matrix._matrix[1][c]),
268
(<NumberFieldElement_quadratic>value).denom)
269
mpq_canonicalize(self._matrix._matrix[1][c])
270
else: # self._n is 6
271
mpz_set(mpq_numref(self._matrix._matrix[0][c]),
272
(<NumberFieldElement_quadratic>value).a)
273
mpz_sub(mpq_numref(self._matrix._matrix[0][c]),
274
mpq_numref(self._matrix._matrix[0][c]),
275
(<NumberFieldElement_quadratic>value).b)
276
mpz_set(mpq_denref(self._matrix._matrix[0][c]),
277
(<NumberFieldElement_quadratic>value).denom)
278
mpq_canonicalize(self._matrix._matrix[0][c])
279
280
mpz_set(mpq_numref(self._matrix._matrix[1][c]),
281
(<NumberFieldElement_quadratic>value).b)
282
mpz_mul_si(mpq_numref(self._matrix._matrix[1][c]),
283
mpq_numref(self._matrix._matrix[1][c]), 2)
284
mpz_set(mpq_denref(self._matrix._matrix[1][c]),
285
(<NumberFieldElement_quadratic>value).denom)
286
mpq_canonicalize(self._matrix._matrix[1][c])
287
return
288
289
v = value
290
291
mpz_init(numer)
292
mpz_init(denom)
293
294
v._ntl_denom_as_mpz(&denom)
295
for k from 0 <= k < self._degree:
296
v._ntl_coeff_as_mpz(&numer, k)
297
mpz_set(mpq_numref(self._matrix._matrix[k][c]), numer)
298
mpz_set(mpq_denref(self._matrix._matrix[k][c]), denom)
299
mpq_canonicalize(self._matrix._matrix[k][c])
300
301
mpz_clear(numer)
302
mpz_clear(denom)
303
304
cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j):
305
"""
306
Get the ij-th of self.
307
308
WARNING: As the name suggests, expect segfaults if i,j are out
309
of bounds!! This is for internal use only.
310
311
EXAMPLES::
312
313
sage: W.<a> = CyclotomicField(5)
314
sage: A = matrix(2, 3, [9939208341, 1/a, 1-a,a, -2/3*a, a^19])
315
316
This implicitly calls get_unsafe::
317
318
sage: A[0,0]
319
9939208341
320
321
TESTS:
322
323
Since separate code exists for each quadratic field, we need
324
doctests for each.::
325
326
sage: K.<z> = CyclotomicField(3) ; M = Matrix(K,2,range(4))
327
sage: M[1,1] = z+1 ; M[1,1]
328
z + 1
329
sage: (M[1,1] - M[0,1])**3
330
1
331
sage: K.<z> = CyclotomicField(4) ; M = Matrix(K,2,range(4))
332
sage: M[1,1] = z+1 ; M[1,1]
333
z + 1
334
sage: (M[1,1] - M[0,1])**4
335
1
336
sage: K.<z> = CyclotomicField(6) ; M = Matrix(K,2,range(4))
337
sage: M[1,1] = z+1 ; M[1,1]
338
z + 1
339
sage: (M[1,1] - M[0,1])**6
340
1
341
"""
342
cdef Py_ssize_t k, c
343
cdef NumberFieldElement x
344
cdef NumberFieldElement_quadratic xq
345
cdef mpz_t denom, quo, tmp
346
cdef ZZ_c coeff
347
348
if self._matrix is None:
349
raise ValueError, "matrix entries not yet initialized"
350
351
c = i * self._ncols + j
352
mpz_init(tmp)
353
354
if self._degree == 2:
355
xq = self._base_ring(0)
356
if self._n == 4:
357
mpz_mul(xq.a, mpq_numref(self._matrix._matrix[0][c]),
358
mpq_denref(self._matrix._matrix[1][c]))
359
mpz_mul(xq.b, mpq_numref(self._matrix._matrix[1][c]),
360
mpq_denref(self._matrix._matrix[0][c]))
361
mpz_mul(xq.denom, mpq_denref(self._matrix._matrix[0][c]),
362
mpq_denref(self._matrix._matrix[1][c]))
363
else: # n is 3 or 6
364
mpz_mul(xq.a, mpq_numref(self._matrix._matrix[0][c]),
365
mpq_denref(self._matrix._matrix[1][c]))
366
mpz_mul_si(xq.a, xq.a, 2)
367
mpz_mul(tmp, mpq_denref(self._matrix._matrix[0][c]),
368
mpq_numref(self._matrix._matrix[1][c]))
369
if self._n == 3:
370
mpz_sub(xq.a, xq.a, tmp)
371
else: # n == 6
372
mpz_add(xq.a, xq.a, tmp)
373
374
mpz_mul(xq.b, mpq_denref(self._matrix._matrix[0][c]),
375
mpq_numref(self._matrix._matrix[1][c]))
376
377
mpz_mul(xq.denom, mpq_denref(self._matrix._matrix[0][c]),
378
mpq_denref(self._matrix._matrix[1][c]))
379
mpz_mul_si(xq.denom, xq.denom, 2)
380
381
xq._reduce_c_()
382
mpz_clear(tmp)
383
return xq
384
385
x = self._base_ring(0)
386
ZZ_construct(&coeff)
387
mpz_init_set_ui(denom, 1)
388
389
# Get the least common multiple of the denominators in
390
# this column.
391
for k from 0 <= k < self._degree:
392
mpz_lcm(denom, denom, mpq_denref(self._matrix._matrix[k][c]))
393
394
for k from 0 <= k < self._degree:
395
# set each entry of x to a*denom/b where a/b is the
396
# k,c entry of _matrix.
397
mpz_mul(tmp, mpq_numref(self._matrix._matrix[k][c]), denom)
398
mpz_divexact(tmp, tmp, mpq_denref(self._matrix._matrix[k][c]))
399
# Now set k-th entry of x's numerator to tmp
400
mpz_to_ZZ(&coeff, &tmp)
401
ZZX_SetCoeff(x.__numerator, k, coeff)
402
403
# Set the denominator of x to denom.
404
mpz_to_ZZ(&x.__denominator, &denom)
405
mpz_clear(denom)
406
mpz_clear(tmp)
407
ZZ_destruct(&coeff)
408
409
return x
410
411
def _pickle(self):
412
"""
413
Used for pickling matrices. This function returns the
414
underlying data and pickle version.
415
416
OUTPUT:
417
data -- output of pickle
418
version -- int
419
420
EXAMPLES::
421
422
sage: K.<z> = CyclotomicField(3)
423
sage: w = matrix(K, 3, 3, [0, -z, -2, -2*z + 2, 2*z, z, z, 1-z, 2+3*z])
424
sage: w._pickle()
425
(('0 0 -2 2 0 0 0 1 2 0 -1 0 -2 2 1 1 -1 3', 0), 0)
426
"""
427
data = self._matrix._pickle()
428
return data, 0
429
430
def _unpickle(self, data, int version):
431
"""
432
Called when unpickling matrices.
433
434
INPUT:
435
data -- a string
436
version -- int
437
438
This modifies self.
439
440
EXAMPLES::
441
442
sage: K.<z> = CyclotomicField(3)
443
sage: w = matrix(K, 3, 3, [0, -z, -2, -2*z + 2, 2*z, z, z, 1-z, 2+3*z])
444
sage: data, version = w._pickle()
445
sage: k = w.parent()(0)
446
sage: k._unpickle(data, version)
447
sage: k == w
448
True
449
"""
450
#self.check_mutability()
451
if version == 0:
452
self._matrix = Matrix_rational_dense(MatrixSpace(QQ, self._degree, self._nrows*self._ncols), None, False, False)
453
self._matrix._unpickle(*data) # data is (data, matrix_QQ_version)
454
else:
455
raise RuntimeError, "unknown matrix version (=%s)"%version
456
457
########################################################################
458
# LEVEL 2 functionality
459
# x * cdef _add_
460
# x * cdef _sub_
461
# * cdef _mul_
462
# x * cdef _lmul_ -- scalar multiplication
463
# x * cdef _cmp_c_impl
464
# x * __neg__
465
# * __invert__
466
# x * __copy__
467
# * _multiply_classical
468
# * _list -- list of underlying elements (need not be a copy)
469
# * _dict -- sparse dictionary of underlying elements (need not be a copy)
470
########################################################################
471
472
cpdef ModuleElement _add_(self, ModuleElement right):
473
"""
474
Return the sum of two dense cyclotomic matrices.
475
476
INPUT:
477
self, right -- dense cyclotomic matrices with the same
478
parents
479
OUTPUT:
480
a dense cyclotomic matrix
481
482
EXAMPLES::
483
484
sage: W.<z> = CyclotomicField(5)
485
sage: A = matrix(2, 3, [1,z,z^2,z^3,z^4,2/3*z]); B = matrix(2, 3, [-1,2*z,3*z^2,5*z+1,z^4,1/3*z])
486
sage: A + B
487
[ 0 3*z 4*z^2]
488
[ z^3 + 5*z + 1 -2*z^3 - 2*z^2 - 2*z - 2 z]
489
490
Verify directly that the above output is correct::
491
492
sage: (A+B).list() == [A.list()[i]+B.list()[i] for i in range(6)]
493
True
494
"""
495
cdef Matrix_cyclo_dense A = Matrix_cyclo_dense.__new__(Matrix_cyclo_dense, self.parent(), None, None, None)
496
# Fix the redundancy here.
497
A._matrix = self._matrix + (<Matrix_cyclo_dense>right)._matrix
498
return A
499
500
cpdef ModuleElement _sub_(self, ModuleElement right):
501
"""
502
Return the difference of two dense cyclotomic matrices.
503
504
INPUT:
505
self, right -- dense cyclotomic matrices with the same
506
parent
507
OUTPUT:
508
a dense cyclotomic matrix
509
510
EXAMPLES::
511
512
sage: W.<z> = CyclotomicField(5)
513
sage: A = matrix(2, 3, [1,z,z^2,z^3,z^4,2/3*z]); B = matrix(2, 3, [-1,2*z,3*z^2,5*z+1,z^4,1/3*z])
514
sage: A - B
515
[ 2 -z -2*z^2]
516
[z^3 - 5*z - 1 0 1/3*z]
517
518
Verify directly that the above output is correct::
519
520
sage: (A-B).list() == [A.list()[i]-B.list()[i] for i in range(6)]
521
True
522
"""
523
cdef Matrix_cyclo_dense A = Matrix_cyclo_dense.__new__(Matrix_cyclo_dense, self.parent(), None, None, None)
524
A._matrix = self._matrix - (<Matrix_cyclo_dense>right)._matrix
525
return A
526
527
cpdef ModuleElement _lmul_(self, RingElement right):
528
"""
529
Multiply a dense cyclotomic matrix by a scalar.
530
531
INPUT:
532
self -- dense cyclotomic matrix
533
right --- scalar in the base cyclotomic field
534
535
EXAMPLES::
536
537
sage: W.<z> = CyclotomicField(5)
538
sage: A = matrix(2, 3, [1,z,z^2,z^3,z^4,2/3*z])
539
sage: (1 + z/3)*A
540
[ 1/3*z + 1 1/3*z^2 + z 1/3*z^3 + z^2]
541
[2/3*z^3 - 1/3*z^2 - 1/3*z - 1/3 -z^3 - z^2 - z - 2/3 2/9*z^2 + 2/3*z]
542
543
Verify directly that the above output is correct::
544
545
sage: ((1+z/3)*A).list() == [(1+z/3)*x for x in A.list()]
546
True
547
"""
548
if right == 1:
549
return self
550
elif right == 0:
551
return self.parent()(0)
552
553
# Create a new matrix object but with the _matrix attribute not initialized:
554
cdef Matrix_cyclo_dense A = Matrix_cyclo_dense.__new__(Matrix_cyclo_dense,
555
self.parent(), None, None, None)
556
557
if right.polynomial().degree() == 0:
558
# multiplication by a rational number
559
A._matrix = self._matrix._lmul_(right)
560
else:
561
# Multiply by nontrivial element of the cyclotomic number field
562
# We do this by finding the matrix of this element, then left
563
# multiplying by it. We have to tweak the matrix some to
564
# get the right basis, etc.
565
T = right.matrix().transpose()
566
A._matrix = T * self._matrix
567
return A
568
569
cdef baseMatrix _matrix_times_matrix_(self, baseMatrix right):
570
"""
571
Return the product of two cyclotomic dense matrices.
572
573
INPUT:
574
self, right -- cyclotomic dense matrices with compatible
575
parents (same base ring, and compatible
576
dimensions for matrix multiplication).
577
578
OUTPUT:
579
cyclotomic dense matrix
580
581
ALGORITHM:
582
Use a multimodular algorithm that involves multiplying the
583
two matrices modulo split primes.
584
585
EXAMPLES::
586
587
sage: W.<z> = CyclotomicField(5)
588
sage: A = matrix(3, 3, [1,z,z^2,z^3,z^4,2/3*z,-3*z,z,2+z]); B = matrix(3, 3, [-1,2*z,3*z^2,5*z+1,z^4,1/3*z,2-z,3-z,5-z])
589
sage: A*B
590
[ -z^3 + 7*z^2 + z - 1 -z^3 + 3*z^2 + 2*z + 1 -z^3 + 25/3*z^2]
591
[-2*z^3 - 5/3*z^2 + 1/3*z + 4 -z^3 - 8/3*z^2 - 2 -2/3*z^2 + 10/3*z + 10/3]
592
[ 4*z^2 + 4*z + 4 -7*z^2 + z + 7 -9*z^3 - 2/3*z^2 + 3*z + 10]
593
594
Verify that the answer above is consistent with what the
595
generic sparse matrix multiply gives (which is a different
596
implementation).::
597
598
sage: A*B == A.sparse_matrix()*B.sparse_matrix()
599
True
600
601
sage: N1 = Matrix(CyclotomicField(6), 1, [1])
602
sage: cf6 = CyclotomicField(6) ; z6 = cf6.0
603
sage: N2 = Matrix(CyclotomicField(6), 1, 5, [0,1,z6,-z6,-z6+1])
604
sage: N1*N2
605
[ 0 1 zeta6 -zeta6 -zeta6 + 1]
606
sage: N1 = Matrix(CyclotomicField(6), 1, [-1])
607
sage: N1*N2
608
[ 0 -1 -zeta6 zeta6 zeta6 - 1]
609
610
Verify that a degenerate case bug reported at trac 5974 is fixed.
611
612
sage: K.<zeta6>=CyclotomicField(6); matrix(K,1,2) * matrix(K,2,[0, 1, 0, -2*zeta6, 0, 0, 1, -2*zeta6 + 1])
613
[0 0 0 0]
614
615
TESTS:
616
617
This is from trac #8666::
618
619
sage: K.<zeta4> = CyclotomicField(4)
620
sage: m = matrix(K, [125])
621
sage: n = matrix(K, [186])
622
sage: m*n
623
[23250]
624
sage: (-m)*n
625
[-23250]
626
"""
627
A, denom_self = self._matrix._clear_denom()
628
B, denom_right = (<Matrix_cyclo_dense>right)._matrix._clear_denom()
629
630
# conservative but correct estimate: 2 is there to account for the
631
# sign of the entries
632
bound = 1 + 2 * A.height() * B.height() * self._ncols
633
634
n = self._base_ring._n()
635
p = previous_prime(MAX_MODULUS)
636
prod = 1
637
v = []
638
while prod <= bound:
639
while (n >= 2 and p % n != 1) or denom_self % p == 0 or denom_right % p == 0:
640
if p == 2:
641
raise RuntimeError, "we ran out of primes in matrix multiplication."
642
p = previous_prime(p)
643
prod *= p
644
Amodp, _ = self._reductions(p)
645
Bmodp, _ = right._reductions(p)
646
_, S = self._reduction_matrix(p)
647
X = Amodp[0]._matrix_from_rows_of_matrices([Amodp[i] * Bmodp[i] for i in range(len(Amodp))])
648
v.append(S*X)
649
p = previous_prime(p)
650
M = matrix(ZZ, self._base_ring.degree(), self._nrows*right.ncols())
651
_lift_crt(M, v)
652
d = denom_self * denom_right
653
if d == 1:
654
M = M.change_ring(QQ)
655
else:
656
M = (1/d)*M
657
cdef Matrix_cyclo_dense C = Matrix_cyclo_dense.__new__(Matrix_cyclo_dense,
658
MatrixSpace(self._base_ring, self._nrows, right.ncols()),
659
None, None, None)
660
C._matrix = M
661
return C
662
663
def __richcmp__(Matrix self, right, int op):
664
"""
665
Compare a matrix with something else. This immediately calls
666
a base class _richcmp.
667
668
EXAMPLES::
669
670
sage: W.<z> = CyclotomicField(5)
671
sage: A = matrix(W, 2, 2, [1,z,-z,1+z/2])
672
673
These implicitly call richcmp::
674
675
sage: A == 5
676
False
677
sage: A < 100
678
True
679
"""
680
return self._richcmp(right, op)
681
682
cdef long _hash(self) except -1:
683
"""
684
Return hash of this matrix.
685
686
EXAMPLES:
687
688
This is called implicitly by the hash function.::
689
690
sage: W.<z> = CyclotomicField(5)
691
sage: A = matrix(W, 2, 2, [1,z,-z,1+z/2])
692
693
The matrix must be immutable.::
694
695
sage: hash(A)
696
Traceback (most recent call last):
697
...
698
TypeError: mutable matrices are unhashable
699
sage: A.set_immutable()
700
701
Yes, this works::
702
703
sage: hash(A)
704
-25
705
"""
706
return self._matrix._hash()
707
708
def __hash__(self):
709
"""
710
Return hash of an immutable matrix. Raise a TypeError if input
711
matrix is mutable.
712
713
EXAMPLES::
714
715
sage: W.<z> = CyclotomicField(5)
716
sage: A = matrix(W, 2, 2, [1,2/3*z+z^2,-z,1+z/2])
717
sage: hash(A)
718
Traceback (most recent call last):
719
...
720
TypeError: mutable matrices are unhashable
721
sage: A.set_immutable()
722
sage: A.__hash__()
723
-18
724
"""
725
if self._is_immutable:
726
return self._hash()
727
else:
728
raise TypeError, "mutable matrices are unhashable"
729
730
cdef int _cmp_c_impl(self, Element right) except -2:
731
"""
732
Implements comparison of two cyclotomic matrices with
733
identical parents.
734
735
INPUT:
736
self, right -- matrices with same parent
737
OUTPUT:
738
int; either -1, 0, or 1
739
740
EXAMPLES:
741
742
This function is called implicitly when comparisons with matrices
743
are done or the cmp function is used.::
744
745
sage: W.<z> = CyclotomicField(5)
746
sage: A = matrix(W, 2, 2, [1,2/3*z+z^2,-z,1+z/2])
747
sage: cmp(A,A)
748
0
749
sage: cmp(A,2*A)
750
-1
751
sage: cmp(2*A,A)
752
1
753
"""
754
return self._matrix._cmp_c_impl((<Matrix_cyclo_dense>right)._matrix)
755
756
def __copy__(self):
757
"""
758
Make a copy of this matrix.
759
760
EXAMPLES:
761
We create a cyclotomic matrix.::
762
763
sage: W.<z> = CyclotomicField(5)
764
sage: A = matrix(W, 2, 2, [1,2/3*z+z^2,-z,1+z/2])
765
766
We make a copy of A.::
767
sage: C = A.__copy__()
768
769
We make another reference to A.::
770
771
sage: B = A
772
773
Changing this reference changes A itself::
774
775
sage: B[0,0] = 10
776
sage: A[0,0]
777
10
778
779
Changing the copy does not change A.::
780
781
sage: C[0,0] = 20
782
sage: C[0,0]
783
20
784
sage: A[0,0]
785
10
786
"""
787
cdef Matrix_cyclo_dense A = Matrix_cyclo_dense.__new__(Matrix_cyclo_dense, self.parent(), None, None, None)
788
A._matrix = self._matrix.__copy__()
789
return A
790
791
def __neg__(self):
792
"""
793
Return the negative of this matrix.
794
795
OUTPUT:
796
matrix
797
798
EXAMPLES::
799
800
sage: W.<z> = CyclotomicField(5)
801
sage: A = matrix(W, 2, 2, [1,2/3*z+z^2,-z,1+z/2])
802
sage: -A
803
[ -1 -z^2 - 2/3*z]
804
[ z -1/2*z - 1]
805
sage: A.__neg__()
806
[ -1 -z^2 - 2/3*z]
807
[ z -1/2*z - 1]
808
"""
809
cdef Matrix_cyclo_dense A = Matrix_cyclo_dense.__new__(Matrix_cyclo_dense, self.parent(), None, None, None)
810
A._matrix = self._matrix.__neg__()
811
return A
812
813
814
########################################################################
815
# LEVEL 3 functionality (Optional)
816
# * __deepcopy__
817
# * __invert__
818
# * Matrix windows -- only if you need strassen for that base
819
# * Other functions (list them here):
820
# * Specialized echelon form
821
########################################################################
822
def set_immutable(self):
823
"""
824
Change this matrix so that it is immutable.
825
826
EXAMPLES::
827
828
sage: W.<z> = CyclotomicField(5)
829
sage: A = matrix(W, 2, 2, [1,2/3*z+z^2,-z,1+z/2])
830
sage: A[0,0] = 10
831
sage: A.set_immutable()
832
sage: A[0,0] = 20
833
Traceback (most recent call last):
834
...
835
ValueError: matrix is immutable; please change a copy instead (i.e., use copy(M) to change a copy of M).
836
837
Note that there is no function to set a matrix to be mutable
838
again, since such a function would violate the whole point.
839
Instead make a copy, which is always mutable by default.::
840
841
sage: A.set_mutable()
842
Traceback (most recent call last):
843
...
844
AttributeError: 'sage.matrix.matrix_cyclo_dense.Matrix_cyclo_dense' object has no attribute 'set_mutable'
845
sage: B = A.__copy__()
846
sage: B[0,0] = 20
847
sage: B[0,0]
848
20
849
"""
850
self._matrix.set_immutable()
851
matrix_dense.Matrix_dense.set_immutable(self)
852
853
def _rational_matrix(self):
854
"""
855
Return the underlying rational matrix corresponding to self.
856
857
EXAMPLES::
858
859
sage: Matrix(CyclotomicField(7),4,4,range(16))._rational_matrix()
860
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
861
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
862
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
863
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
864
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
865
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
866
sage: Matrix(CyclotomicField(7),4,4,[CyclotomicField(7).gen(0)**i for i in range(16)])._rational_matrix()
867
[ 1 0 0 0 0 0 -1 1 0 0 0 0 0 -1 1 0]
868
[ 0 1 0 0 0 0 -1 0 1 0 0 0 0 -1 0 1]
869
[ 0 0 1 0 0 0 -1 0 0 1 0 0 0 -1 0 0]
870
[ 0 0 0 1 0 0 -1 0 0 0 1 0 0 -1 0 0]
871
[ 0 0 0 0 1 0 -1 0 0 0 0 1 0 -1 0 0]
872
[ 0 0 0 0 0 1 -1 0 0 0 0 0 1 -1 0 0]
873
"""
874
return self._matrix
875
876
def denominator(self):
877
"""
878
Return the denominator of the entries of this matrix.
879
880
OUTPUT:
881
integer -- the smallest integer d so that d * self has
882
entries in the ring of integers
883
884
EXAMPLES::
885
886
sage: W.<z> = CyclotomicField(5)
887
sage: A = matrix(W, 2, 2, [-2/7,2/3*z+z^2,-z,1+z/19]); A
888
[ -2/7 z^2 + 2/3*z]
889
[ -z 1/19*z + 1]
890
sage: d = A.denominator(); d
891
399
892
"""
893
return self._matrix.denominator()
894
895
def coefficient_bound(self):
896
r"""
897
Return an upper bound for the (complex) absolute values of all
898
entries of self with respect to all embeddings.
899
900
Use \code{self.height()} for a sharper bound.
901
902
This is computed using just the Cauchy-Schwarz inequality, i.e.,
903
we use the fact that
904
$$ \left| \sum_i a_i\zeta^i \right| \leq \sum_i |a_i|, $$
905
as $|\zeta| = 1$.
906
907
EXAMPLES::
908
909
sage: W.<z> = CyclotomicField(5)
910
sage: A = matrix(W, 2, 2, [1+z, 0, 9*z+7, -3 + 4*z]); A
911
[ z + 1 0]
912
[9*z + 7 4*z - 3]
913
sage: A.coefficient_bound()
914
16
915
916
The above bound is just $9 + 7$, coming from the lower left entry.
917
A better bound would be the following::
918
919
sage: (A[1,0]).abs()
920
12.997543663...
921
"""
922
cdef Py_ssize_t i, j
923
924
bound = 0
925
for i from 0 <= i < self._matrix._ncols:
926
927
n = 0
928
for j from 0 <= j < self._matrix._nrows:
929
n += self._matrix[j, i].abs()
930
if bound < n:
931
bound = n
932
933
return bound
934
935
936
def height(self):
937
r"""
938
Return the height of self.
939
940
If we let $a_{ij}$ be the $i,j$ entry of self, then we define
941
the height of self to be
942
$$
943
\max_v \max_{i,j} |a_{ij}|_v,
944
$$
945
where $v$ runs over all complex embeddings of \code{self.base_ring()}.
946
947
EXAMPLES::
948
949
sage: W.<z> = CyclotomicField(5)
950
sage: A = matrix(W, 2, 2, [1+z, 0, 9*z+7, -3 + 4*z]); A
951
[ z + 1 0]
952
[9*z + 7 4*z - 3]
953
sage: A.height()
954
12.997543663...
955
sage: (A[1,0]).abs()
956
12.997543663...
957
"""
958
cdef Py_ssize_t i, j
959
960
emb = self._base_ring.complex_embeddings()
961
962
ht = 0
963
for i from 0 <= i < self._nrows:
964
for j from 0 <= j < self._ncols:
965
t = max([ x.norm().sqrt() for x in [ f(self.get_unsafe(i,j)) for f in emb ] ])
966
if t > ht:
967
ht = t
968
969
return ht
970
971
cdef _randomize_rational_column_unsafe(Matrix_cyclo_dense self,
972
Py_ssize_t col, mpz_t nump1, mpz_t denp1, distribution=None):
973
"""
974
Randomizes all entries in column ``col``. This is a helper method
975
used in the implementation of dense matrices over cyclotomic fields.
976
977
INPUT:
978
979
- ``col`` - Integer, indicating the column; must be coercable to
980
``int``, and this must lie between 0 (inclusive) and
981
``self._ncols`` (exclusive), since no bounds-checking is performed
982
- ``nump1`` - Integer, numerator bound plus one
983
- ``denp1`` - Integer, denominator bound plus one
984
- ``distribution`` - ``None`` or '1/n' (default: ``None``); if '1/n'
985
then ``num_bound``, ``den_bound`` are ignored and numbers are chosen
986
using the GMP function ``mpq_randomize_entry_recip_uniform``
987
- ``nonzero`` - Bool (default: ``False``); whether the new entries
988
are forced to be non-zero
989
990
OUTPUT:
991
992
- None, the matrix is modified in-space
993
994
WARNING:
995
996
This method is quite unsafe. It's called from the method
997
``randomize``, but probably shouldn't be called from another method
998
without first carefully reading the source code!
999
1000
TESTS:
1001
1002
The following doctests are all indirect::
1003
1004
sage: MS = MatrixSpace(CyclotomicField(10), 4, 4)
1005
sage: A = MS.random_element(); A
1006
[ -2*zeta10^3 + 2*zeta10^2 - zeta10 zeta10^3 + 2*zeta10^2 - zeta10 + 1 0 -2*zeta10^3 + zeta10^2 - 2*zeta10 + 2]
1007
[ 0 -zeta10^3 + 2*zeta10^2 - zeta10 -zeta10^3 + 1 zeta10^3 + zeta10]
1008
[ 1/2*zeta10^2 -2*zeta10^2 + 2 -1/2*zeta10^3 + 1/2*zeta10^2 + 2 2*zeta10^3 - zeta10^2 - 2]
1009
[ 1 zeta10^2 + 2 2*zeta10^2 2*zeta10 - 2]
1010
sage: B = MS.random_element(density=0.5)
1011
sage: B._rational_matrix()
1012
[ 0 0 0 0 1 0 0 2 0 2 0 0 0 0 0 0]
1013
[ 0 0 0 0 0 0 0 0 -1 -2 0 0 0 0 0 2]
1014
[ 0 -1 0 0 -1 0 0 0 0 0 0 0 0 0 -2 -1]
1015
[ 0 0 0 0 0 0 0 2 -1/2 1/2 0 0 0 0 -1 0]
1016
sage: C = MS.random_element(density=0.5, num_bound=20, den_bound=20)
1017
sage: C._rational_matrix()
1018
[ 0 0 8/11 -10/3 -11/7 8 1 -3 0 0 1 0 0 0 0 0]
1019
[ 0 0 -11/17 -3/13 -5/6 17/3 -19/17 -4/5 0 0 9 0 0 0 0 0]
1020
[ 0 0 -11 -3/2 -5/12 8/11 0 -3/19 0 0 -5/6 0 0 0 0 0]
1021
[ 0 0 0 5/8 -5/11 -5/4 6/11 2/3 0 0 -16/11 0 0 0 0 0]
1022
"""
1023
cdef Py_ssize_t i
1024
cdef Matrix_rational_dense mat = self._matrix
1025
1026
sig_on()
1027
if distribution == "1/n":
1028
for i from 0 <= i < mat._nrows:
1029
mpq_randomize_entry_recip_uniform(mat._matrix[i][col])
1030
elif mpz_cmp_si(denp1, 2): # denom is > 1
1031
for i from 0 <= i < mat._nrows:
1032
mpq_randomize_entry(mat._matrix[i][col], nump1, denp1)
1033
else:
1034
for i from 0 <= i < mat._nrows:
1035
mpq_randomize_entry_as_int(mat._matrix[i][col], nump1)
1036
sig_off()
1037
1038
def randomize(self, density=1, num_bound=2, den_bound=2, \
1039
distribution=None, nonzero=False, *args, **kwds):
1040
r"""
1041
Randomize the entries of ``self``.
1042
1043
Choose rational numbers according to ``distribution``, whose
1044
numerators are bounded by ``num_bound`` and whose denominators are
1045
bounded by ``den_bound``.
1046
1047
EXAMPLES::
1048
1049
sage: A = Matrix(CyclotomicField(5),2,2,range(4)) ; A
1050
[0 1]
1051
[2 3]
1052
sage: A.randomize()
1053
sage: A # random output
1054
[ 1/2*zeta5^2 + zeta5 1/2]
1055
[ -zeta5^2 + 2*zeta5 -2*zeta5^3 + 2*zeta5^2 + 2]
1056
"""
1057
# Problem 1:
1058
# We cannot simply call the ``randomize`` code in ``matrix2.pyx`` on
1059
# the underlying matrix, since this is a d x (mn) matrix, where d is
1060
# the degree of the field extension, which leads to an overly dense
1061
# matrix.
1062
#
1063
# Problem 2:
1064
# We cannot simply copy the code from ``matrix2.pyx``, since the
1065
# ``random_element`` method for cyclotomic fields does not support
1066
# the arguments ``num_bound`` and ``den_bound``, which are support by
1067
# the rational field.
1068
#
1069
# Proposed solution:
1070
# Randomly select a proportion of ``density`` of the elements in the
1071
# matrix over the cyclotomic field, that is, this many columns in the
1072
# underlying rational matrix. Then, for each element in that column,
1073
# randomize it to a rational number, applying the arguments
1074
# ``num_bound`` and ``den_bound``.
1075
1076
density = float(density)
1077
if density <= 0:
1078
return
1079
if density > 1:
1080
density = 1
1081
1082
self.check_mutability()
1083
self.clear_cache()
1084
1085
cdef Py_ssize_t col, i, k, num
1086
cdef randstate rstate = current_randstate()
1087
cdef Integer B, C
1088
cdef bint col_is_zero
1089
1090
B = Integer(num_bound+1)
1091
C = Integer(den_bound+1)
1092
1093
if nonzero:
1094
if density >= 1:
1095
for col from 0 <= col < self._matrix._ncols:
1096
col_is_zero = True
1097
while col_is_zero:
1098
self._randomize_rational_column_unsafe(col, B.value, \
1099
C.value, distribution)
1100
# Check whether the new column is non-zero
1101
for i from 0 <= i < self._degree:
1102
if mpq_sgn(self._matrix._matrix[i][col]) != 0:
1103
col_is_zero = False
1104
break
1105
else:
1106
num = int(self._nrows * self._ncols * density)
1107
for k from 0 <= k < num:
1108
col = rstate.c_random() % self._matrix._ncols
1109
col_is_zero = True
1110
while col_is_zero:
1111
self._randomize_rational_column_unsafe(col, B.value, \
1112
C.value, distribution)
1113
# Check whether the new column is non-zero
1114
for i from 0 <= i < self._degree:
1115
if mpq_sgn(self._matrix._matrix[i][col]) != 0:
1116
col_is_zero = False
1117
break
1118
else:
1119
if density >= 1:
1120
for col from 0 <= col < self._matrix._ncols:
1121
self._randomize_rational_column_unsafe(col, B.value, \
1122
C.value, distribution)
1123
else:
1124
num = int(self._nrows * self._ncols * density)
1125
for k from 0 <= k < num:
1126
col = rstate.c_random() % self._matrix._ncols
1127
self._randomize_rational_column_unsafe(col, B.value, \
1128
C.value, distribution)
1129
1130
def _charpoly_bound(self):
1131
"""
1132
Determine a bound for the coefficients of the characteristic
1133
polynomial of self. We use the bound in Lemma 2.2 of:
1134
1135
Dumas, J-G. "Bounds on the coefficients of characteristic
1136
and minimal polynomials." J. Inequal. Pure Appl. Math. 8
1137
(2007), no. 2.
1138
1139
This bound only applies for self._nrows >= 4, so in all
1140
smaller cases, we just use a naive bound.
1141
1142
EXAMPLES::
1143
1144
sage: A = Matrix(CyclotomicField(7),3,3,range(9))
1145
sage: A._charpoly_bound()
1146
2048
1147
sage: A.charpoly()
1148
x^3 - 12*x^2 - 18*x
1149
1150
An example from the above paper, where the bound is sharp::
1151
1152
sage: B = Matrix(CyclotomicField(7), 5,5, [1,1,1,1,1,1,1,-1,-1,-1,1,-1,1,-1,-1,1,-1,-1,1,-1,1,-1,-1,-1,1])
1153
sage: B._charpoly_bound()
1154
80
1155
sage: B.charpoly()
1156
x^5 - 5*x^4 + 40*x^2 - 80*x + 48
1157
"""
1158
cdef Py_ssize_t i
1159
1160
# should we even bother with this check, or just say in
1161
# the docstring that we assume it's square?
1162
if self._nrows != self._ncols:
1163
raise ArithmeticError, "self must be a square matrix"
1164
1165
if self.is_zero():
1166
return 1
1167
1168
B = self.coefficient_bound()
1169
1170
# TODO: should charpoly just hardcode the return value for
1171
# self.nrows() < 4?
1172
1173
# this bound is only valid for n >= 4, use naive bounds
1174
# in other cases.
1175
if self._nrows <= 3:
1176
return max(1, 3*B, 6*B**2, 4*B**3)
1177
1178
# This is an approximation to 2^(5/6*log_2(5) - 2/3*log_2(6))
1179
alpha = RealNumber('1.15799718800731')
1180
# This is 2*e^(1-(2(7\gamma-4))/(13(3-2\gamma))), where \gamma
1181
# is Euler's constant.
1182
delta = RealNumber('5.418236')
1183
# This is an approximation to 1/2. :)
1184
half = RealNumber('0.5')
1185
1186
D = (((1+2*delta*self._nrows*(B**2)).sqrt()-1)/(delta*B**2)).ceil()
1187
1188
# TODO: we don't check anything about overflows anywhere here;
1189
# should we?
1190
1191
# i = 0 case
1192
M = ((self._nrows * B**2)**(self._nrows * half)).ceil()
1193
1194
for i from 1 <= i < D:
1195
val = binomial(self._nrows, i) * \
1196
(((self._nrows-i)*B**2)**((self._nrows-i)*half)).ceil()
1197
if val > M:
1198
M = val
1199
1200
return M
1201
1202
1203
def charpoly(self, var='x', algorithm="multimodular", proof=None):
1204
r"""
1205
Return the characteristic polynomial of self, as a polynomial
1206
over the base ring.
1207
1208
INPUT:
1209
algorithm -- 'multimodular' (default): reduce modulo
1210
primes, compute charpoly mod
1211
p, and lift (very fast)
1212
'pari': use pari (quite slow; comparable to
1213
Magma v2.14 though)
1214
'hessenberg': put matrix in Hessenberg form
1215
(double dog slow)
1216
proof -- bool (default: None) proof flag determined by
1217
global linalg proof.
1218
1219
OUTPUT:
1220
polynomial
1221
1222
EXAMPLES::
1223
1224
sage: K.<z> = CyclotomicField(5)
1225
sage: a = matrix(K, 3, [1,z,1+z^2, z/3,1,2,3,z^2,1-z])
1226
sage: f = a.charpoly(); f
1227
x^3 + (z - 3)*x^2 + (-16/3*z^2 - 2*z)*x - 2/3*z^3 + 16/3*z^2 - 5*z + 5/3
1228
sage: f(a)
1229
[0 0 0]
1230
[0 0 0]
1231
[0 0 0]
1232
sage: a.charpoly(algorithm='pari')
1233
x^3 + (z - 3)*x^2 + (-16/3*z^2 - 2*z)*x - 2/3*z^3 + 16/3*z^2 - 5*z + 5/3
1234
sage: a.charpoly(algorithm='hessenberg')
1235
x^3 + (z - 3)*x^2 + (-16/3*z^2 - 2*z)*x - 2/3*z^3 + 16/3*z^2 - 5*z + 5/3
1236
1237
sage: Matrix(K, 1, [0]).charpoly()
1238
x
1239
sage: Matrix(K, 1, [5]).charpoly(var='y')
1240
y - 5
1241
1242
sage: Matrix(CyclotomicField(13),3).charpoly()
1243
x^3
1244
sage: Matrix(CyclotomicField(13),3).charpoly()[2].parent()
1245
Cyclotomic Field of order 13 and degree 12
1246
1247
TESTS::
1248
1249
sage: Matrix(CyclotomicField(10),0).charpoly()
1250
1
1251
"""
1252
key = 'charpoly-%s-%s'%(algorithm,proof)
1253
f = self.fetch(key)
1254
if f is not None:
1255
return f.change_variable_name(var)
1256
1257
if self.nrows() != self.ncols():
1258
raise TypeError, "self must be square"
1259
1260
if self.is_zero():
1261
R = PolynomialRing(self.base_ring(), name=var)
1262
f = R.gen(0)**self.nrows()
1263
self.cache(key, f)
1264
return f
1265
1266
if self.nrows() == 1:
1267
R = PolynomialRing(self.base_ring(), name=var)
1268
f = R.gen(0) - self[0,0]
1269
self.cache(key, f)
1270
return f
1271
1272
if algorithm == 'multimodular':
1273
f = self._charpoly_multimodular(var, proof=proof)
1274
elif algorithm == 'pari':
1275
f = self._charpoly_over_number_field(var)
1276
elif algorithm == 'hessenberg':
1277
f = self._charpoly_hessenberg(var)
1278
else:
1279
raise ValueError, "unknown algorithm '%s'"%algorithm
1280
self.cache(key, f)
1281
return f
1282
1283
def _charpoly_mod(self, p):
1284
"""
1285
Return the characteristic polynomial of self*denom modulo all
1286
primes over $p$.
1287
1288
This is used internally by the multimodular charpoly algorithm.
1289
1290
INPUT:
1291
p -- a prime that splits completely
1292
1293
OUTPUT:
1294
matrix over GF(p) whose columns correspond to the entries
1295
of all the characteristic polynomials of the reduction of self modulo all
1296
the primes over p.
1297
1298
EXAMPLES::
1299
1300
sage: W.<z> = CyclotomicField(5)
1301
sage: A = matrix(W, 2, 2, [1+z, 0, 9*z+7, -3 + 4*z]); A
1302
[ z + 1 0]
1303
[9*z + 7 4*z - 3]
1304
sage: A._charpoly_mod(11)
1305
[8 2 1]
1306
[1 6 0]
1307
[4 0 0]
1308
[0 0 0]
1309
"""
1310
tm = verbose("Computing characteristic polynomial of cyclotomic matrix modulo %s."%p)
1311
# Reduce self modulo all primes over p
1312
R, denom = self._reductions(p)
1313
# Compute the characteristic polynomial of each reduced matrix
1314
F = [A.charpoly('x') for A in R]
1315
# Put the characteristic polynomials together as the rows of a mod-p matrix
1316
k = R[0].base_ring()
1317
S = matrix(k, len(F), self.nrows()+1, [f.list() for f in F])
1318
# multiply by inverse of reduction matrix to lift
1319
_, L = self._reduction_matrix(p)
1320
X = L * S
1321
# Now the columns of the matrix X define the entries of the
1322
# charpoly modulo p.
1323
verbose("Finished computing charpoly mod %s."%p, tm)
1324
return X
1325
1326
def _charpoly_multimodular(self, var='x', proof=None):
1327
"""
1328
Compute the characteristic polynomial of self using a
1329
multimodular algorithm.
1330
1331
INPUT:
1332
proof -- bool (default: global flag); if False, compute
1333
using primes $p_i$ until the lift modulo all
1334
primes up to $p_i$ is the same as the lift modulo
1335
all primes up to $p_{i+3}$ or the bound is
1336
reached.
1337
1338
EXAMPLES::
1339
1340
sage: K.<z> = CyclotomicField(3)
1341
sage: A = matrix(3, [-z, 2*z + 1, 1/2*z + 2, 1, -1/2, 2*z + 2, -2*z - 2, -2*z - 2, 2*z - 1])
1342
sage: A._charpoly_multimodular()
1343
x^3 + (-z + 3/2)*x^2 + (17/2*z + 9/2)*x - 9/2*z - 23/2
1344
sage: A._charpoly_multimodular('T')
1345
T^3 + (-z + 3/2)*T^2 + (17/2*z + 9/2)*T - 9/2*z - 23/2
1346
sage: A._charpoly_multimodular('T', proof=False)
1347
T^3 + (-z + 3/2)*T^2 + (17/2*z + 9/2)*T - 9/2*z - 23/2
1348
1349
TESTS:
1350
1351
We test a degenerate case::
1352
1353
sage: A = matrix(CyclotomicField(1),2,[1,2,3,4]); A.charpoly()
1354
x^2 - 5*x - 2
1355
"""
1356
cdef Matrix_cyclo_dense A
1357
A = Matrix_cyclo_dense.__new__(Matrix_cyclo_dense, self.parent(),
1358
None, None, None)
1359
1360
proof = get_proof_flag(proof, "linear_algebra")
1361
1362
n = self._base_ring._n()
1363
p = previous_prime(MAX_MODULUS)
1364
prod = 1
1365
v = []
1366
#A, denom = self._matrix._clear_denom()
1367
# TODO: this might be stupidly slow
1368
denom = self._matrix.denominator()
1369
A._matrix = <Matrix_rational_dense>(denom*self._matrix)
1370
bound = A._charpoly_bound()
1371
L_last = 0
1372
while prod <= bound:
1373
while (n >= 2 and p % n != 1) or denom % p == 0:
1374
if p == 2:
1375
raise RuntimeError, "we ran out of primes in multimodular charpoly algorithm."
1376
p = previous_prime(p)
1377
1378
X = A._charpoly_mod(p)
1379
v.append(X)
1380
prod *= p
1381
p = previous_prime(p)
1382
1383
# if we've used enough primes as determined by bound, or
1384
# if we've used 3 primes, we check to see if the result is
1385
# the same.
1386
if prod >= bound or (not proof and (len(v) % 3 == 0)):
1387
M = matrix(ZZ, self._base_ring.degree(), self._nrows+1)
1388
L = _lift_crt(M, v)
1389
if not proof and L == L_last:
1390
break
1391
L_last = L
1392
1393
# Now each column of L encodes a coefficient of the output polynomial,
1394
# with column 0 being the constant coefficient.
1395
K = self.base_ring()
1396
R = K[var]
1397
coeffs = [K(w.list()) for w in L.columns()]
1398
f = R(coeffs)
1399
1400
# Rescale to account for denominator, if necessary
1401
if denom != 1:
1402
x = R.gen()
1403
f = f(x * denom) * (1 / (denom**f.degree()))
1404
1405
return f
1406
1407
1408
def _reductions(self, p):
1409
"""
1410
Compute the reductions modulo all primes over p of denom*self,
1411
where denom is the denominator of self.
1412
1413
INPUT:
1414
p -- a prime that splits completely in the base cyclotomic field.
1415
1416
OUTPUT:
1417
list -- of r distinct matrices modulo p, where r is
1418
the degree of the cyclotomic base field.
1419
denom -- an integer
1420
1421
EXAMPLES::
1422
1423
sage: K.<z> = CyclotomicField(3)
1424
sage: w = matrix(K, 2, 3, [0, -z/5, -2/3, -2*z + 2, 2*z, z])
1425
sage: R, d = w._reductions(7)
1426
sage: R[0]
1427
[0 2 4]
1428
[1 1 4]
1429
sage: R[1]
1430
[0 1 4]
1431
[5 4 2]
1432
sage: d
1433
15
1434
"""
1435
# Get matrix that defines the linear reduction maps modulo
1436
# each prime of the base ring over p.
1437
T, _ = self._reduction_matrix(p)
1438
# Clear denominator and get matrix over the integers suitable
1439
# for reduction.
1440
A, denom = self._matrix._clear_denom()
1441
# Actually reduce the matrix over the integers modulo the
1442
# prime p.
1443
B = A._mod_int(p)
1444
# Now multiply, which computes from B all the reductions of
1445
# self*denom modulo each of the primes over p.
1446
R = T * B
1447
# Finally compute the actual reductions by extracting them
1448
# from R (note that the rows of R define the reductions).
1449
ans = R._matrices_from_rows(self._nrows, self._ncols)
1450
return ans, denom
1451
1452
def _reduction_matrix(self, p):
1453
"""
1454
INPUT:
1455
p -- a prime that splits completely in the base field.
1456
1457
OUTPUT:
1458
-- Matrix over GF(p) whose action from the left
1459
gives the map from O_K to GF(p) x ... x GF(p)
1460
given by reducing modulo all the primes over p.
1461
-- inverse of this matrix
1462
1463
EXAMPLES::
1464
1465
sage: K.<z> = CyclotomicField(3)
1466
sage: w = matrix(K, 2, 3, [0, -z/5, -2/3, -2*z + 2, 2*z, z])
1467
sage: A, B = w._reduction_matrix(7)
1468
sage: A
1469
[1 4]
1470
[1 2]
1471
sage: B
1472
[6 2]
1473
[4 3]
1474
1475
The reduction matrix is used to calculate the reductions mod primes
1476
above p. ::
1477
1478
sage: K.<z> = CyclotomicField(5)
1479
sage: A = matrix(K, 2, 2, [1, z, z^2+1, 5*z^3]); A
1480
[ 1 z]
1481
[z^2 + 1 5*z^3]
1482
sage: T, S = A._reduction_matrix(11)
1483
sage: T * A._rational_matrix().change_ring(GF(11))
1484
[ 1 9 5 4]
1485
[ 1 5 4 9]
1486
[ 1 4 6 1]
1487
[ 1 3 10 3]
1488
1489
The rows of this product are the (flattened) matrices mod each prime above p::
1490
1491
sage: roots = [r for r, e in K.defining_polynomial().change_ring(GF(11)).roots()]; roots
1492
[9, 5, 4, 3]
1493
sage: [r^2+1 for r in roots]
1494
[5, 4, 6, 10]
1495
sage: [5*r^3 for r in roots]
1496
[4, 9, 1, 3]
1497
1498
The reduction matrix is cached::
1499
sage: w._reduction_matrix(7) is w._reduction_matrix(7)
1500
True
1501
"""
1502
cache = self.fetch('reduction_matrices')
1503
if cache is None:
1504
cache = {}
1505
self.cache('reduction_matrices', cache)
1506
try:
1507
return cache[p]
1508
except KeyError:
1509
pass
1510
K = self.base_ring()
1511
phi = K.defining_polynomial()
1512
from sage.rings.all import GF
1513
from constructor import matrix
1514
F = GF(p)
1515
aa = [a for a, _ in phi.change_ring(F).roots()]
1516
n = K.degree()
1517
if len(aa) != n:
1518
raise ValueError, "the prime p (=%s) must split completely but doesn't"%p
1519
T = matrix(F, n)
1520
for i in range(n):
1521
a = aa[i]
1522
b = 1
1523
for j in range(n):
1524
T[i,j] = b
1525
b *= a
1526
T.set_immutable()
1527
ans = (T, T**(-1))
1528
cache[p] = ans
1529
return ans
1530
1531
def echelon_form(self, algorithm='multimodular', height_guess=None):
1532
"""
1533
Find the echelon form of self, using the specified algorithm.
1534
1535
The result is cached for each algorithm separately.
1536
1537
EXAMPLES::
1538
1539
sage: W.<z> = CyclotomicField(3)
1540
sage: A = matrix(W, 2, 3, [1+z, 2/3, 9*z+7, -3 + 4*z, z, -7*z]); A
1541
[ z + 1 2/3 9*z + 7]
1542
[4*z - 3 z -7*z]
1543
sage: A.echelon_form()
1544
[ 1 0 -192/97*z - 361/97]
1545
[ 0 1 1851/97*z + 1272/97]
1546
sage: A.echelon_form(algorithm='classical')
1547
[ 1 0 -192/97*z - 361/97]
1548
[ 0 1 1851/97*z + 1272/97]
1549
1550
We verify that the result is cached and that the caches are separate::
1551
1552
sage: A.echelon_form() is A.echelon_form()
1553
True
1554
sage: A.echelon_form() is A.echelon_form(algorithm='classical')
1555
False
1556
1557
TESTS::
1558
1559
sage: W.<z> = CyclotomicField(13)
1560
sage: A = Matrix(W, 2,3, [10^30*(1-z)^13, 1, 2, 3, 4, z])
1561
sage: B = Matrix(W, 2,3, [(1-z)^13, 1, 2, 3, 4, z])
1562
sage: A.echelon_form() == A.echelon_form('classical') # long time (4s on sage.math, 2011)
1563
True
1564
sage: B.echelon_form() == B.echelon_form('classical')
1565
True
1566
1567
A degenerate case with the degree 1 cyclotomic field::
1568
1569
sage: A = matrix(CyclotomicField(1),2,3,[1,2,3,4,5,6]);
1570
sage: A.echelon_form()
1571
[ 1 0 -1]
1572
[ 0 1 2]
1573
1574
A case that checks the bug in :trac:`3500`::
1575
1576
sage: cf4 = CyclotomicField(4) ; z4 = cf4.0
1577
sage: A = Matrix(cf4, 1, 2, [-z4, 1])
1578
sage: A.echelon_form()
1579
[ 1 zeta4]
1580
1581
Verify that the matrix on :trac:`10281` works::
1582
1583
sage: K.<rho> = CyclotomicField(106)
1584
sage: coeffs = [(18603/107*rho^51 - 11583/107*rho^50 - 19907/107*rho^49 - 13588/107*rho^48 - 8722/107*rho^47 + 2857/107*rho^46 - 19279/107*rho^45 - 16666/107*rho^44 - 11327/107*rho^43 + 3802/107*rho^42 + 18998/107*rho^41 - 10798/107*rho^40 + 16210/107*rho^39 - 13768/107*rho^38 + 15063/107*rho^37 - 14433/107*rho^36 - 19434/107*rho^35 - 12606/107*rho^34 + 3786/107*rho^33 - 17996/107*rho^32 + 12341/107*rho^31 - 15656/107*rho^30 - 19092/107*rho^29 + 8382/107*rho^28 - 18147/107*rho^27 + 14024/107*rho^26 + 18751/107*rho^25 - 8301/107*rho^24 - 20112/107*rho^23 - 14483/107*rho^22 + 4715/107*rho^21 + 20065/107*rho^20 + 15293/107*rho^19 + 10072/107*rho^18 + 4775/107*rho^17 - 953/107*rho^16 - 19782/107*rho^15 - 16020/107*rho^14 + 5633/107*rho^13 - 17618/107*rho^12 - 18187/107*rho^11 + 7492/107*rho^10 + 19165/107*rho^9 - 9988/107*rho^8 - 20042/107*rho^7 + 10109/107*rho^6 - 17677/107*rho^5 - 17723/107*rho^4 - 12489/107*rho^3 - 6321/107*rho^2 - 4082/107*rho - 1378/107, 1, 4*rho + 1), (0, 1, rho + 4)]
1585
sage: m = matrix(2, coeffs)
1586
sage: a = m.echelon_form(algorithm='classical')
1587
sage: b = m.echelon_form(algorithm='multimodular') # long time (5s on sage.math, 2012)
1588
sage: a == b # long time (depends on previous)
1589
True
1590
"""
1591
key = 'echelon_form-%s'%algorithm
1592
E = self.fetch(key)
1593
if E is not None:
1594
return E
1595
1596
if self._nrows == 0:
1597
E = self.__copy__()
1598
self.cache(key, E)
1599
self.cache('pivots', ())
1600
return E
1601
1602
if algorithm == 'multimodular':
1603
E = self._echelon_form_multimodular(height_guess=height_guess)
1604
elif algorithm == 'classical':
1605
E = (self*self.denominator())._echelon_classical()
1606
else:
1607
raise ValueError, "unknown algorithm '%s'"%algorithm
1608
1609
self.cache(key, E)
1610
return E
1611
1612
def _echelon_form_multimodular(self, num_primes=10, height_guess=None):
1613
"""
1614
Use a multimodular algorithm to find the echelon form of self.
1615
1616
INPUT:
1617
num_primes -- number of primes to work modulo
1618
height_guess -- guess for the height of the echelon form
1619
of self
1620
1621
OUTPUT:
1622
matrix in reduced row echelon form
1623
1624
EXAMPLES::
1625
1626
sage: W.<z> = CyclotomicField(3)
1627
sage: A = matrix(W, 2, 3, [1+z, 2/3, 9*z+7, -3 + 4*z, z, -7*z]); A
1628
[ z + 1 2/3 9*z + 7]
1629
[4*z - 3 z -7*z]
1630
sage: A._echelon_form_multimodular(10)
1631
[ 1 0 -192/97*z - 361/97]
1632
[ 0 1 1851/97*z + 1272/97]
1633
1634
TESTS:
1635
1636
We test a degenerate case::
1637
1638
sage: A = matrix(CyclotomicField(5),0); A
1639
[]
1640
sage: A._echelon_form_multimodular(10)
1641
[]
1642
sage: A.pivots()
1643
()
1644
1645
sage: A = matrix(CyclotomicField(13), 2, 3, [5, 1, 2, 46307, 46307*4, 46307])
1646
sage: A._echelon_form_multimodular()
1647
[ 1 0 7/19]
1648
[ 0 1 3/19]
1649
"""
1650
cdef int i
1651
cdef Matrix_cyclo_dense res
1652
1653
verbose("entering _echelon_form_multimodular", level=echelon_verbose_level)
1654
1655
denom = self._matrix.denominator()
1656
A = denom * self
1657
1658
# This bound is chosen somewhat arbitrarily. Changing it affects the
1659
# runtime, not the correctness of the result.
1660
if height_guess is None:
1661
height_guess = (A.coefficient_bound()+100)*1000000
1662
1663
# This is all setup to keep track of various data
1664
# in the loop below.
1665
p = previous_prime(MAX_MODULUS)
1666
found = 0
1667
prod = 1
1668
n = self._base_ring._n()
1669
height_bound = self._ncols * height_guess * A.coefficient_bound() + 1
1670
mod_p_ech_ls = []
1671
max_pivots = []
1672
is_square = self._nrows == self._ncols
1673
1674
verbose("using height bound %s"%height_bound, level=echelon_verbose_level)
1675
1676
while True:
1677
# Generate primes to use, and find echelon form
1678
# modulo those primes.
1679
while found < num_primes or prod <= height_bound:
1680
if (n == 1) or p%n == 1:
1681
try:
1682
mod_p_ech, piv_ls = A._echelon_form_one_prime(p)
1683
except ValueError:
1684
# This means that we chose a prime which divides
1685
# the denominator of the echelon form of self, so
1686
# just skip it and continue
1687
p = previous_prime(p)
1688
continue
1689
# if we have the identity, just return it, and
1690
# we're done.
1691
if is_square and len(piv_ls) == self._nrows:
1692
self.cache('pivots', tuple(range(self._nrows)))
1693
return self.parent().identity_matrix()
1694
if piv_ls > max_pivots:
1695
mod_p_ech_ls = [mod_p_ech]
1696
max_pivots = piv_ls
1697
# add this to the list of primes
1698
prod = p
1699
found = 1
1700
elif piv_ls == max_pivots:
1701
mod_p_ech_ls.append(mod_p_ech)
1702
# add this to the list of primes
1703
prod *= p
1704
found += 1
1705
else:
1706
# this means that the rank profile mod this
1707
# prime is worse than those that came before,
1708
# so we just loop
1709
p = previous_prime(p)
1710
continue
1711
1712
p = previous_prime(p)
1713
1714
if found > num_primes:
1715
num_primes = found
1716
1717
verbose("computed echelon form mod %s primes"%num_primes,
1718
level=echelon_verbose_level)
1719
verbose("current product of primes used: %s"%prod,
1720
level=echelon_verbose_level)
1721
1722
# Use CRT to lift back to ZZ
1723
mat_over_ZZ = matrix(ZZ, self._base_ring.degree(), self._nrows * self._ncols)
1724
_lift_crt(mat_over_ZZ, mod_p_ech_ls)
1725
# note: saving the CRT intermediate MultiModularBasis does
1726
# not seem to affect the runtime at all
1727
1728
# Attempt to use rational reconstruction to find
1729
# our echelon form
1730
try:
1731
verbose("attempting rational reconstruction ...", level=echelon_verbose_level)
1732
res = Matrix_cyclo_dense.__new__(Matrix_cyclo_dense, self.parent(),
1733
None, None, None)
1734
res._matrix = <Matrix_rational_dense>matrix_integer_dense_rational_reconstruction(mat_over_ZZ, prod)
1735
1736
except ValueError:
1737
# If a ValueError is raised here, it means that the
1738
# rational reconstruction failed. In this case, add
1739
# on a few more primes, and try again.
1740
1741
num_primes += echelon_primes_increment
1742
verbose("rational reconstruction failed, trying with %s primes"%num_primes, level=echelon_verbose_level)
1743
continue
1744
1745
verbose("rational reconstruction succeeded with %s primes!"%num_primes, level=echelon_verbose_level)
1746
1747
if ((res * res.denominator()).coefficient_bound() *
1748
self.coefficient_bound() * self.ncols()) > prod:
1749
# In this case, we don't know the result to sufficient
1750
# "precision" (here precision is just the modulus,
1751
# prod) to guarantee its correctness, so loop.
1752
1753
num_primes += echelon_primes_increment
1754
verbose("height not sufficient to determine echelon form", level=echelon_verbose_level)
1755
continue
1756
1757
verbose("found echelon form with %s primes, whose product is %s"%(num_primes, prod), level=echelon_verbose_level)
1758
self.cache('pivots', tuple(max_pivots))
1759
return res
1760
1761
def _echelon_form_one_prime(self, p):
1762
"""
1763
Find the echelon form of self mod the primes dividing p. Return
1764
the rational matrix representing this lift. If the pivots of the
1765
reductions mod the primes over p are different, then no such lift
1766
exists, and we raise a ValueError. If this happens, then the
1767
denominator of the echelon form of self is divisible by p. (Note
1768
that the converse need not be true.)
1769
1770
INPUT:
1771
p -- a prime that splits completely in the cyclotomic base field.
1772
1773
OUTPUT:
1774
matrix -- Lift via CRT of the echelon forms of self modulo
1775
each of the primes over p.
1776
tuple -- the tuple of pivots for the echelon form of self mod the
1777
primes dividing p
1778
1779
EXAMPLES::
1780
1781
sage: W.<z> = CyclotomicField(3)
1782
sage: A = matrix(W, 2, 3, [1+z, 2/3, 9*z+7, -3 + 4*z, z, -7*z]); A
1783
[ z + 1 2/3 9*z + 7]
1784
[4*z - 3 z -7*z]
1785
sage: A._echelon_form_one_prime(7)
1786
(
1787
[1 0 4 0 1 2]
1788
[0 0 3 0 0 4], (0, 1)
1789
)
1790
sage: Matrix(W,2,3,[2*z+3,0,1,0,1,0])._echelon_form_one_prime(7)
1791
Traceback (most recent call last):
1792
...
1793
ValueError: echelon form mod 7 not defined
1794
1795
"""
1796
cdef Matrix_cyclo_dense res
1797
cdef int i
1798
1799
# Initialize variables
1800
is_square = self._nrows == self._ncols
1801
ls, denom = self._reductions(p)
1802
1803
# Find our first echelon form, and the associated list
1804
# of pivots
1805
ech_ls = [ls[0].echelon_form()]
1806
pivot_ls = ech_ls[0].pivots()
1807
# If we've found the identity matrix, we're all done.
1808
if self._nrows == self._ncols == len(pivot_ls):
1809
return (self.parent().identity_matrix(), range(self._nrows))
1810
1811
# For each reduction of self (i.e. for each prime of
1812
# self.base_ring() over p), compute the echelon form, and
1813
# keep track of all reductions which have the largest
1814
# number of pivots seen so far.
1815
for i from 1 <= i < len(ls):
1816
ech = ls[i].echelon_form()
1817
1818
# This should only occur when p divides the denominator
1819
# of the echelon form of self.
1820
if ech.pivots() != pivot_ls:
1821
raise ValueError, "echelon form mod %s not defined"%p
1822
1823
ech_ls.append(ech)
1824
1825
# Now, just lift back to ZZ and return it.
1826
1827
# TODO: coercion going on here
1828
reduction = matrix(ZZ, len(ech_ls), self._nrows * self._ncols,
1829
[ [y.lift() for y in E.list()] for E in ech_ls])
1830
1831
# TODO: more coercion happening here
1832
_, Finv = self._reduction_matrix(p)
1833
1834
lifted_matrix = Finv * reduction
1835
1836
return (lifted_matrix, pivot_ls)
1837
1838
1839