Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/matrix/matrix_integer_dense.pyx
4045 views
1
"""
2
Dense matrices over the integer ring
3
4
AUTHORS:
5
6
- William Stein
7
8
- Robert Bradshaw
9
10
EXAMPLES::
11
12
sage: a = matrix(ZZ, 3,3, range(9)); a
13
[0 1 2]
14
[3 4 5]
15
[6 7 8]
16
sage: a.det()
17
0
18
sage: a[0,0] = 10; a.det()
19
-30
20
sage: a.charpoly()
21
x^3 - 22*x^2 + 102*x + 30
22
sage: b = -3*a
23
sage: a == b
24
False
25
sage: b < a
26
True
27
28
TESTS::
29
30
sage: a = matrix(ZZ,2,range(4), sparse=False)
31
sage: TestSuite(a).run()
32
sage: Matrix(ZZ,0,0).inverse()
33
[]
34
"""
35
36
########## *** IMPORTANT ***
37
# If you're working on this code, we *always* assume that
38
# self._matrix[i] = self._entries[i*self._ncols]
39
# !!!!!!!! Do not break this!
40
# This is assumed in the _rational_kernel_iml
41
42
######################################################################
43
# Copyright (C) 2006,2007 William Stein
44
#
45
# Distributed under the terms of the GNU General Public License (GPL)
46
#
47
# The full text of the GPL is available at:
48
# http://www.gnu.org/licenses/
49
######################################################################
50
51
from sage.modules.vector_integer_dense cimport Vector_integer_dense
52
53
from sage.misc.misc import verbose, get_verbose, cputime
54
55
from sage.rings.arith import previous_prime
56
from sage.structure.element import is_Element
57
from sage.structure.proof.proof import get_flag as get_proof_flag
58
59
from sage.matrix.matrix_rational_dense cimport Matrix_rational_dense
60
61
#########################################################
62
# PARI C library
63
from sage.libs.pari.gen cimport gen, PariInstance
64
from sage.libs.pari.gen import pari
65
66
cdef extern from 'pari/pari.h':
67
GEN zeromat(long m, long n)
68
GEN mathnf0(GEN x,long flag)
69
GEN det0(GEN a,long flag)
70
GEN gcoeff(GEN,long,long)
71
GEN gtomat(GEN x)
72
GEN gel(GEN,long)
73
long glength(GEN x)
74
GEN ginv(GEN x)
75
long rank(GEN x)
76
77
cdef extern from "convert.h":
78
cdef void t_INT_to_ZZ( mpz_t value, long *g )
79
80
#########################################################
81
82
include "../ext/interrupt.pxi"
83
include "../ext/stdsage.pxi"
84
include "../ext/gmp.pxi"
85
include "../ext/random.pxi"
86
87
ctypedef unsigned int uint
88
89
from sage.ext.multi_modular import MultiModularBasis
90
from sage.ext.multi_modular cimport MultiModularBasis
91
92
from sage.rings.integer cimport Integer
93
from sage.rings.rational_field import QQ
94
from sage.rings.real_double import RDF
95
from sage.rings.integer_ring import ZZ, IntegerRing_class
96
from sage.rings.integer_ring cimport IntegerRing_class
97
from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
98
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
99
from sage.structure.element cimport ModuleElement, RingElement, Element, Vector
100
from sage.structure.element import is_Vector
101
from sage.structure.sequence import Sequence
102
103
from matrix_modn_dense_float cimport Matrix_modn_dense_template
104
from matrix_modn_dense_float cimport Matrix_modn_dense_float
105
from matrix_modn_dense_double cimport Matrix_modn_dense_double
106
107
from matrix_mod2_dense import Matrix_mod2_dense
108
from matrix_mod2_dense cimport Matrix_mod2_dense
109
110
from matrix_modn_dense cimport is_Matrix_modn_dense
111
112
113
from matrix2 import decomp_seq
114
115
import sage.modules.free_module
116
import sage.modules.free_module_element
117
118
from matrix cimport Matrix
119
120
cimport sage.structure.element
121
122
import sage.matrix.matrix_space as matrix_space
123
124
################
125
# Used for modular HNF
126
from sage.rings.fast_arith cimport arith_int
127
cdef arith_int ai
128
ai = arith_int()
129
################
130
131
######### linbox interface ##########
132
from sage.libs.linbox.linbox cimport Linbox_integer_dense, Linbox_modn_dense
133
cdef Linbox_integer_dense linbox
134
linbox = Linbox_integer_dense()
135
USE_LINBOX_POLY = True
136
137
138
########## iml -- integer matrix library ###########
139
140
cdef extern from "iml.h":
141
142
enum SOLU_POS:
143
LeftSolu = 101
144
RightSolu = 102
145
146
long nullspaceMP(long n, long m,
147
mpz_t *A, mpz_t * *mp_N_pass)
148
149
void nonsingSolvLlhsMM (SOLU_POS solupos, long n, \
150
long m, mpz_t *mp_A, mpz_t *mp_B, mpz_t *mp_N, \
151
mpz_t mp_D)
152
153
154
155
cdef class Matrix_integer_dense(matrix_dense.Matrix_dense): # dense or sparse
156
r"""
157
Matrix over the integers.
158
159
On a 32-bit machine, they can have at most `2^{32}-1` rows or
160
columns. On a 64-bit machine, matrices can have at most
161
`2^{64}-1` rows or columns.
162
163
EXAMPLES::
164
165
sage: a = MatrixSpace(ZZ,3)(2); a
166
[2 0 0]
167
[0 2 0]
168
[0 0 2]
169
sage: a = matrix(ZZ,1,3, [1,2,-3]); a
170
[ 1 2 -3]
171
sage: a = MatrixSpace(ZZ,2,4)(2); a
172
Traceback (most recent call last):
173
...
174
TypeError: nonzero scalar matrix must be square
175
"""
176
########################################################################
177
# LEVEL 1 functionality
178
# x * __cinit__
179
# x * __dealloc__
180
# x * __init__
181
# x * set_unsafe
182
# x * get_unsafe
183
# x * def _pickle
184
# x * def _unpickle
185
########################################################################
186
187
def __cinit__(self, parent, entries, coerce, copy):
188
"""
189
Create and allocate memory for the matrix. Does not actually
190
initialize any of the memory.
191
192
INPUT:
193
194
195
- ``parent, entries, coerce, copy`` - as for
196
__init__.
197
198
199
EXAMPLES::
200
201
sage: from sage.matrix.matrix_integer_dense import Matrix_integer_dense
202
sage: a = Matrix_integer_dense.__new__(Matrix_integer_dense, Mat(ZZ,3), 0,0,0)
203
sage: type(a)
204
<type 'sage.matrix.matrix_integer_dense.Matrix_integer_dense'>
205
206
.. warning::
207
208
This is for internal use only, or if you really know what
209
you're doing.
210
"""
211
matrix_dense.Matrix_dense.__init__(self, parent)
212
self._nrows = parent.nrows()
213
self._ncols = parent.ncols()
214
self._pivots = None
215
216
# Allocate an array where all the entries of the matrix are stored.
217
sig_on()
218
self._entries = <mpz_t *>sage_malloc(sizeof(mpz_t) * (self._nrows * self._ncols))
219
sig_off()
220
if self._entries == NULL:
221
raise MemoryError("out of memory allocating a matrix")
222
223
# Allocate an array of pointers to the rows, which is useful for
224
# certain algorithms.
225
##################################
226
# *IMPORTANT*: FOR MATRICES OVER ZZ, WE ALWAYS ASSUME THAT
227
# THIS ARRAY IS *not* PERMUTED. This should be OK, since all
228
# algorithms are multi-modular.
229
##################################
230
self._matrix = <mpz_t **> sage_malloc(sizeof(mpz_t*)*self._nrows)
231
if self._matrix == NULL:
232
sage_free(self._entries)
233
self._entries = NULL
234
raise MemoryError("out of memory allocating a matrix")
235
236
# Set each of the pointers in the array self._matrix to point
237
# at the memory for the corresponding row.
238
cdef Py_ssize_t i, k
239
k = 0
240
for i from 0 <= i < self._nrows:
241
self._matrix[i] = self._entries + k
242
k = k + self._ncols
243
244
cdef _init_linbox(self):
245
sig_on()
246
linbox.set(self._matrix, self._nrows, self._ncols)
247
sig_off()
248
249
def __copy__(self):
250
r"""
251
Returns a new copy of this matrix.
252
253
EXAMPLES::
254
255
sage: a = matrix(ZZ,1,3, [1,2,-3]); a
256
[ 1 2 -3]
257
sage: b = a.__copy__(); b
258
[ 1 2 -3]
259
sage: b is a
260
False
261
sage: b == a
262
True
263
"""
264
cdef Matrix_integer_dense A
265
A = Matrix_integer_dense.__new__(Matrix_integer_dense, self._parent,
266
0, 0, 0)
267
cdef Py_ssize_t i
268
sig_on()
269
for i from 0 <= i < self._nrows * self._ncols:
270
mpz_init_set(A._entries[i], self._entries[i])
271
sig_off()
272
A._initialized = True
273
if self._subdivisions is not None:
274
A.subdivide(*self.subdivisions())
275
return A
276
277
def __hash__(self):
278
r"""
279
Returns hash of self.
280
281
self must be immutable.
282
283
EXAMPLES::
284
285
sage: a = Matrix(ZZ,2,[1,2,3,4])
286
sage: hash(a)
287
Traceback (most recent call last):
288
...
289
TypeError: mutable matrices are unhashable
290
291
::
292
293
sage: a.set_immutable()
294
sage: hash(a)
295
8
296
"""
297
return self._hash()
298
299
def __dealloc__(self):
300
"""
301
Frees all the memory allocated for this matrix. EXAMPLE::
302
303
sage: a = Matrix(ZZ,2,[1,2,3,4])
304
sage: del a
305
"""
306
cdef Py_ssize_t i
307
if self._initialized:
308
for i from 0 <= i < (self._nrows * self._ncols):
309
mpz_clear(self._entries[i])
310
sage_free(self._entries)
311
sage_free(self._matrix)
312
313
def __init__(self, parent, entries, copy, coerce):
314
r"""
315
Initialize a dense matrix over the integers.
316
317
INPUT:
318
319
320
- ``parent`` - a matrix space
321
322
- ``entries`` - list - create the matrix with those
323
entries along the rows.
324
325
- ``other`` - a scalar; entries is coerced to an
326
integer and the diagonal entries of this matrix are set to that
327
integer.
328
329
- ``coerce`` - whether need to coerce entries to the
330
integers (program may crash if you get this wrong)
331
332
- ``copy`` - ignored (since integers are immutable)
333
334
335
EXAMPLES:
336
337
The __init__ function is called implicitly in each of the
338
examples below to actually fill in the values of the matrix.
339
340
We create a `2 \times 2` and a `1\times 4` matrix::
341
342
sage: matrix(ZZ,2,2,range(4))
343
[0 1]
344
[2 3]
345
sage: Matrix(ZZ,1,4,range(4))
346
[0 1 2 3]
347
348
If the number of columns isn't given, it is determined from the
349
number of elements in the list.
350
351
::
352
353
sage: matrix(ZZ,2,range(4))
354
[0 1]
355
[2 3]
356
sage: matrix(ZZ,2,range(6))
357
[0 1 2]
358
[3 4 5]
359
360
Another way to make a matrix is to create the space of matrices and
361
coerce lists into it.
362
363
::
364
365
sage: A = Mat(ZZ,2); A
366
Full MatrixSpace of 2 by 2 dense matrices over Integer Ring
367
sage: A(range(4))
368
[0 1]
369
[2 3]
370
371
Actually it is only necessary that the input can be coerced to a
372
list, so the following also works::
373
374
sage: v = reversed(range(4)); type(v)
375
<type 'listreverseiterator'>
376
sage: A(v)
377
[3 2]
378
[1 0]
379
380
Matrices can have many rows or columns (in fact, on a 64-bit
381
machine they could have up to `2^64-1` rows or columns)::
382
383
sage: v = matrix(ZZ,1,10^5, range(10^5))
384
sage: v.parent()
385
Full MatrixSpace of 1 by 100000 dense matrices over Integer Ring
386
"""
387
cdef Py_ssize_t i, j
388
cdef bint is_list
389
cdef Integer x
390
391
if entries is None:
392
x = ZZ(0)
393
is_list = 0
394
elif isinstance(entries, (int,long)) or is_Element(entries):
395
try:
396
x = ZZ(entries)
397
except TypeError:
398
self._initialized = False
399
raise TypeError("unable to coerce entry to an integer")
400
is_list = 0
401
else:
402
entries = list(entries)
403
is_list = 1
404
405
if is_list:
406
407
# Create the matrix whose entries are in the given entry list.
408
if len(entries) != self._nrows * self._ncols:
409
sage_free(self._entries)
410
sage_free(self._matrix)
411
self._entries = NULL
412
raise TypeError("entries has the wrong length")
413
if coerce:
414
for i from 0 <= i < self._nrows * self._ncols:
415
x = ZZ(entries[i])
416
# todo -- see integer.pyx and the TODO there; perhaps this could be
417
# sped up by creating a mpz_init_set_sage function.
418
mpz_init_set(self._entries[i], x.value)
419
self._initialized = True
420
else:
421
for i from 0 <= i < self._nrows * self._ncols:
422
mpz_init_set(self._entries[i], (<Integer> entries[i]).value)
423
self._initialized = True
424
else:
425
426
# If x is zero, make the zero matrix and be done.
427
if mpz_sgn(x.value) == 0:
428
self._zero_out_matrix()
429
return
430
431
# the matrix must be square:
432
if self._nrows != self._ncols:
433
sage_free(self._entries)
434
sage_free(self._matrix)
435
self._entries = NULL
436
raise TypeError("nonzero scalar matrix must be square")
437
438
# Now we set all the diagonal entries to x and all other entries to 0.
439
self._zero_out_matrix()
440
j = 0
441
for i from 0 <= i < self._nrows:
442
mpz_set(self._entries[j], x.value)
443
j = j + self._nrows + 1
444
self._initialized = True
445
446
cdef set_unsafe(self, Py_ssize_t i, Py_ssize_t j, value):
447
"""
448
Set position i,j of this matrix to x.
449
450
(VERY UNSAFE - value *must* be of type Integer).
451
452
INPUT:
453
454
455
- ``i`` - row
456
457
- ``j`` - column
458
459
- ``value`` - The value to set self[i,j] to. value
460
MUST be of type Integer
461
462
463
EXAMPLES::
464
465
sage: a = matrix(ZZ,2,3, range(6)); a
466
[0 1 2]
467
[3 4 5]
468
sage: a[0,0] = 10
469
sage: a
470
[10 1 2]
471
[ 3 4 5]
472
"""
473
mpz_set(self._matrix[i][j], (<Integer>value).value)
474
475
cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j):
476
"""
477
Returns (j, i) entry of self as a new Integer.
478
479
.. warning::
480
481
This is very unsafe; it assumes i and j are in the right
482
range.
483
484
EXAMPLES::
485
486
sage: a = MatrixSpace(ZZ,3)(range(9)); a
487
[0 1 2]
488
[3 4 5]
489
[6 7 8]
490
sage: a[1,2]
491
5
492
sage: a[4,7]
493
Traceback (most recent call last):
494
...
495
IndexError: matrix index out of range
496
sage: a[-1,0]
497
6
498
"""
499
cdef Integer z
500
z = PY_NEW(Integer)
501
mpz_set(z.value, self._matrix[i][j])
502
return z
503
504
def _pickle(self):
505
"""
506
EXAMPLES::
507
508
sage: a = matrix(ZZ,2,3,[1,193,15,-2,3,0])
509
sage: a._pickle()
510
('1 61 f -2 3 0', 0)
511
512
sage: S = ModularSymbols(250,4,sign=1).cuspidal_submodule().new_subspace().decomposition() # long time
513
sage: S == loads(dumps(S)) # long time
514
True
515
"""
516
return self._pickle_version0(), 0
517
518
cdef _pickle_version0(self):
519
"""
520
EXAMPLES::
521
522
sage: matrix(ZZ,1,3,[1,193,15])._pickle() # indirect doctest
523
('1 61 f', 0)
524
525
"""
526
return self._export_as_string(32)
527
528
cpdef _export_as_string(self, int base=10):
529
"""
530
Return space separated string of the entries in this matrix, in the
531
given base. This is optimized for speed.
532
533
INPUT: base -an integer = 36; (default: 10)
534
535
EXAMPLES::
536
537
sage: m = matrix(ZZ,2,3,[1,2,-3,1,-2,-45])
538
sage: m._export_as_string(10)
539
'1 2 -3 1 -2 -45'
540
sage: m._export_as_string(16)
541
'1 2 -3 1 -2 -2d'
542
"""
543
# TODO: *maybe* redo this to use mpz_import and mpz_export
544
# from sec 5.14 of the GMP manual. ??
545
cdef int i, j, len_so_far, m, n
546
cdef char *a
547
cdef char *s, *t, *tmp
548
549
if self._nrows == 0 or self._ncols == 0:
550
data = ''
551
else:
552
n = self._nrows*self._ncols*10
553
s = <char*> sage_malloc(n * sizeof(char))
554
t = s
555
len_so_far = 0
556
557
sig_on()
558
for i from 0 <= i < self._nrows * self._ncols:
559
m = mpz_sizeinbase (self._entries[i], base)
560
if len_so_far + m + 2 >= n:
561
# copy to new string with double the size
562
n = 2*n + m + 1
563
tmp = <char*> sage_malloc(n * sizeof(char))
564
strcpy(tmp, s)
565
sage_free(s)
566
s = tmp
567
t = s + len_so_far
568
#endif
569
mpz_get_str(t, base, self._entries[i])
570
m = strlen(t)
571
len_so_far = len_so_far + m + 1
572
t = t + m
573
t[0] = <char>32
574
t[1] = <char>0
575
t = t + 1
576
sig_off()
577
data = str(s)[:-1]
578
sage_free(s)
579
return data
580
581
def _unpickle(self, data, int version):
582
if version == 0:
583
self._unpickle_version0(data)
584
else:
585
raise RuntimeError("unknown matrix version (=%s)"%version)
586
587
cdef _unpickle_version0(self, data):
588
cdef Py_ssize_t i, n
589
data = data.split()
590
n = self._nrows * self._ncols
591
if len(data) != n:
592
raise RuntimeError("invalid pickle data.")
593
for i from 0 <= i < n:
594
s = data[i]
595
if mpz_init_set_str(self._entries[i], s, 32):
596
raise RuntimeError("invalid pickle data")
597
self._initialized = True
598
599
600
def __richcmp__(Matrix self, right, int op): # always need for mysterious reasons.
601
return self._richcmp(right, op)
602
603
########################################################################
604
# LEVEL 1 helpers:
605
# These function support the implementation of the level 1 functionality.
606
########################################################################
607
cdef _zero_out_matrix(self):
608
"""
609
Set this matrix to be the zero matrix. This is only for internal
610
use. (Note: this matrix must NOT already have initialised
611
entries.)
612
"""
613
# TODO: This is about 6-10 slower than MAGMA doing what seems to be the same thing.
614
# Moreover, NTL can also do this quickly. Why? I think both have specialized
615
# small integer classes. (dmharvey: yes, NTL does not allocate any memory when
616
# initializing a ZZ to zero.)
617
sig_on()
618
cdef Py_ssize_t i
619
for i from 0 <= i < self._nrows * self._ncols:
620
mpz_init(self._entries[i])
621
sig_off()
622
self._initialized = True
623
624
cdef _new_unitialized_matrix(self, Py_ssize_t nrows, Py_ssize_t ncols):
625
"""
626
Return a new matrix over the integers with the given number of rows
627
and columns. All memory is allocated for this matrix, but its
628
entries have not yet been filled in.
629
"""
630
P = self._parent.matrix_space(nrows, ncols)
631
return Matrix_integer_dense.__new__(Matrix_integer_dense, P, None, None, None)
632
633
634
########################################################################
635
# LEVEL 2 functionality
636
# x * cdef _add_
637
# x * cdef _sub_
638
# x * cdef _mul_
639
# x * cdef _cmp_c_impl
640
# * __neg__
641
# * __invert__
642
# * __copy__
643
# x * _multiply_classical
644
# * _list -- list of underlying elements (need not be a copy)
645
# * _dict -- sparse dictionary of underlying elements (need not be a copy)
646
########################################################################
647
648
# cdef _mul_(self, Matrix right):
649
# def __neg__(self):
650
# def __invert__(self):
651
# def __copy__(self):
652
# def _multiply_classical(left, matrix.Matrix _right):
653
# def _list(self):
654
# def _dict(self):
655
656
def __nonzero__(self):
657
r"""
658
Tests whether self is the zero matrix.
659
660
EXAMPLES::
661
662
sage: a = MatrixSpace(ZZ, 2, 3)(range(6)); a
663
[0 1 2]
664
[3 4 5]
665
sage: a.__nonzero__()
666
True
667
sage: (a - a).__nonzero__()
668
False
669
670
::
671
672
sage: a = MatrixSpace(ZZ, 0, 3)()
673
sage: a.__nonzero__()
674
False
675
sage: a = MatrixSpace(ZZ, 3, 0)()
676
sage: a.__nonzero__()
677
False
678
sage: a = MatrixSpace(ZZ, 0, 0)()
679
sage: a.__nonzero__()
680
False
681
"""
682
cdef mpz_t *a, *b
683
cdef Py_ssize_t i, j
684
cdef int k
685
for i from 0 <= i < self._nrows * self._ncols:
686
if mpz_sgn(self._entries[i]):
687
return True
688
return False
689
690
def _multiply_linbox(self, Matrix right):
691
"""
692
Multiply matrices over ZZ using linbox.
693
694
.. warning::
695
696
This is very slow right now, i.e., linbox is very slow.
697
698
EXAMPLES::
699
700
sage: A = matrix(ZZ,2,3,range(6))
701
sage: A*A.transpose()
702
[ 5 14]
703
[14 50]
704
sage: A._multiply_linbox(A.transpose())
705
[ 5 14]
706
[14 50]
707
"""
708
cdef int e
709
cdef Matrix_integer_dense ans, B
710
B = right
711
ans = self.new_matrix(nrows = self.nrows(), ncols = right.ncols())
712
self._init_linbox()
713
sig_on()
714
linbox.matrix_matrix_multiply(ans._matrix, B._matrix, B._nrows, B._ncols)
715
sig_off()
716
return ans
717
718
def _multiply_classical(self, Matrix right):
719
"""
720
EXAMPLE::
721
722
sage: n = 3
723
sage: a = MatrixSpace(ZZ,n,n)(range(n^2))
724
sage: b = MatrixSpace(ZZ,n,n)(range(1, n^2 + 1))
725
sage: a._multiply_classical(b)
726
[ 18 21 24]
727
[ 54 66 78]
728
[ 90 111 132]
729
"""
730
if self._ncols != right._nrows:
731
raise IndexError("Number of columns of self must equal number of rows of right.")
732
733
cdef Py_ssize_t i, j, k, l, nr, nc, snc
734
cdef mpz_t *v
735
cdef object parent
736
737
nr = self._nrows
738
nc = right._ncols
739
snc = self._ncols
740
741
if self._nrows == right._nrows:
742
# self acts on the space of right
743
parent = right.parent()
744
if self._ncols == right._ncols:
745
# right acts on the space of self
746
parent = self.parent()
747
else:
748
parent = self.matrix_space(nr, nc)
749
750
cdef Matrix_integer_dense M, _right
751
_right = right
752
753
M = Matrix_integer_dense.__new__(Matrix_integer_dense, parent, None, None, None)
754
Matrix.__init__(M, parent)
755
756
# M has memory allocated but entries are not initialized
757
cdef mpz_t *entries
758
entries = M._entries
759
760
cdef mpz_t s, z
761
mpz_init(s)
762
mpz_init(z)
763
764
sig_on()
765
l = 0
766
for i from 0 <= i < nr:
767
for j from 0 <= j < nc:
768
mpz_set_si(s,0) # set s = 0
769
v = self._matrix[i]
770
for k from 0 <= k < snc:
771
mpz_mul(z, v[k], _right._matrix[k][j])
772
mpz_add(s, s, z)
773
mpz_init_set(entries[l], s)
774
l += 1
775
sig_off()
776
mpz_clear(s)
777
mpz_clear(z)
778
M._initialized = True
779
return M
780
781
cdef sage.structure.element.Matrix _matrix_times_matrix_(self, sage.structure.element.Matrix right):
782
783
#############
784
# see the tune_multiplication function below.
785
n = max(self._nrows, self._ncols, right._nrows, right._ncols)
786
if n <= 20:
787
return self._multiply_classical(right)
788
a = self.height(); b = right.height()
789
if float(max(a,b)) / float(n) >= 0.70:
790
return self._multiply_classical(right)
791
else:
792
return self._multiply_multi_modular(right)
793
794
cpdef ModuleElement _lmul_(self, RingElement right):
795
"""
796
EXAMPLES::
797
798
sage: a = matrix(QQ,2,range(6))
799
sage: (3/4) * a
800
[ 0 3/4 3/2]
801
[ 9/4 3 15/4]
802
"""
803
cdef Py_ssize_t i
804
cdef Integer _x
805
_x = Integer(right)
806
cdef Matrix_integer_dense M
807
M = Matrix_integer_dense.__new__(Matrix_integer_dense, self._parent, None, None, None)
808
for i from 0 <= i < self._nrows * self._ncols:
809
mpz_init(M._entries[i])
810
mpz_mul(M._entries[i], self._entries[i], _x.value)
811
M._initialized = True
812
return M
813
814
cpdef ModuleElement _add_(self, ModuleElement right):
815
"""
816
Add two dense matrices over ZZ.
817
818
EXAMPLES::
819
820
sage: a = MatrixSpace(ZZ,3)(range(9))
821
sage: a+a
822
[ 0 2 4]
823
[ 6 8 10]
824
[12 14 16]
825
sage: b = MatrixSpace(ZZ,3)(range(9))
826
sage: b.swap_rows(1,2)
827
sage: a+b
828
[ 0 2 4]
829
[ 9 11 13]
830
[ 9 11 13]
831
"""
832
cdef Py_ssize_t i, j
833
834
cdef Matrix_integer_dense M
835
M = Matrix_integer_dense.__new__(Matrix_integer_dense, self._parent, None, None, None)
836
837
sig_on()
838
cdef mpz_t *row_self, *row_right, *row_ans
839
for i from 0 <= i < self._nrows:
840
row_self = self._matrix[i]
841
row_right = (<Matrix_integer_dense> right)._matrix[i]
842
row_ans = M._matrix[i]
843
for j from 0 <= j < self._ncols:
844
mpz_init(row_ans[j])
845
mpz_add(row_ans[j], row_self[j], row_right[j])
846
sig_off()
847
M._initialized = True
848
return M
849
850
cpdef ModuleElement _sub_(self, ModuleElement right):
851
"""
852
Subtract two dense matrices over ZZ.
853
854
EXAMPLES::
855
856
sage: M = Mat(ZZ,3)
857
sage: a = M(range(9)); b = M(reversed(range(9)))
858
sage: a - b
859
[-8 -6 -4]
860
[-2 0 2]
861
[ 4 6 8]
862
"""
863
cdef Py_ssize_t i, j
864
865
cdef Matrix_integer_dense M
866
M = Matrix_integer_dense.__new__(Matrix_integer_dense, self._parent, None, None, None)
867
868
sig_on()
869
cdef mpz_t *row_self, *row_right, *row_ans
870
for i from 0 <= i < self._nrows:
871
row_self = self._matrix[i]
872
row_right = (<Matrix_integer_dense> right)._matrix[i]
873
row_ans = M._matrix[i]
874
for j from 0 <= j < self._ncols:
875
mpz_init(row_ans[j])
876
mpz_sub(row_ans[j], row_self[j], row_right[j])
877
sig_off()
878
M._initialized = True
879
return M
880
881
882
cdef int _cmp_c_impl(self, Element right) except -2:
883
r"""
884
Compares self with right, examining entries in lexicographic (row
885
major) ordering.
886
887
EXAMPLES::
888
889
sage: Matrix(ZZ, [[0, 10], [20, 30]]).__cmp__(Matrix(ZZ, [[0, 10], [20, 30]]))
890
0
891
sage: Matrix(ZZ, [[0, 10], [20, 30]]).__cmp__(Matrix(ZZ, [[0, 15], [20, 30]]))
892
-1
893
sage: Matrix(ZZ, [[5, 10], [20, 30]]).__cmp__(Matrix(ZZ, [[0, 15], [20, 30]]))
894
1
895
sage: Matrix(ZZ, [[5, 10], [20, 30]]).__cmp__(Matrix(ZZ, [[0, 10], [25, 30]]))
896
1
897
"""
898
cdef mpz_t *a, *b
899
cdef Py_ssize_t i, j
900
cdef int k
901
902
for i from 0 <= i < self._nrows:
903
a = self._matrix[i]
904
b = (<Matrix_integer_dense>right)._matrix[i]
905
for j from 0 <= j < self._ncols:
906
k = mpz_cmp(a[j], b[j])
907
if k:
908
if k < 0:
909
return -1
910
else:
911
return 1
912
return 0
913
914
915
cdef Vector _vector_times_matrix_(self, Vector v):
916
"""
917
Returns the vector times matrix product.
918
919
INPUT:
920
921
922
- ``v`` - a free module element.
923
924
925
OUTPUT: The vector times matrix product v\*A.
926
927
EXAMPLES::
928
929
sage: B = matrix(ZZ,2, [1,2,3,4])
930
sage: V = ZZ^2
931
sage: w = V([-1,5])
932
sage: w*B
933
(14, 18)
934
"""
935
cdef Vector_integer_dense w, ans
936
cdef Py_ssize_t i, j
937
cdef mpz_t x
938
939
M = self._row_ambient_module()
940
w = <Vector_integer_dense> v
941
ans = M.zero_vector()
942
943
mpz_init(x)
944
for i from 0 <= i < self._ncols:
945
mpz_set_si(x, 0)
946
for j from 0 <= j < self._nrows:
947
mpz_addmul(x, w._entries[j], self._matrix[j][i])
948
mpz_set(ans._entries[i], x)
949
mpz_clear(x)
950
return ans
951
952
953
########################################################################
954
# LEVEL 3 functionality (Optional)
955
# * __deepcopy__
956
# * __invert__
957
# * Matrix windows -- only if you need strassen for that base
958
# * Other functions (list them here):
959
# * Specialized echelon form
960
########################################################################
961
962
def _clear_denom(self):
963
"""
964
INPUT:
965
966
- ``self`` - a matrix
967
968
OUTPUT: self, 1
969
970
EXAMPLES::
971
972
sage: a = matrix(ZZ,2,[1,2,3,4])
973
sage: a._clear_denom()
974
(
975
[1 2]
976
[3 4], 1
977
)
978
"""
979
return self, ZZ(1)
980
981
def charpoly(self, var='x', algorithm='linbox'):
982
"""
983
INPUT:
984
985
986
- ``var`` - a variable name
987
988
- ``algorithm`` - 'linbox' (default) 'generic'
989
990
991
.. note::
992
993
Linbox charpoly disabled on 64-bit machines, since it hangs
994
in many cases.
995
996
EXAMPLES::
997
998
sage: A = matrix(ZZ,6, range(36))
999
sage: f = A.charpoly(); f
1000
x^6 - 105*x^5 - 630*x^4
1001
sage: f(A) == 0
1002
True
1003
sage: n=20; A = Mat(ZZ,n)(range(n^2))
1004
sage: A.charpoly()
1005
x^20 - 3990*x^19 - 266000*x^18
1006
sage: A.minpoly()
1007
x^3 - 3990*x^2 - 266000*x
1008
1009
TESTS:
1010
1011
The cached polynomial should be independent of the ``var``
1012
argument (:trac:`12292`). We check (indirectly) that the
1013
second call uses the cached value by noting that its result is
1014
not cached::
1015
1016
sage: M = MatrixSpace(ZZ, 2)
1017
sage: A = M(range(0, 2^2))
1018
sage: type(A)
1019
<type 'sage.matrix.matrix_integer_dense.Matrix_integer_dense'>
1020
sage: A.charpoly('x')
1021
x^2 - 3*x - 2
1022
sage: A.charpoly('y')
1023
y^2 - 3*y - 2
1024
sage: A._cache['charpoly_linbox']
1025
x^2 - 3*x - 2
1026
1027
"""
1028
cache_key = 'charpoly_%s' % algorithm
1029
g = self.fetch(cache_key)
1030
if g is not None:
1031
return g.change_variable_name(var)
1032
1033
if algorithm == 'linbox' and not USE_LINBOX_POLY:
1034
algorithm = 'generic'
1035
1036
if algorithm == 'linbox':
1037
g = self._charpoly_linbox(var)
1038
elif algorithm == 'generic':
1039
g = matrix_dense.Matrix_dense.charpoly(self, var)
1040
else:
1041
raise ValueError("no algorithm '%s'"%algorithm)
1042
1043
self.cache(cache_key, g)
1044
return g
1045
1046
def minpoly(self, var='x', algorithm='linbox'):
1047
"""
1048
INPUT:
1049
1050
1051
- ``var`` - a variable name
1052
1053
- ``algorithm`` - 'linbox' (default) 'generic'
1054
1055
1056
.. note::
1057
1058
Linbox charpoly disabled on 64-bit machines, since it hangs
1059
in many cases.
1060
1061
EXAMPLES::
1062
1063
sage: A = matrix(ZZ,6, range(36))
1064
sage: A.minpoly()
1065
x^3 - 105*x^2 - 630*x
1066
sage: n=6; A = Mat(ZZ,n)([k^2 for k in range(n^2)])
1067
sage: A.minpoly()
1068
x^4 - 2695*x^3 - 257964*x^2 + 1693440*x
1069
"""
1070
key = 'minpoly_%s_%s'%(algorithm, var)
1071
x = self.fetch(key)
1072
if x: return x
1073
1074
if algorithm == 'linbox' and not USE_LINBOX_POLY:
1075
algorithm = 'generic'
1076
1077
if algorithm == 'linbox':
1078
g = self._minpoly_linbox(var)
1079
elif algorithm == 'generic':
1080
g = matrix_dense.Matrix_dense.minpoly(self, var)
1081
else:
1082
raise ValueError("no algorithm '%s'"%algorithm)
1083
1084
self.cache(key, g)
1085
return g
1086
1087
def _minpoly_linbox(self, var='x'):
1088
return self._poly_linbox(var=var, typ='minpoly')
1089
1090
def _charpoly_linbox(self, var='x'):
1091
if self.is_zero(): # program around a bug in linbox on 32-bit linux
1092
x = self.base_ring()[var].gen()
1093
return x ** self._nrows
1094
return self._poly_linbox(var=var, typ='charpoly')
1095
1096
def _poly_linbox(self, var='x', typ='minpoly'):
1097
"""
1098
INPUT:
1099
1100
1101
- ``var`` - 'x'
1102
1103
- ``typ`` - 'minpoly' or 'charpoly'
1104
"""
1105
time = verbose('computing %s of %s x %s matrix using linbox'%(typ, self._nrows, self._ncols))
1106
if self._nrows != self._ncols:
1107
raise ArithmeticError("self must be a square matrix")
1108
if self._nrows <= 1:
1109
return matrix_dense.Matrix_dense.charpoly(self, var)
1110
self._init_linbox()
1111
if typ == 'minpoly':
1112
sig_on()
1113
v = linbox.minpoly()
1114
sig_off()
1115
else:
1116
sig_on()
1117
v = linbox.charpoly()
1118
sig_off()
1119
R = self._base_ring[var]
1120
verbose('finished computing %s'%typ, time)
1121
return R(v)
1122
1123
1124
def height(self):
1125
"""
1126
Return the height of this matrix, i.e., the max absolute value of
1127
the entries of the matrix.
1128
1129
OUTPUT: A nonnegative integer.
1130
1131
EXAMPLE::
1132
1133
sage: a = Mat(ZZ,3)(range(9))
1134
sage: a.height()
1135
8
1136
sage: a = Mat(ZZ,2,3)([-17,3,-389,15,-1,0]); a
1137
[ -17 3 -389]
1138
[ 15 -1 0]
1139
sage: a.height()
1140
389
1141
"""
1142
cdef mpz_t h
1143
cdef Integer x
1144
1145
self.mpz_height(h)
1146
x = Integer()
1147
x.set_from_mpz(h)
1148
mpz_clear(h)
1149
1150
return x
1151
1152
cdef int mpz_height(self, mpz_t height) except -1:
1153
"""
1154
Used to compute the height of this matrix.
1155
1156
INPUT:
1157
1158
1159
- ``height`` - a GMP mpz_t (that has not been
1160
initialized!)
1161
1162
1163
OUTPUT: sets the value of height to the height of this matrix,
1164
i.e., the max absolute value of the entries of the matrix.
1165
"""
1166
cdef mpz_t x, h
1167
cdef Py_ssize_t i
1168
1169
mpz_init_set_si(h, 0)
1170
mpz_init(x)
1171
1172
sig_on()
1173
1174
for i from 0 <= i < self._nrows * self._ncols:
1175
mpz_abs(x, self._entries[i])
1176
if mpz_cmp(h, x) < 0:
1177
mpz_set(h, x)
1178
1179
sig_off()
1180
1181
mpz_init_set(height, h)
1182
mpz_clear(h)
1183
mpz_clear(x)
1184
1185
return 0 # no error occurred.
1186
1187
def _multiply_multi_modular(left, Matrix_integer_dense right):
1188
"""
1189
Multiply this matrix by ``left`` using a multi modular algorithm.
1190
1191
EXAMPLES::
1192
1193
sage: M = Matrix(ZZ, 2, 3, range(5,11))
1194
sage: N = Matrix(ZZ, 3, 2, range(15,21))
1195
sage: M._multiply_multi_modular(N)
1196
[310 328]
1197
[463 490]
1198
sage: M._multiply_multi_modular(-N)
1199
[-310 -328]
1200
[-463 -490]
1201
"""
1202
cdef Integer h
1203
cdef mod_int *moduli
1204
cdef int i, n, k
1205
1206
h = left.height() * right.height() * left.ncols()
1207
verbose('multiplying matrices of height %s and %s'%(left.height(),right.height()))
1208
mm = MultiModularBasis(h)
1209
res = left._reduce(mm)
1210
res_right = right._reduce(mm)
1211
k = len(mm)
1212
for i in range(k): # yes, I could do this with zip, but to conserve memory...
1213
t = cputime()
1214
res[i] *= res_right[i]
1215
verbose('multiplied matrices modulo a prime (%s/%s)'%(i+1,k), t)
1216
result = left.new_matrix(left.nrows(), right.ncols())
1217
_lift_crt(result, res, mm) # changes result
1218
return result
1219
1220
cdef void reduce_entry_unsafe(self, Py_ssize_t i, Py_ssize_t j, Integer modulus):
1221
# Used for p-adic matrices.
1222
if mpz_cmp(self._matrix[i][j], modulus.value) >= 0 or mpz_cmp_ui(self._matrix[i][j], 0) < 0:
1223
mpz_mod(self._matrix[i][j], self._matrix[i][j], modulus.value)
1224
1225
def _mod_int(self, modulus):
1226
"""
1227
Reduce the integer matrix modulo a positive integer.
1228
1229
EXAMPLES::
1230
sage: matrix(QQ,2,[1,0,0,1]).change_ring(GF(2)) - 1
1231
[0 0]
1232
[0 0]
1233
1234
"""
1235
cdef mod_int c = modulus
1236
if int(c) != modulus:
1237
raise OverflowError
1238
else:
1239
return self._mod_int_c(modulus)
1240
1241
cdef _mod_two(self):
1242
cdef Matrix_mod2_dense res
1243
res = Matrix_mod2_dense.__new__(Matrix_mod2_dense, matrix_space.MatrixSpace(IntegerModRing(2), self._nrows, self._ncols, sparse=False), None, None, None)
1244
res.__init__(matrix_space.MatrixSpace(IntegerModRing(2), self._nrows, self._ncols, sparse=False), self.list(), None, None)
1245
return res
1246
1247
cdef _mod_int_c(self, mod_int p):
1248
from matrix_modn_dense_float import MAX_MODULUS as MAX_MODULUS_FLOAT
1249
from matrix_modn_dense_double import MAX_MODULUS as MAX_MODULUS_DOUBLE
1250
1251
cdef Py_ssize_t i, j
1252
cdef mpz_t* self_row
1253
1254
cdef float* res_row_f
1255
cdef Matrix_modn_dense_float res_f
1256
1257
cdef double* res_row_d
1258
cdef Matrix_modn_dense_double res_d
1259
1260
if p == 2:
1261
return self._mod_two()
1262
elif p < MAX_MODULUS_FLOAT:
1263
res_f = Matrix_modn_dense_float.__new__(Matrix_modn_dense_float,
1264
matrix_space.MatrixSpace(IntegerModRing(p), self._nrows, self._ncols, sparse=False), None, None, None)
1265
for i from 0 <= i < self._nrows:
1266
self_row = self._matrix[i]
1267
res_row_f = res_f._matrix[i]
1268
for j from 0 <= j < self._ncols:
1269
res_row_f[j] = <float>mpz_fdiv_ui(self_row[j], p)
1270
return res_f
1271
1272
elif p < MAX_MODULUS_DOUBLE:
1273
res_d = Matrix_modn_dense_double.__new__(Matrix_modn_dense_double,
1274
matrix_space.MatrixSpace(IntegerModRing(p), self._nrows, self._ncols, sparse=False), None, None, None)
1275
for i from 0 <= i < self._nrows:
1276
self_row = self._matrix[i]
1277
res_row_d = res_d._matrix[i]
1278
for j from 0 <= j < self._ncols:
1279
res_row_d[j] = <double>mpz_fdiv_ui(self_row[j], p)
1280
return res_d
1281
else:
1282
raise ValueError("p to big.")
1283
1284
def _reduce(self, moduli):
1285
from matrix_modn_dense_float import MAX_MODULUS as MAX_MODULUS_FLOAT
1286
from matrix_modn_dense_double import MAX_MODULUS as MAX_MODULUS_DOUBLE
1287
1288
if isinstance(moduli, (int, long, Integer)):
1289
return self._mod_int(moduli)
1290
elif isinstance(moduli, list):
1291
moduli = MultiModularBasis(moduli)
1292
1293
cdef MultiModularBasis mm
1294
mm = moduli
1295
1296
res = []
1297
for p in mm:
1298
if p < MAX_MODULUS_FLOAT:
1299
res.append( Matrix_modn_dense_float.__new__(Matrix_modn_dense_float,
1300
matrix_space.MatrixSpace(IntegerModRing(p), self._nrows, self._ncols, sparse=False),
1301
None, None, None) )
1302
elif p < MAX_MODULUS_DOUBLE:
1303
res.append( Matrix_modn_dense_double.__new__(Matrix_modn_dense_double,
1304
matrix_space.MatrixSpace(IntegerModRing(p), self._nrows, self._ncols, sparse=False),
1305
None, None, None) )
1306
else:
1307
raise ValueError("p=%d too big."%p)
1308
1309
cdef size_t i, k, n
1310
cdef Py_ssize_t nr, nc
1311
1312
n = len(mm)
1313
nr = self._nrows
1314
nc = self._ncols
1315
1316
cdef mod_int **row_list
1317
row_list = <mod_int**>sage_malloc(sizeof(mod_int*) * n)
1318
if row_list == NULL:
1319
raise MemoryError("out of memory allocating multi-modular coefficient list")
1320
for k in range(n):
1321
row_list[k] = <mod_int*>sage_malloc(sizeof(mod_int)*nc)
1322
if row_list[k] == NULL:
1323
for i in range(k):
1324
sage_free(row_list[i])
1325
sage_free(row_list)
1326
raise MemoryError("out of memory allocating multi-modular coefficient list")
1327
1328
sig_on()
1329
for i from 0 <= i < nr:
1330
for k from 0 <= k < n:
1331
mm.mpz_reduce_vec(self._matrix[i], row_list, nc)
1332
if isinstance(res[k], Matrix_modn_dense_float):
1333
for j in range(nc):
1334
(<Matrix_modn_dense_float>res[k])._matrix[i][j] = (<float>row_list[k][j])%(<Matrix_modn_dense_float>res[k]).p
1335
else:
1336
for j in range(nc):
1337
(<Matrix_modn_dense_double>res[k])._matrix[i][j] = (<double>row_list[k][j])%(<Matrix_modn_dense_double>res[k]).p
1338
sig_off()
1339
1340
for k in range(n):
1341
sage_free(row_list[k])
1342
sage_free(row_list)
1343
return res
1344
1345
def _linbox_modn_det(self, mod_int n):
1346
"""
1347
INPUT:
1348
1349
1350
- ``n`` - a prime (at most 67108879)
1351
1352
1353
EXAMPLES::
1354
1355
sage: a = matrix(ZZ, 3, [1,2,5,-7,8,10,192,5,18])
1356
sage: a.det()
1357
-3669
1358
sage: a._linbox_modn_det(5077)
1359
1408
1360
sage: a._linbox_modn_det(3)
1361
0
1362
sage: a._linbox_modn_det(2)
1363
1
1364
sage: a.det()%5077
1365
1408
1366
sage: a.det()%2
1367
1
1368
sage: a.det()%3
1369
0
1370
"""
1371
d = self._linbox_modn(n).det()
1372
return IntegerModRing(n)(d)
1373
1374
def _linbox_modn(self, mod_int n):
1375
"""
1376
Return modn linbox object associated to this integer matrix.
1377
1378
EXAMPLES::
1379
1380
sage: a = matrix(ZZ, 3, [1,2,5,-7,8,10,192,5,18])
1381
sage: b = a._linbox_modn(19); b
1382
<sage.libs.linbox.linbox.Linbox_modn_dense object at ...>
1383
sage: b.charpoly()
1384
[2L, 10L, 11L, 1L]
1385
"""
1386
if n > 67108879: # doesn't work for bigger primes -- experimental observation
1387
raise NotImplementedError("modulus to big")
1388
cdef mod_int** matrix = <mod_int**>sage_malloc(sizeof(mod_int*) * self._nrows)
1389
if matrix == NULL:
1390
raise MemoryError("out of memory allocating multi-modular coefficient list")
1391
1392
cdef Py_ssize_t i, j
1393
for i from 0 <= i < self._nrows:
1394
matrix[i] = <mod_int *>sage_malloc(sizeof(mod_int) * self._ncols)
1395
if matrix[i] == NULL:
1396
raise MemoryError("out of memory allocating multi-modular coefficient list")
1397
for j from 0 <= j < self._ncols:
1398
matrix[i][j] = mpz_fdiv_ui(self._matrix[i][j], n)
1399
1400
cdef Linbox_modn_dense L = Linbox_modn_dense()
1401
L.set(n, matrix, self._nrows, self._ncols)
1402
return L
1403
1404
def _echelon_in_place_classical(self):
1405
cdef Matrix_integer_dense E
1406
E = self.echelon_form()
1407
1408
cdef int i
1409
for i from 0 <= i < self._ncols * self._nrows:
1410
mpz_set(self._entries[i], E._entries[i])
1411
1412
self.clear_cache()
1413
1414
def _echelon_strassen(self):
1415
raise NotImplementedError
1416
1417
def _magma_init_(self, magma):
1418
"""
1419
EXAMPLES::
1420
1421
sage: m = matrix(ZZ,2,3,[1,2,-3,1,-2,-45])
1422
sage: m._magma_init_(magma)
1423
'Matrix(IntegerRing(),2,3,StringToIntegerSequence("1 2 -3 1 -2 -45"))'
1424
sage: magma(m) # optional - magma
1425
[ 1 2 -3]
1426
[ 1 -2 -45]
1427
"""
1428
w = self._export_as_string(base=10)
1429
return 'Matrix(IntegerRing(),%s,%s,StringToIntegerSequence("%s"))'%(
1430
self.nrows(), self.ncols(), w)
1431
1432
def symplectic_form(self):
1433
r"""
1434
Find a symplectic basis for self if self is an anti-symmetric,
1435
alternating matrix.
1436
1437
Returns a pair (F, C) such that the rows of C form a symplectic
1438
basis for self and F = C \* self \* C.transpose().
1439
1440
Raises a ValueError if self is not anti-symmetric, or self is not
1441
alternating.
1442
1443
Anti-symmetric means that `M = -M^t`. Alternating means
1444
that the diagonal of `M` is identically zero.
1445
1446
A symplectic basis is a basis of the form
1447
`e_1, \ldots, e_j, f_1, \ldots f_j, z_1, \dots, z_k`
1448
such that
1449
1450
- `z_i M v^t` = 0 for all vectors `v`
1451
1452
- `e_i M {e_j}^t = 0` for all `i, j`
1453
1454
- `f_i M {f_j}^t = 0` for all `i, j`
1455
1456
- `e_i M {f_i}^t = 1` for all `i`
1457
1458
- `e_i M {f_j}^t = 0` for all `i` not equal
1459
`j`.
1460
1461
The ordering for the factors `d_{i} | d_{i+1}` and for
1462
the placement of zeroes was chosen to agree with the output of
1463
``smith_form``.
1464
1465
See the example for a pictorial description of such a basis.
1466
1467
EXAMPLES::
1468
1469
sage: E = matrix(ZZ, 5, 5, [0, 14, 0, -8, -2, -14, 0, -3, -11, 4, 0, 3, 0, 0, 0, 8, 11, 0, 0, 8, 2, -4, 0, -8, 0]); E
1470
[ 0 14 0 -8 -2]
1471
[-14 0 -3 -11 4]
1472
[ 0 3 0 0 0]
1473
[ 8 11 0 0 8]
1474
[ 2 -4 0 -8 0]
1475
sage: F, C = E.symplectic_form()
1476
sage: F
1477
[ 0 0 1 0 0]
1478
[ 0 0 0 2 0]
1479
[-1 0 0 0 0]
1480
[ 0 -2 0 0 0]
1481
[ 0 0 0 0 0]
1482
sage: F == C * E * C.transpose()
1483
True
1484
sage: E.smith_form()[0]
1485
[1 0 0 0 0]
1486
[0 1 0 0 0]
1487
[0 0 2 0 0]
1488
[0 0 0 2 0]
1489
[0 0 0 0 0]
1490
"""
1491
import sage.matrix.symplectic_basis
1492
return sage.matrix.symplectic_basis.symplectic_basis_over_ZZ(self)
1493
1494
hermite_form = echelon_form
1495
1496
def echelon_form(self, algorithm="default", proof=None, include_zero_rows=True,
1497
transformation=False, D=None):
1498
r"""
1499
Return the echelon form of this matrix over the integers, also known
1500
as the hermit normal form (HNF).
1501
1502
INPUT:
1503
1504
- ``algorithm`` -- String. The algorithm to use. Valid options are:
1505
1506
- ``'default'`` -- Let Sage pick an algorithm (default). Up
1507
to 10 rows or columns: pari with flag 0; Up to 75 rows or
1508
columns: pari with flag 1; Larger: use padic algorithm.
1509
1510
- ``'padic'`` - an asymptotically fast p-adic modular
1511
algorithm, If your matrix has large coefficients and is
1512
small, you may also want to try this.
1513
1514
- ``'pari'`` - use PARI with flag 1
1515
1516
- ``'pari0'`` - use PARI with flag 0
1517
1518
- ``'pari4'`` - use PARI with flag 4 (use heuristic LLL)
1519
1520
- ``'ntl'`` - use NTL (only works for square matrices of
1521
full rank!)
1522
1523
- ``proof`` - (default: True); if proof=False certain
1524
determinants are computed using a randomized hybrid p-adic
1525
multimodular strategy until it stabilizes twice (instead of up to
1526
the Hadamard bound). It is *incredibly* unlikely that one would
1527
ever get an incorrect result with proof=False.
1528
1529
- ``include_zero_rows`` - (default: True) if False,
1530
don't include zero rows
1531
1532
- ``transformation`` - if given, also compute
1533
transformation matrix; only valid for padic algorithm
1534
1535
- ``D`` - (default: None) if given and the algorithm
1536
is 'ntl', then D must be a multiple of the determinant and this
1537
function will use that fact.
1538
1539
OUTPUT:
1540
1541
The Hermite normal form (=echelon form over `\ZZ`) of self.
1542
1543
EXAMPLES::
1544
1545
sage: A = MatrixSpace(ZZ,2)([1,2,3,4])
1546
sage: A.echelon_form()
1547
[1 0]
1548
[0 2]
1549
sage: A = MatrixSpace(ZZ,5)(range(25))
1550
sage: A.echelon_form()
1551
[ 5 0 -5 -10 -15]
1552
[ 0 1 2 3 4]
1553
[ 0 0 0 0 0]
1554
[ 0 0 0 0 0]
1555
[ 0 0 0 0 0]
1556
1557
Getting a transformation matrix in the nonsquare case::
1558
1559
sage: A = matrix(ZZ,5,3,[1..15])
1560
sage: H, U = A.hermite_form(transformation=True, include_zero_rows=False)
1561
sage: H
1562
[1 2 3]
1563
[0 3 6]
1564
sage: U
1565
[ 0 0 0 4 -3]
1566
[ 0 0 0 13 -10]
1567
sage: U*A == H
1568
True
1569
1570
TESTS: Make sure the zero matrices are handled correctly::
1571
1572
sage: m = matrix(ZZ,3,3,[0]*9)
1573
sage: m.echelon_form()
1574
[0 0 0]
1575
[0 0 0]
1576
[0 0 0]
1577
sage: m = matrix(ZZ,3,1,[0]*3)
1578
sage: m.echelon_form()
1579
[0]
1580
[0]
1581
[0]
1582
sage: m = matrix(ZZ,1,3,[0]*3)
1583
sage: m.echelon_form()
1584
[0 0 0]
1585
1586
The ultimate border case!
1587
1588
::
1589
1590
sage: m = matrix(ZZ,0,0,[])
1591
sage: m.echelon_form()
1592
[]
1593
1594
.. note::
1595
1596
If 'ntl' is chosen for a non square matrix this function
1597
raises a ValueError.
1598
1599
Special cases: 0 or 1 rows::
1600
1601
sage: a = matrix(ZZ, 1,2,[0,-1])
1602
sage: a.hermite_form()
1603
[0 1]
1604
sage: a.pivots()
1605
(1,)
1606
sage: a = matrix(ZZ, 1,2,[0,0])
1607
sage: a.hermite_form()
1608
[0 0]
1609
sage: a.pivots()
1610
()
1611
sage: a = matrix(ZZ,1,3); a
1612
[0 0 0]
1613
sage: a.echelon_form(include_zero_rows=False)
1614
[]
1615
sage: a.echelon_form(include_zero_rows=True)
1616
[0 0 0]
1617
1618
Illustrate using various algorithms.::
1619
1620
sage: matrix(ZZ,3,[1..9]).hermite_form(algorithm='pari')
1621
[1 2 3]
1622
[0 3 6]
1623
[0 0 0]
1624
sage: matrix(ZZ,3,[1..9]).hermite_form(algorithm='pari0')
1625
[1 2 3]
1626
[0 3 6]
1627
[0 0 0]
1628
sage: matrix(ZZ,3,[1..9]).hermite_form(algorithm='pari4')
1629
[1 2 3]
1630
[0 3 6]
1631
[0 0 0]
1632
sage: matrix(ZZ,3,[1..9]).hermite_form(algorithm='padic')
1633
[1 2 3]
1634
[0 3 6]
1635
[0 0 0]
1636
sage: matrix(ZZ,3,[1..9]).hermite_form(algorithm='default')
1637
[1 2 3]
1638
[0 3 6]
1639
[0 0 0]
1640
1641
The 'ntl' algorithm doesn't work on matrices that do not have full rank.::
1642
1643
sage: matrix(ZZ,3,[1..9]).hermite_form(algorithm='ntl')
1644
Traceback (most recent call last):
1645
...
1646
ValueError: ntl only computes HNF for square matrices of full rank.
1647
sage: matrix(ZZ,3,[0] +[2..9]).hermite_form(algorithm='ntl')
1648
[1 0 0]
1649
[0 1 0]
1650
[0 0 3]
1651
1652
TESTS:
1653
1654
This example illustrated trac 2398::
1655
1656
sage: a = matrix([(0, 0, 3), (0, -2, 2), (0, 1, 2), (0, -2, 5)])
1657
sage: a.hermite_form()
1658
[0 1 2]
1659
[0 0 3]
1660
[0 0 0]
1661
[0 0 0]
1662
1663
Check that #12280 is fixed::
1664
1665
sage: m = matrix([(-2, 1, 9, 2, -8, 1, -3, -1, -4, -1),
1666
... (5, -2, 0, 1, 0, 4, -1, 1, -2, 0),
1667
... (-11, 3, 1, 0, -3, -2, -1, -11, 2, -2),
1668
... (-1, 1, -1, -2, 1, -1, -1, -1, -1, 7),
1669
... (-2, -1, -1, 1, 1, -2, 1, 0, 2, -4)]).stack(
1670
... 200 * identity_matrix(ZZ, 10))
1671
sage: matrix(ZZ,m).hermite_form(algorithm='pari', include_zero_rows=False)
1672
[ 1 0 2 0 13 5 1 166 72 69]
1673
[ 0 1 1 0 20 4 15 195 65 190]
1674
[ 0 0 4 0 24 5 23 22 51 123]
1675
[ 0 0 0 1 23 7 20 105 60 151]
1676
[ 0 0 0 0 40 4 0 80 36 68]
1677
[ 0 0 0 0 0 10 0 100 190 170]
1678
[ 0 0 0 0 0 0 25 0 100 150]
1679
[ 0 0 0 0 0 0 0 200 0 0]
1680
[ 0 0 0 0 0 0 0 0 200 0]
1681
[ 0 0 0 0 0 0 0 0 0 200]
1682
sage: matrix(ZZ,m).hermite_form(algorithm='padic', include_zero_rows=False)
1683
[ 1 0 2 0 13 5 1 166 72 69]
1684
[ 0 1 1 0 20 4 15 195 65 190]
1685
[ 0 0 4 0 24 5 23 22 51 123]
1686
[ 0 0 0 1 23 7 20 105 60 151]
1687
[ 0 0 0 0 40 4 0 80 36 68]
1688
[ 0 0 0 0 0 10 0 100 190 170]
1689
[ 0 0 0 0 0 0 25 0 100 150]
1690
[ 0 0 0 0 0 0 0 200 0 0]
1691
[ 0 0 0 0 0 0 0 0 200 0]
1692
[ 0 0 0 0 0 0 0 0 0 200]
1693
"""
1694
if self._nrows == 0 or self._ncols == 0:
1695
self.cache('pivots', ())
1696
self.cache('rank', 0)
1697
if transformation:
1698
return self, self
1699
return self
1700
1701
key = 'hnf-%s-%s'%(include_zero_rows,transformation)
1702
ans = self.fetch(key)
1703
if ans is not None: return ans
1704
1705
cdef Py_ssize_t nr, nc, n, i, j
1706
nr = self._nrows
1707
nc = self._ncols
1708
n = nr if nr >= nc else nc
1709
if algorithm is 'default':
1710
if transformation: algorithm = 'padic'
1711
else:
1712
if n <= 10: algorithm = 'pari0'
1713
elif n <= 75: algorithm = 'pari'
1714
else: algorithm = 'padic'
1715
1716
cdef bint pari_big = 0
1717
if algorithm.startswith('pari'):
1718
if self.height().ndigits() > 10000 or n >= 50:
1719
pari_big = 1
1720
1721
cdef Matrix_integer_dense H_m
1722
1723
proof = get_proof_flag(proof, "linear_algebra")
1724
pivots = None
1725
rank = None
1726
1727
if algorithm == "padic":
1728
import matrix_integer_dense_hnf
1729
if transformation:
1730
H_m, U, pivots = matrix_integer_dense_hnf.hnf_with_transformation(self, proof=proof)
1731
if not include_zero_rows:
1732
r = H_m.rank()
1733
H_m = H_m[:r]
1734
U = U[:r]
1735
else:
1736
H_m, pivots = matrix_integer_dense_hnf.hnf(self,
1737
include_zero_rows=include_zero_rows, proof=proof)
1738
self.cache('pivots', tuple(pivots))
1739
self.cache('rank', len(pivots))
1740
1741
1742
elif algorithm == 'pari0':
1743
if transformation:
1744
raise ValueError("transformation matrix only available with p-adic algorithm")
1745
if pari_big:
1746
H_m = self._hnf_pari_big(0, include_zero_rows=include_zero_rows)
1747
else:
1748
H_m = self._hnf_pari(0, include_zero_rows=include_zero_rows)
1749
1750
elif algorithm == 'pari':
1751
if transformation:
1752
raise ValueError("transformation matrix only available with p-adic algorithm")
1753
if pari_big:
1754
H_m = self._hnf_pari_big(1, include_zero_rows=include_zero_rows)
1755
else:
1756
H_m = self._hnf_pari(1, include_zero_rows=include_zero_rows)
1757
1758
elif algorithm == 'pari4':
1759
if transformation:
1760
raise ValueError("transformation matrix only available with p-adic algorithm")
1761
if pari_big:
1762
H_m = self._hnf_pari_big(4, include_zero_rows=include_zero_rows)
1763
else:
1764
H_m = self._hnf_pari(4, include_zero_rows=include_zero_rows)
1765
1766
elif algorithm == 'ntl':
1767
if transformation:
1768
raise ValueError("transformation matrix only available with p-adic algorithm")
1769
1770
if nr != nc:
1771
raise ValueError("ntl only computes HNF for square matrices of full rank.")
1772
1773
import sage.libs.ntl.ntl_mat_ZZ
1774
v = sage.libs.ntl.ntl_mat_ZZ.ntl_mat_ZZ(self._nrows,self._ncols)
1775
for i from 0 <= i < self._nrows:
1776
for j from 0 <= j < self._ncols:
1777
v[i,j] = self.get_unsafe(nr-i-1,nc-j-1)
1778
1779
try:
1780
w = v.HNF(D=D)
1781
except RuntimeError: # HNF may fail if a nxm matrix has rank < m
1782
raise ValueError("ntl only computes HNF for square matrices of full rank.")
1783
1784
rank = w.nrows()
1785
1786
if include_zero_rows:
1787
H_m = self.new_matrix()
1788
else:
1789
H_m = self.new_matrix(nrows=w.nrows())
1790
1791
nr = w.nrows()
1792
nc = w.ncols()
1793
1794
for i from 0 <= i < w.nrows():
1795
for j from 0 <= j < w.ncols():
1796
H_m[i,j] = w[nr-i-1,nc-j-1]
1797
1798
else:
1799
raise TypeError("algorithm '%s' not understood"%(algorithm))
1800
1801
H_m.set_immutable()
1802
if pivots is None:
1803
from matrix_integer_dense_hnf import pivots_of_hnf_matrix
1804
pivots = tuple(pivots_of_hnf_matrix(H_m))
1805
rank = len(pivots)
1806
else:
1807
pivots = tuple(pivots)
1808
1809
H_m.cache('pivots', pivots)
1810
self.cache('pivots', pivots)
1811
1812
H_m.cache('rank', rank)
1813
self.cache('rank',rank)
1814
1815
H_m.cache('in_echelon_form', True)
1816
1817
1818
if transformation:
1819
U.set_immutable()
1820
ans = H_m, U
1821
else:
1822
ans = H_m
1823
self.cache(key, ans)
1824
return ans
1825
1826
def saturation(self, p=0, proof=None, max_dets=5):
1827
r"""
1828
Return a saturation matrix of self, which is a matrix whose rows
1829
span the saturation of the row span of self. This is not unique.
1830
1831
The saturation of a `\ZZ` module `M`
1832
embedded in `\ZZ^n` is the a module `S` that
1833
contains `M` with finite index such that
1834
`\ZZ^n/S` is torsion free. This function takes the
1835
row span `M` of self, and finds another matrix of full rank
1836
with row span the saturation of `M`.
1837
1838
INPUT:
1839
1840
1841
- ``p`` - (default: 0); if nonzero given, saturate
1842
only at the prime `p`, i.e., return a matrix whose row span
1843
is a `\ZZ`-module `S` that contains self and
1844
such that the index of `S` in its saturation is coprime to
1845
`p`. If `p` is None, return full saturation of
1846
self.
1847
1848
- ``proof`` - (default: use proof.linear_algebra());
1849
if False, the determinant calculations are done with proof=False.
1850
1851
- ``max_dets`` - (default: 5); technical parameter -
1852
max number of determinant to compute when bounding prime divisor of
1853
self in its saturation.
1854
1855
1856
OUTPUT:
1857
1858
1859
- ``matrix`` - a matrix over ZZ
1860
1861
1862
.. note::
1863
1864
The result is *not* cached.
1865
1866
ALGORITHM: 1. Replace input by a matrix of full rank got from a
1867
subset of the rows. 2. Divide out any common factors from rows. 3.
1868
Check max_dets random dets of submatrices to see if their GCD
1869
(with p) is 1 - if so matrix is saturated and we're done. 4.
1870
Finally, use that if A is a matrix of full rank, then
1871
`hnf(transpose(A))^{-1}*A` is a saturation of A.
1872
1873
EXAMPLES::
1874
1875
sage: A = matrix(ZZ, 3, 5, [-51, -1509, -71, -109, -593, -19, -341, 4, 86, 98, 0, -246, -11, 65, 217])
1876
sage: A.echelon_form()
1877
[ 1 5 2262 20364 56576]
1878
[ 0 6 35653 320873 891313]
1879
[ 0 0 42993 386937 1074825]
1880
sage: S = A.saturation(); S
1881
[ -51 -1509 -71 -109 -593]
1882
[ -19 -341 4 86 98]
1883
[ 35 994 43 51 347]
1884
1885
Notice that the saturation spans a different module than A.
1886
1887
::
1888
1889
sage: S.echelon_form()
1890
[ 1 2 0 8 32]
1891
[ 0 3 0 -2 -6]
1892
[ 0 0 1 9 25]
1893
sage: V = A.row_space(); W = S.row_space()
1894
sage: V.is_submodule(W)
1895
True
1896
sage: V.index_in(W)
1897
85986
1898
sage: V.index_in_saturation()
1899
85986
1900
1901
We illustrate each option::
1902
1903
sage: S = A.saturation(p=2)
1904
sage: S = A.saturation(proof=False)
1905
sage: S = A.saturation(max_dets=2)
1906
"""
1907
proof = get_proof_flag(proof, "linear_algebra")
1908
import matrix_integer_dense_saturation
1909
return matrix_integer_dense_saturation.saturation(self, p=p, proof=proof, max_dets=max_dets)
1910
1911
def index_in_saturation(self, proof=None):
1912
"""
1913
Return the index of self in its saturation.
1914
1915
INPUT:
1916
1917
1918
- ``proof`` - (default: use proof.linear_algebra());
1919
if False, the determinant calculations are done with proof=False.
1920
1921
1922
OUTPUT:
1923
1924
1925
- ``positive integer`` - the index of the row span of
1926
this matrix in its saturation
1927
1928
1929
ALGORITHM: Use Hermite normal form twice to find an invertible
1930
matrix whose inverse transforms a matrix with the same row span as
1931
self to its saturation, then compute the determinant of that
1932
matrix.
1933
1934
EXAMPLES::
1935
1936
sage: A = matrix(ZZ, 2,3, [1..6]); A
1937
[1 2 3]
1938
[4 5 6]
1939
sage: A.index_in_saturation()
1940
3
1941
sage: A.saturation()
1942
[1 2 3]
1943
[1 1 1]
1944
"""
1945
proof = get_proof_flag(proof, "linear_algebra")
1946
import matrix_integer_dense_saturation
1947
return matrix_integer_dense_saturation.index_in_saturation(self, proof=proof)
1948
1949
def pivots(self):
1950
"""
1951
Return the pivot column positions of this matrix.
1952
1953
OUTPUT: a tuple of Python integers: the position of the
1954
first nonzero entry in each row of the echelon form.
1955
1956
EXAMPLES::
1957
1958
sage: n = 3; A = matrix(ZZ,n,range(n^2)); A
1959
[0 1 2]
1960
[3 4 5]
1961
[6 7 8]
1962
sage: A.pivots()
1963
(0, 1)
1964
sage: A.echelon_form()
1965
[ 3 0 -3]
1966
[ 0 1 2]
1967
[ 0 0 0]
1968
"""
1969
p = self.fetch('pivots')
1970
if not p is None: return tuple(p)
1971
1972
cdef Matrix_integer_dense E
1973
E = self.echelon_form()
1974
1975
# Now we determine the pivots from the matrix E as quickly as we can.
1976
# For each row, we find the first nonzero position in that row -- it is the pivot.
1977
cdef Py_ssize_t i, j, k
1978
cdef mpz_t *row
1979
p = []
1980
k = 0
1981
for i from 0 <= i < E._nrows:
1982
row = E._matrix[i] # pointer to ith row
1983
for j from k <= j < E._ncols:
1984
if mpz_cmp_si(row[j], 0) != 0: # nonzero position
1985
p.append(j)
1986
k = j+1 # so start at next position next time
1987
break
1988
p = tuple(p)
1989
self.cache('pivots', p)
1990
return p
1991
1992
#### Elementary divisors
1993
1994
def elementary_divisors(self, algorithm='pari'):
1995
"""
1996
Return the elementary divisors of self, in order.
1997
1998
1999
.. warning::
2000
2001
This is MUCH faster than the smith_form function.
2002
2003
The elementary divisors are the invariants of the finite abelian
2004
group that is the cokernel of *left* multiplication of this matrix.
2005
They are ordered in reverse by divisibility.
2006
2007
INPUT:
2008
2009
2010
- ``self`` - matrix
2011
2012
- ``algorithm`` - (default: 'pari')
2013
2014
- ``'pari'``: works robustly, but is slower.
2015
2016
- ``'linbox'`` - use linbox (currently off, broken)
2017
2018
2019
OUTPUT: list of integers
2020
2021
2022
.. note::
2023
2024
These are the invariants of the cokernel of *left* multiplication::
2025
2026
sage: M = Matrix([[3,0,1],[0,1,0]])
2027
sage: M
2028
[3 0 1]
2029
[0 1 0]
2030
sage: M.elementary_divisors()
2031
[1, 1]
2032
sage: M.transpose().elementary_divisors()
2033
[1, 1, 0]
2034
2035
EXAMPLES::
2036
2037
sage: matrix(3, range(9)).elementary_divisors()
2038
[1, 3, 0]
2039
sage: matrix(3, range(9)).elementary_divisors(algorithm='pari')
2040
[1, 3, 0]
2041
sage: C = MatrixSpace(ZZ,4)([3,4,5,6,7,3,8,10,14,5,6,7,2,2,10,9])
2042
sage: C.elementary_divisors()
2043
[1, 1, 1, 687]
2044
2045
::
2046
2047
sage: M = matrix(ZZ, 3, [1,5,7, 3,6,9, 0,1,2])
2048
sage: M.elementary_divisors()
2049
[1, 1, 6]
2050
2051
This returns a copy, which is safe to change::
2052
2053
sage: edivs = M.elementary_divisors()
2054
sage: edivs.pop()
2055
6
2056
sage: M.elementary_divisors()
2057
[1, 1, 6]
2058
2059
.. seealso::
2060
2061
:meth:`smith_form`
2062
"""
2063
d = self.fetch('elementary_divisors')
2064
if not d is None:
2065
return d[:]
2066
if self._nrows == 0 or self._ncols == 0:
2067
d = []
2068
else:
2069
if algorithm == 'linbox':
2070
raise ValueError("linbox too broken -- currently Linbox SNF is disabled.")
2071
# This fails in linbox: a = matrix(ZZ,2,[1, 1, -1, 0, 0, 0, 0, 1])
2072
try:
2073
d = self._elementary_divisors_linbox()
2074
except RuntimeError:
2075
import sys
2076
sys.stderr.write("DONT PANIC -- switching to using PARI (which will work fine)\n")
2077
algorithm = 'pari'
2078
if algorithm == 'pari':
2079
d = self._pari_().matsnf(0).python()
2080
i = d.count(0)
2081
d.sort()
2082
if i > 0:
2083
d = d[i:] + [d[0]]*i
2084
elif not (algorithm in ['pari', 'linbox']):
2085
raise ValueError("algorithm (='%s') unknown"%algorithm)
2086
self.cache('elementary_divisors', d)
2087
return d[:]
2088
2089
def _elementary_divisors_linbox(self):
2090
self._init_linbox()
2091
sig_on()
2092
d = linbox.smithform()
2093
sig_off()
2094
return d
2095
2096
def smith_form(self):
2097
r"""
2098
Returns matrices S, U, and V such that S = U\*self\*V, and S is in
2099
Smith normal form. Thus S is diagonal with diagonal entries the
2100
ordered elementary divisors of S.
2101
2102
.. warning::
2103
2104
The elementary_divisors function, which returns the
2105
diagonal entries of S, is VASTLY faster than this function.
2106
2107
The elementary divisors are the invariants of the finite abelian
2108
group that is the cokernel of this matrix. They are ordered in
2109
reverse by divisibility.
2110
2111
EXAMPLES::
2112
2113
sage: A = MatrixSpace(IntegerRing(), 3)(range(9))
2114
sage: D, U, V = A.smith_form()
2115
sage: D
2116
[1 0 0]
2117
[0 3 0]
2118
[0 0 0]
2119
sage: U
2120
[ 0 1 0]
2121
[ 0 -1 1]
2122
[-1 2 -1]
2123
sage: V
2124
[-1 4 1]
2125
[ 1 -3 -2]
2126
[ 0 0 1]
2127
sage: U*A*V
2128
[1 0 0]
2129
[0 3 0]
2130
[0 0 0]
2131
2132
It also makes sense for nonsquare matrices::
2133
2134
sage: A = Matrix(ZZ,3,2,range(6))
2135
sage: D, U, V = A.smith_form()
2136
sage: D
2137
[1 0]
2138
[0 2]
2139
[0 0]
2140
sage: U
2141
[ 0 1 0]
2142
[ 0 -1 1]
2143
[-1 2 -1]
2144
sage: V
2145
[-1 3]
2146
[ 1 -2]
2147
sage: U * A * V
2148
[1 0]
2149
[0 2]
2150
[0 0]
2151
2152
Empty matrices are handled sensibly (see trac #3068)::
2153
2154
sage: m = MatrixSpace(ZZ, 2,0)(0); d,u,v = m.smith_form(); u*m*v == d
2155
True
2156
sage: m = MatrixSpace(ZZ, 0,2)(0); d,u,v = m.smith_form(); u*m*v == d
2157
True
2158
sage: m = MatrixSpace(ZZ, 0,0)(0); d,u,v = m.smith_form(); u*m*v == d
2159
True
2160
2161
.. seealso::
2162
2163
:meth:`elementary_divisors`
2164
"""
2165
v = self._pari_().matsnf(1).python()
2166
if self._ncols == 0: v[0] = self.matrix_space(ncols = self._nrows)(1)
2167
if self._nrows == 0: v[1] = self.matrix_space(nrows = self._ncols)(1)
2168
# need to reverse order of rows of U, columns of V, and both of D.
2169
D = self.matrix_space()([v[2][i,j] for i in xrange(self._nrows-1,-1,-1) for j in xrange(self._ncols-1,-1,-1)])
2170
2171
if self._ncols == 0:
2172
# silly special cases for matrices with 0 columns (PARI has a unique empty matrix)
2173
U = self.matrix_space(ncols = self._nrows)(1)
2174
else:
2175
U = self.matrix_space(ncols = self._nrows)([v[0][i,j] for i in xrange(self._nrows-1,-1,-1) for j in xrange(self._nrows)])
2176
2177
if self._nrows == 0:
2178
# silly special cases for matrices with 0 rows (PARI has a unique empty matrix)
2179
V = self.matrix_space(nrows = self._ncols)(1)
2180
else:
2181
V = self.matrix_space(nrows = self._ncols)([v[1][i,j] for i in xrange(self._ncols) for j in xrange(self._ncols-1,-1,-1)])
2182
2183
return D, U, V
2184
2185
def frobenius(self, flag=0, var='x'):
2186
"""
2187
Return the Frobenius form (rational canonical form) of this
2188
matrix.
2189
2190
INPUT:
2191
2192
- ``flag`` -- 0 (default), 1 or 2 as follows:
2193
2194
- ``0`` -- (default) return the Frobenius form of this
2195
matrix.
2196
2197
- ``1`` -- return only the elementary divisor
2198
polynomials, as polynomials in var.
2199
2200
- ``2`` -- return a two-components vector [F,B] where F
2201
is the Frobenius form and B is the basis change so that
2202
`M=B^{-1}FB`.
2203
2204
- ``var`` -- a string (default: 'x')
2205
2206
ALGORITHM: uses PARI's matfrobenius()
2207
2208
EXAMPLES::
2209
2210
sage: A = MatrixSpace(ZZ, 3)(range(9))
2211
sage: A.frobenius(0)
2212
[ 0 0 0]
2213
[ 1 0 18]
2214
[ 0 1 12]
2215
sage: A.frobenius(1)
2216
[x^3 - 12*x^2 - 18*x]
2217
sage: A.frobenius(1, var='y')
2218
[y^3 - 12*y^2 - 18*y]
2219
sage: F, B = A.frobenius(2)
2220
sage: A == B^(-1)*F*B
2221
True
2222
sage: a=matrix([])
2223
sage: a.frobenius(2)
2224
([], [])
2225
sage: a.frobenius(0)
2226
[]
2227
sage: a.frobenius(1)
2228
[]
2229
sage: B = random_matrix(ZZ,2,3)
2230
sage: B.frobenius()
2231
Traceback (most recent call last):
2232
...
2233
ArithmeticError: frobenius matrix of non-square matrix not defined.
2234
2235
AUTHORS:
2236
2237
- Martin Albrect (2006-04-02)
2238
2239
TODO: - move this to work for more general matrices than just over
2240
Z. This will require fixing how PARI polynomials are coerced to
2241
Sage polynomials.
2242
"""
2243
if not self.is_square():
2244
raise ArithmeticError("frobenius matrix of non-square matrix not defined.")
2245
2246
v = self._pari_().matfrobenius(flag)
2247
if flag==0:
2248
return self.matrix_space()(v.python())
2249
elif flag==1:
2250
r = PolynomialRing(self.base_ring(), names=var)
2251
retr = []
2252
for f in v:
2253
retr.append(eval(str(f).replace("^","**"), {'x':r.gen()}, r.gens_dict()))
2254
return retr
2255
elif flag==2:
2256
F = matrix_space.MatrixSpace(QQ, self.nrows())(v[0].python())
2257
B = matrix_space.MatrixSpace(QQ, self.nrows())(v[1].python())
2258
return F, B
2259
2260
def _right_kernel_matrix(self, **kwds):
2261
r"""
2262
Returns a pair that includes a matrix of basis vectors
2263
for the right kernel of ``self``.
2264
2265
INPUT:
2266
2267
- ``algorithm`` - determines which algorithm to use, options are:
2268
2269
- 'pari' - use the ``matkerint()`` function from the PARI library
2270
- 'padic' - use the p-adic algorithm from the IML library
2271
- 'default' - use a heuristic to decide which of the two above
2272
routines is fastest. This is the default value.
2273
2274
- ``proof`` - this is passed to the p-adic IML algorithm.
2275
If not specified, the global flag for linear algebra will be used.
2276
2277
OUTPUT:
2278
2279
Returns a pair. First item is the string is either
2280
'computed-pari-int' or 'computed-iml-int', which identifies
2281
the nature of the basis vectors.
2282
2283
Second item is a matrix whose rows are a basis for the right kernel,
2284
over the integers, as computed by either the IML or PARI libraries.
2285
2286
EXAMPLES::
2287
2288
sage: A = matrix(ZZ, [[4, 7, 9, 7, 5, 0],
2289
... [1, 0, 5, 8, 9, 1],
2290
... [0, 1, 0, 1, 9, 7],
2291
... [4, 7, 6, 5, 1, 4]])
2292
2293
sage: result = A._right_kernel_matrix(algorithm='pari')
2294
sage: result[0]
2295
'computed-pari-int'
2296
sage: X = result[1]; X
2297
[-26 31 -30 21 2 -10]
2298
[-47 -13 48 -14 -11 18]
2299
sage: A*X.transpose() == zero_matrix(ZZ, 4, 2)
2300
True
2301
2302
sage: result = A._right_kernel_matrix(algorithm='padic')
2303
sage: result[0]
2304
'computed-iml-int'
2305
sage: X = result[1]; X
2306
[-469 214 -30 119 -37 0]
2307
[ 370 -165 18 -91 30 -2]
2308
sage: A*X.transpose() == zero_matrix(ZZ, 4, 2)
2309
True
2310
2311
sage: result = A._right_kernel_matrix(algorithm='default')
2312
sage: result[0]
2313
'computed-pari-int'
2314
sage: result[1]
2315
[-26 31 -30 21 2 -10]
2316
[-47 -13 48 -14 -11 18]
2317
2318
sage: result = A._right_kernel_matrix()
2319
sage: result[0]
2320
'computed-pari-int'
2321
sage: result[1]
2322
[-26 31 -30 21 2 -10]
2323
[-47 -13 48 -14 -11 18]
2324
2325
With the 'default' given as the algorithm, several heuristics are
2326
used to determine if PARI or IML ('padic') is used. The code has
2327
exact details, but roughly speaking, relevant factors are: the
2328
absolute size of the matrix, or the relative dimensions, or the
2329
magnitude of the entries. ::
2330
2331
sage: A = random_matrix(ZZ, 18, 11)
2332
sage: A._right_kernel_matrix(algorithm='default')[0]
2333
'computed-pari-int'
2334
sage: A = random_matrix(ZZ, 18, 11, x = 10^200)
2335
sage: A._right_kernel_matrix(algorithm='default')[0]
2336
'computed-iml-int'
2337
sage: A = random_matrix(ZZ, 60, 60)
2338
sage: A._right_kernel_matrix(algorithm='default')[0]
2339
'computed-iml-int'
2340
sage: A = random_matrix(ZZ, 60, 55)
2341
sage: A._right_kernel_matrix(algorithm='default')[0]
2342
'computed-pari-int'
2343
2344
TESTS:
2345
2346
We test three trivial cases. PARI is used for small matrices,
2347
but we let the heuristic decide that. ::
2348
2349
sage: A = matrix(ZZ, 0, 2)
2350
sage: A._right_kernel_matrix()[1]
2351
[1 0]
2352
[0 1]
2353
sage: A = matrix(ZZ, 2, 0)
2354
sage: A._right_kernel_matrix()[1].parent()
2355
Full MatrixSpace of 0 by 0 dense matrices over Integer Ring
2356
sage: A = zero_matrix(ZZ, 4, 3)
2357
sage: A._right_kernel_matrix()[1]
2358
[1 0 0]
2359
[0 1 0]
2360
[0 0 1]
2361
"""
2362
tm = verbose("computing right kernel matrix over the integers for %sx%s matrix" % (self.nrows(), self.ncols()),level=1)
2363
2364
algorithm = kwds.pop('algorithm', None)
2365
if algorithm == None:
2366
algorithm = 'default'
2367
2368
if algorithm == 'default':
2369
# The heuristic here could be auto-tuned, stored for
2370
# different architecture, etc. What I've done below here
2371
# I just got by playing around with examples. This is
2372
# *dramatically* better than doing absolutely nothing
2373
# (i.e., always choosing 'padic'), but is of course
2374
# far from optimal. -- William Stein
2375
if max(self._nrows, self._ncols) <= 10:
2376
# pari much better for very small matrices, as long as entries aren't huge.
2377
algorithm = 'pari'
2378
if max(self._nrows, self._ncols) <= 50:
2379
# when entries are huge, padic relatively good.
2380
h = self.height().ndigits()
2381
if h < 100:
2382
algorithm = 'pari'
2383
else:
2384
algorithm = 'padic'
2385
elif self._nrows <= self._ncols + 3:
2386
# the padic algorithm is much better for bigger
2387
# matrices if there are nearly more columns than rows
2388
# (that is its forte)
2389
algorithm = 'padic'
2390
else:
2391
algorithm = 'pari'
2392
2393
if algorithm == 'pari':
2394
K = self._pari_().matkerint().mattranspose().python()
2395
format = 'computed-pari-int'
2396
if algorithm == 'padic':
2397
proof = kwds.pop('proof', None)
2398
proof = get_proof_flag(proof, "linear_algebra")
2399
K = self._rational_kernel_iml().transpose().saturation(proof=proof)
2400
format = 'computed-iml-int'
2401
tm = verbose("done computing right kernel matrix over the integers for %sx%s matrix" % (self.nrows(), self.ncols()),level=1, t=tm)
2402
return (format, K)
2403
2404
def _adjoint(self):
2405
"""
2406
Return the adjoint of this matrix.
2407
2408
Assumes self is a square matrix (checked in adjoint).
2409
2410
EXAMPLES::
2411
2412
sage: m = matrix(ZZ,3,[1..9])
2413
sage: m.adjoint()
2414
[ -3 6 -3]
2415
[ 6 -12 6]
2416
[ -3 6 -3]
2417
"""
2418
return self.parent()(self._pari_().matadjoint().python())
2419
2420
def _ntl_(self):
2421
r"""
2422
ntl.mat_ZZ representation of self.
2423
2424
EXAMPLE::
2425
2426
sage: a = MatrixSpace(ZZ,200).random_element(x=-2, y=2) # -2 to 2
2427
sage: A = a._ntl_()
2428
2429
.. note::
2430
2431
NTL only knows dense matrices, so if you provide a sparse
2432
matrix NTL will allocate memory for every zero entry.
2433
"""
2434
import sage.libs.ntl.ntl_mat_ZZ
2435
return sage.libs.ntl.ntl_mat_ZZ.ntl_mat_ZZ(self._nrows,self._ncols, self.list())
2436
2437
2438
####################################################################################
2439
# LLL
2440
####################################################################################
2441
def LLL_gram(self):
2442
"""
2443
LLL reduction of the lattice whose gram matrix is self.
2444
2445
INPUT:
2446
2447
2448
- ``M`` - gram matrix of a definite quadratic form
2449
2450
2451
OUTPUT:
2452
2453
2454
- ``U`` - unimodular transformation matrix such that
2455
U.transpose() \* M \* U is LLL-reduced.
2456
2457
ALGORITHM: Use PARI
2458
2459
EXAMPLES::
2460
2461
sage: M = Matrix(ZZ, 2, 2, [5,3,3,2]) ; M
2462
[5 3]
2463
[3 2]
2464
sage: U = M.LLL_gram(); U
2465
[-1 1]
2466
[ 1 -2]
2467
sage: U.transpose() * M * U
2468
[1 0]
2469
[0 1]
2470
2471
Semidefinite and indefinite forms no longer raise a ValueError::
2472
2473
sage: Matrix(ZZ,2,2,[2,6,6,3]).LLL_gram()
2474
[-3 -1]
2475
[ 1 0]
2476
sage: Matrix(ZZ,2,2,[1,0,0,-1]).LLL_gram()
2477
[ 0 -1]
2478
[ 1 0]
2479
2480
"""
2481
if self._nrows != self._ncols:
2482
raise ArithmeticError("self must be a square matrix")
2483
2484
n = self.nrows()
2485
# maybe should be /unimodular/ matrices ?
2486
P = self._pari_()
2487
try:
2488
U = P.lllgramint()
2489
except (RuntimeError, ArithmeticError), msg:
2490
raise ValueError("not a definite matrix")
2491
MS = matrix_space.MatrixSpace(ZZ,n)
2492
U = MS(U.python())
2493
# Fix last column so that det = +1
2494
if U.det() == -1:
2495
for i in range(n):
2496
U[i,n-1] = - U[i,n-1]
2497
return U
2498
2499
def BKZ(self, delta=None, fp="rr", block_size=10, prune=0, use_givens=False):
2500
"""
2501
Block Korkin-Zolotarev reduction.
2502
2503
INPUT:
2504
2505
2506
- ``fp`` - 'fp' - double precision: NTL's FP or
2507
fpLLL's double
2508
2509
- ``'qd'`` - quad doubles: NTL's QP
2510
2511
- ``'qd1'`` - quad doubles: uses quad_float precision
2512
to compute Gram-Schmidt, but uses double precision in the search
2513
phase of the block reduction algorithm. This seems adequate for
2514
most purposes, and is faster than 'qd', which uses quad_float
2515
precision uniformly throughout.
2516
2517
- ``'xd'`` - extended exponent: NTL's XD
2518
2519
- ``'rr'`` - arbitrary precision (default)
2520
2521
- ``block_size`` - specifies the size of the blocks
2522
in the reduction. High values yield shorter vectors, but the
2523
running time increases exponentially with
2524
``block_size``. ``block_size`` should be
2525
between 2 and the number of rows of ``self`` (default:
2526
10)
2527
2528
- ``prune`` - The optional parameter
2529
``prune`` can be set to any positive number to invoke
2530
the Volume Heuristic from [Schnorr and Horner, Eurocrypt '95]. This
2531
can significantly reduce the running time, and hence allow much
2532
bigger block size, but the quality of the reduction is of course
2533
not as good in general. Higher values of ``prune`` mean
2534
better quality, and slower running time. When ``prune``
2535
== 0, pruning is disabled. Recommended usage: for
2536
``block_size`` = 30, set 10 = ``prune`` =
2537
15.
2538
2539
- ``use_givens`` - use Given's orthogonalization.
2540
This is a bit slower, but generally much more stable, and is really
2541
the preferred orthogonalization strategy. For a nice description of
2542
this, see Chapter 5 of [G. Golub and C. van Loan, Matrix
2543
Computations, 3rd edition, Johns Hopkins Univ. Press, 1996].
2544
2545
2546
EXAMPLE::
2547
2548
sage: A = Matrix(ZZ,3,3,range(1,10))
2549
sage: A.BKZ()
2550
[ 0 0 0]
2551
[ 2 1 0]
2552
[-1 1 3]
2553
sage: A = Matrix(ZZ,3,3,range(1,10))
2554
sage: A.BKZ(use_givens=True)
2555
[ 0 0 0]
2556
[ 2 1 0]
2557
[-1 1 3]
2558
2559
::
2560
2561
sage: A = Matrix(ZZ,3,3,range(1,10))
2562
sage: A.BKZ(fp="fp")
2563
[ 0 0 0]
2564
[ 2 1 0]
2565
[-1 1 3]
2566
"""
2567
if delta is None:
2568
delta = 0.99
2569
elif delta <= 0.25:
2570
raise TypeError("delta must be > 0.25")
2571
elif delta > 1:
2572
raise TypeError("delta must be <= 1")
2573
delta = float(delta)
2574
2575
if fp is None:
2576
fp = "rr"
2577
2578
if fp == "fp":
2579
algorithm = "BKZ_FP"
2580
elif fp == "qd":
2581
algorithm = "BKZ_QP"
2582
elif fp == "qd1":
2583
algorithm = "BKZ_QP1"
2584
elif fp == "xd":
2585
algorithm = "BKZ_XD"
2586
elif fp == "rr":
2587
algorithm = "BKZ_RR"
2588
else:
2589
raise TypeError("fp parameter not understood.")
2590
2591
block_size = int(block_size)
2592
2593
if prune < 0:
2594
raise TypeError("prune must be >= 0")
2595
prune = int(prune)
2596
2597
if get_verbose() >= 2:
2598
verbose = True
2599
else:
2600
verbose = False
2601
2602
A = self._ntl_()
2603
2604
if algorithm == "BKZ_FP":
2605
if not use_givens:
2606
r = A.BKZ_FP(U=None, delta=delta, BlockSize=block_size, prune=prune, verbose=verbose)
2607
else:
2608
r = A.G_BKZ_FP(U=None, delta=delta, BlockSize=block_size, prune=prune, verbose=verbose)
2609
2610
elif algorithm == "BKZ_QP":
2611
if not use_givens:
2612
r = A.BKZ_QP(U=None, delta=delta, BlockSize=block_size, prune=prune, verbose=verbose)
2613
else:
2614
r = A.G_BKZ_QP(U=None, delta=delta, BlockSize=block_size, prune=prune, verbose=verbose)
2615
2616
elif algorithm == "BKZ_QP1":
2617
if not use_givens:
2618
r = A.BKZ_QP1(U=None, delta=delta, BlockSize=block_size, prune=prune, verbose=verbose)
2619
else:
2620
r = A.G_BKZ_QP1(U=None, delta=delta, BlockSize=block_size, prune=prune, verbose=verbose)
2621
2622
elif algorithm == "BKZ_XD":
2623
if not use_givens:
2624
r = A.BKZ_XD(U=None, delta=delta, BlockSize=block_size, prune=prune, verbose=verbose)
2625
else:
2626
r = A.G_BKZ_XD(U=None, delta=delta, BlockSize=block_size, prune=prune, verbose=verbose)
2627
2628
elif algorithm == "BKZ_RR":
2629
if not use_givens:
2630
r = A.BKZ_RR(U=None, delta=delta, BlockSize=block_size, prune=prune, verbose=verbose)
2631
else:
2632
r = A.G_BKZ_RR(U=None, delta=delta, BlockSize=block_size, prune=prune, verbose=verbose)
2633
2634
self.cache("rank",ZZ(r))
2635
R = <Matrix_integer_dense>self.new_matrix(entries=map(ZZ,A.list()))
2636
return R
2637
2638
def LLL(self, delta=None, eta=None, algorithm="fpLLL:wrapper", fp=None, prec=0, early_red = False, use_givens = False):
2639
r"""
2640
Returns LLL reduced or approximated LLL reduced lattice R for this
2641
matrix interpreted as a lattice.
2642
2643
A lattice `(b_1, b_2, ..., b_d)` is
2644
`(\delta, \eta)` -LLL-reduced if the two following
2645
conditions hold:
2646
2647
- For any `i>j`, we have `|mu_{i, j}| <= \eta`,
2648
- For any `i<d`, we have
2649
`\delta |b_i^*|^2 <= |b_{i + 1}^* + mu_{i + 1, i} b_i^* |^2`,
2650
2651
where `mu_{i,j} = <b_i, b_j^*>/<b_j^*,b_j^*>` and
2652
`b_i^*` is the `i`-th vector of the Gram-Schmidt
2653
orthogonalisation of `(b_1, b_2, ..., b_d)`.
2654
2655
The default reduction parameters are `\delta=3/4` and
2656
`eta=0.501`. The parameters `\delta` and
2657
`\eta` must satisfy: `0.25 < \delta <= 1.0` and
2658
`0.5 <= \eta < sqrt(\delta)`. Polynomial time
2659
complexity is only guaranteed for `\delta < 1`.
2660
2661
The lattice is returned as a matrix. Also the rank (and the
2662
determinant) of self are cached if those are computed during the
2663
reduction. Note that in general this only happens when self.rank()
2664
== self.ncols() and the exact algorithm is used.
2665
2666
INPUT:
2667
2668
2669
- ``delta`` - parameter as described above (default:
2670
3/4)
2671
2672
- ``eta`` - parameter as described above (default:
2673
0.501), ignored by NTL
2674
2675
- ``algorithm`` - string (default: "fpLLL:wrapper")
2676
one of the algorithms mentioned below
2677
2678
- ``fp``
2679
2680
- None - NTL's exact reduction or fpLLL's
2681
wrapper
2682
2683
- ``'fp'`` - double precision: NTL's FP or fpLLL's
2684
double
2685
2686
- ``'qd'`` - quad doubles: NTL's QP
2687
2688
- ``'xd'`` - extended exponent: NTL's XD or fpLLL's
2689
dpe
2690
2691
- ``'rr'`` - arbitrary precision: NTL'RR or fpLLL's
2692
MPFR
2693
2694
- ``prec`` - precision, ignored by NTL (default: auto
2695
choose)
2696
2697
- ``early_red`` - perform early reduction, ignored by
2698
NTL (default: False)
2699
2700
- ``use_givens`` - use Givens orthogonalization
2701
(default: False) only applicable to approximate reductions and NTL.
2702
This is more stable but slower.
2703
2704
Also, if the verbose level is = 2, some more verbose output is
2705
printed during the calculation if NTL is used.
2706
2707
AVAILABLE ALGORITHMS:
2708
2709
- ``NTL:LLL`` - NTL's LLL + fp
2710
2711
- ``fpLLL:heuristic`` - fpLLL's heuristic + fp
2712
2713
- ``fpLLL:fast`` - fpLLL's fast
2714
2715
- ``fpLLL:wrapper`` - fpLLL's automatic choice
2716
(default)
2717
2718
2719
OUTPUT: a matrix over the integers
2720
2721
EXAMPLE::
2722
2723
sage: A = Matrix(ZZ,3,3,range(1,10))
2724
sage: A.LLL()
2725
[ 0 0 0]
2726
[ 2 1 0]
2727
[-1 1 3]
2728
2729
We compute the extended GCD of a list of integers using LLL, this
2730
example is from the Magma handbook::
2731
2732
sage: Q = [ 67015143, 248934363018, 109210, 25590011055, 74631449, \
2733
10230248, 709487, 68965012139, 972065, 864972271 ]
2734
sage: n = len(Q)
2735
sage: S = 100
2736
sage: X = Matrix(ZZ, n, n + 1)
2737
sage: for i in xrange(n):
2738
... X[i,i + 1] = 1
2739
sage: for i in xrange(n):
2740
... X[i,0] = S*Q[i]
2741
sage: L = X.LLL()
2742
sage: M = L.row(n-1).list()[1:]
2743
sage: M
2744
[-3, -1, 13, -1, -4, 2, 3, 4, 5, -1]
2745
sage: add([Q[i]*M[i] for i in range(n)])
2746
-1
2747
2748
TESTS::
2749
2750
sage: matrix(ZZ, 0, 0).LLL()
2751
[]
2752
sage: matrix(ZZ, 3, 0).LLL()
2753
[]
2754
sage: matrix(ZZ, 0, 3).LLL()
2755
[]
2756
2757
sage: M = matrix(ZZ, [[1,2,3],[31,41,51],[101,201,301]])
2758
sage: A = M.LLL()
2759
sage: A
2760
[ 0 0 0]
2761
[-1 0 1]
2762
[ 1 1 1]
2763
sage: B = M.LLL(algorithm='NTL:LLL')
2764
sage: C = M.LLL(algorithm='NTL:LLL', fp=None)
2765
sage: D = M.LLL(algorithm='NTL:LLL', fp='fp')
2766
sage: F = M.LLL(algorithm='NTL:LLL', fp='xd')
2767
sage: G = M.LLL(algorithm='NTL:LLL', fp='rr')
2768
sage: A == B == C == D == F == G
2769
True
2770
sage: H = M.LLL(algorithm='NTL:LLL', fp='qd')
2771
Traceback (most recent call last):
2772
...
2773
TypeError: algorithm NTL:LLL_QD not supported
2774
2775
ALGORITHM: Uses the NTL library by Victor Shoup or fpLLL library by
2776
Damien Stehle depending on the chosen algorithm.
2777
2778
REFERENCES:
2779
2780
- ``ntl.mat_ZZ`` or ``sage.libs.fplll.fplll`` for details on
2781
the used algorithms.
2782
"""
2783
if self.ncols()==0 or self.nrows()==0:
2784
verbose("Trivial matrix, nothing to do")
2785
return self
2786
2787
tm = verbose("LLL of %sx%s matrix (algorithm %s)"%(self.nrows(), self.ncols(), algorithm))
2788
import sage.libs.ntl.all
2789
ntl_ZZ = sage.libs.ntl.all.ZZ
2790
2791
from sage.libs.fplll.fplll import FP_LLL
2792
2793
if get_verbose() >= 2: verb = True
2794
else: verb = False
2795
2796
# auto choice
2797
2798
# FP choice
2799
if algorithm == 'NTL:LLL':
2800
if fp == None:
2801
algorithm = 'NTL:LLL_FP'
2802
elif fp == 'fp':
2803
algorithm = 'NTL:LLL_FP'
2804
elif fp == 'qd':
2805
algorithm = 'NTL:LLL_QD'
2806
elif fp == 'xd':
2807
algorithm = 'NTL:LLL_XD'
2808
elif fp == 'rr':
2809
algorithm = 'NTL:LLL_RR'
2810
elif algorithm == 'fpLLL:heuristic':
2811
if fp == None:
2812
raise TypeError("if 'fpLLL:heuristic' is chosen, a floating point number implementation must be chosen")
2813
elif fp == 'fp':
2814
fp = 'double'
2815
elif fp == 'qd':
2816
raise TypeError("fpLLL does not support quad doubles.")
2817
elif fp == 'xd':
2818
fp = 'dpe'
2819
elif fp == 'rr':
2820
fp = 'mpfr'
2821
2822
if algorithm == "NTL:LLL":
2823
if delta is None:
2824
delta = ZZ(3)/ZZ(4)
2825
elif delta <= ZZ(1)/ZZ(4):
2826
raise TypeError("delta must be > 1/4")
2827
elif delta > 1:
2828
raise TypeError("delta must be <= 1")
2829
delta = QQ(delta)
2830
a = delta.numer()
2831
b = delta.denom()
2832
2833
else:
2834
if delta is None:
2835
delta = 0.99
2836
elif delta <= 0.25:
2837
raise TypeError("delta must be > 0.25")
2838
elif delta > 1:
2839
raise TypeError("delta must be <= 1")
2840
delta = float(delta)
2841
2842
if eta is None:
2843
eta = 0.501
2844
elif eta < 0.5:
2845
raise TypeError("eta must be >= 0.5")
2846
2847
if prec < 0:
2848
raise TypeError("precision prec must be >= 0")
2849
int(prec)
2850
2851
if algorithm.startswith('NTL:'):
2852
A = sage.libs.ntl.all.mat_ZZ(self.nrows(),self.ncols(),map(ntl_ZZ,self.list()))
2853
2854
if algorithm == "NTL:LLL":
2855
r, det2 = A.LLL(a,b, verbose=verb)
2856
det2 = ZZ(det2)
2857
try:
2858
det = ZZ(det2.sqrt_approx())
2859
self.cache("det", det)
2860
except TypeError:
2861
pass
2862
elif algorithm == "NTL:LLL_FP":
2863
if use_givens:
2864
r = A.G_LLL_FP(delta, verbose=verb)
2865
else:
2866
r = A.LLL_FP(delta, verbose=verb)
2867
elif algorithm == "NTL:LLL_QP":
2868
if use_givens:
2869
r = A.G_LLL_QP(delta, verbose=verb)
2870
else:
2871
r = A.LLL_QP(delta, verbose=verb)
2872
elif algorithm == "NTL:LLL_XD":
2873
if use_givens:
2874
r = A.G_LLL_XD(delta, verbose=verb)
2875
else:
2876
r = A.LLL_XD(delta, verbose=verb)
2877
elif algorithm == "NTL:LLL_RR":
2878
if use_givens:
2879
r = A.G_LLL_RR(delta, verbose=verb)
2880
else:
2881
r = A.LLL_XD(delta, verbose=verb)
2882
else:
2883
raise TypeError("algorithm %s not supported"%algorithm)
2884
2885
r = ZZ(r)
2886
2887
R = <Matrix_integer_dense>self.new_matrix(entries=map(ZZ,A.list()))
2888
self.cache("rank",r)
2889
2890
elif algorithm.startswith('fpLLL:'):
2891
2892
A = sage.libs.fplll.fplll.FP_LLL(self)
2893
if algorithm == 'fpLLL:wrapper':
2894
A.wrapper(prec, eta, delta)
2895
elif algorithm == 'fpLLL:heuristic':
2896
if early_red:
2897
A.heuristic_early_red(prec,eta,delta,fp)
2898
else:
2899
A.heuristic(prec,eta,delta,fp)
2900
elif algorithm == 'fpLLL:fast':
2901
if early_red:
2902
A.fast_early_red(prec,eta,delta)
2903
else:
2904
A.fast(prec,eta,delta)
2905
elif algorithm == 'fpLLL:proved':
2906
A.proved(prec,eta,delta)
2907
else:
2908
raise TypeError("algorithm %s not supported"%algorithm)
2909
R = A._sage_()
2910
else:
2911
raise TypeError("algorithm %s not supported"%algorithm)
2912
2913
verbose("LLL finished", tm)
2914
return R
2915
2916
def is_LLL_reduced(self, delta=None, eta=None):
2917
r"""
2918
Return ``True`` if this lattice is
2919
`(\delta, \eta)`-LLL reduced. See ``self.LLL``
2920
for a definition of LLL reduction.
2921
2922
INPUT:
2923
2924
2925
- ``delta`` - parameter as described above (default:
2926
3/4)
2927
2928
- ``eta`` - parameter as described above (default:
2929
0.501)
2930
2931
2932
EXAMPLE::
2933
2934
sage: A = random_matrix(ZZ, 10, 10)
2935
sage: L = A.LLL()
2936
sage: A.is_LLL_reduced()
2937
False
2938
sage: L.is_LLL_reduced()
2939
True
2940
"""
2941
if eta is None:
2942
eta = 0.501
2943
if delta is None:
2944
delta = ZZ(3)/ZZ(4)
2945
2946
if delta <= ZZ(1)/ZZ(4):
2947
raise TypeError("delta must be > 1/4")
2948
elif delta > 1:
2949
raise TypeError("delta must be <= 1")
2950
2951
if eta < 0.5:
2952
raise TypeError("eta must be >= 0.5")
2953
2954
# this is pretty slow
2955
import sage.modules.misc
2956
G, mu = sage.modules.misc.gram_schmidt(self.rows())
2957
#For any $i>j$, we have $|mu_{i, j}| <= \eta$
2958
for e in mu.list():
2959
if e.abs() > eta:
2960
return False
2961
2962
#For any $i<d$, we have $\delta |b_i^*|^2 <= |b_{i+1}^* + mu_{i+1, i} b_i^* |^2$
2963
norms = [G[i].norm()**2 for i in range(len(G))]
2964
for i in xrange(1,self.nrows()):
2965
if norms[i] < (delta - mu[i,i-1]**2) * norms[i-1]:
2966
return False
2967
return True
2968
2969
def prod_of_row_sums(self, cols):
2970
"""
2971
Return the product of the sums of the entries in the submatrix of
2972
self with given columns.
2973
2974
INPUT:
2975
2976
2977
- ``cols`` - a list (or set) of integers representing
2978
columns of self.
2979
2980
2981
OUTPUT: an integer
2982
2983
EXAMPLES::
2984
2985
sage: a = matrix(ZZ,2,3,[1..6]); a
2986
[1 2 3]
2987
[4 5 6]
2988
sage: a.prod_of_row_sums([0,2])
2989
40
2990
sage: (1+3)*(4+6)
2991
40
2992
sage: a.prod_of_row_sums(set([0,2]))
2993
40
2994
"""
2995
cdef Py_ssize_t c, row
2996
cdef mpz_t s, pr
2997
mpz_init(s)
2998
mpz_init(pr)
2999
3000
mpz_set_si(pr, 1)
3001
for row from 0 <= row < self._nrows:
3002
mpz_set_si(s, 0)
3003
for c in cols:
3004
if c<0 or c >= self._ncols:
3005
raise IndexError("matrix column index out of range")
3006
mpz_add(s, s, self._matrix[row][c])
3007
mpz_mul(pr, pr, s)
3008
cdef Integer z
3009
z = PY_NEW(Integer)
3010
mpz_set(z.value, pr)
3011
mpz_clear(s)
3012
mpz_clear(pr)
3013
return z
3014
3015
def _linbox_sparse(self):
3016
cdef Py_ssize_t i, j
3017
v = ['%s %s M'%(self._nrows, self._ncols)]
3018
for i from 0 <= i < self._nrows:
3019
for j from 0 <= j < self._ncols:
3020
if mpz_cmp_si(self._matrix[i][j], 0):
3021
v.append('%s %s %s'%(i+1,j+1,self.get_unsafe(i,j)))
3022
v.append('0 0 0\n')
3023
return '\n'.join(v)
3024
3025
def _linbox_dense(self):
3026
cdef Py_ssize_t i, j
3027
v = ['%s %s x'%(self._nrows, self._ncols)]
3028
for i from 0 <= i < self._nrows:
3029
for j from 0 <= j < self._ncols:
3030
v.append(str(self.get_unsafe(i,j)))
3031
return ' '.join(v)
3032
3033
def rational_reconstruction(self, N):
3034
"""
3035
Use rational reconstruction to lift self to a matrix over the
3036
rational numbers (if possible), where we view self as a matrix
3037
modulo N.
3038
3039
INPUT:
3040
3041
3042
- ``N`` - an integer
3043
3044
3045
OUTPUT:
3046
3047
3048
- ``matrix`` - over QQ or raise a ValueError
3049
3050
3051
EXAMPLES: We create a random 4x4 matrix over ZZ.
3052
3053
::
3054
3055
sage: A = matrix(ZZ, 4, [4, -4, 7, 1, -1, 1, -1, -12, -1, -1, 1, -1, -3, 1, 5, -1])
3056
3057
There isn't a unique rational reconstruction of it::
3058
3059
sage: A.rational_reconstruction(11)
3060
Traceback (most recent call last):
3061
...
3062
ValueError: Rational reconstruction of 4 (mod 11) does not exist.
3063
3064
We throw in a denominator and reduce the matrix modulo 389 - it
3065
does rationally reconstruct.
3066
3067
::
3068
3069
sage: B = (A/3 % 389).change_ring(ZZ)
3070
sage: B.rational_reconstruction(389) == A/3
3071
True
3072
3073
TEST:
3074
3075
Check that ticket #9345 is fixed::
3076
3077
sage: A = random_matrix(ZZ, 3, 3)
3078
sage: A.rational_reconstruction(0)
3079
Traceback (most recent call last):
3080
...
3081
ZeroDivisionError: The modulus cannot be zero
3082
"""
3083
import misc
3084
return misc.matrix_integer_dense_rational_reconstruction(self, N)
3085
3086
def randomize(self, density=1, x=None, y=None, distribution=None, \
3087
nonzero=False):
3088
"""
3089
Randomize ``density`` proportion of the entries of this matrix,
3090
leaving the rest unchanged.
3091
3092
The parameters are the same as the ones for the integer ring's
3093
``random_element`` function.
3094
3095
If ``x`` and ``y`` are given, randomized entries of this matrix have
3096
to be between ``x`` and ``y`` and have density 1.
3097
3098
INPUT:
3099
3100
- ``self`` - a mutable matrix over ZZ
3101
3102
- ``density`` - a float between 0 and 1
3103
3104
- ``x, y`` - if not ``None``, these are passed to the
3105
``ZZ.random_element`` function as the upper and lower endpoints in
3106
the uniform distribution
3107
3108
- ``distribution`` - would also be passed into ``ZZ.random_element``
3109
if given
3110
3111
- ``nonzero`` - bool (default: ``False``); whether the new entries
3112
are guaranteed to be zero
3113
3114
OUTPUT:
3115
3116
- None, the matrix is modified in-place
3117
3118
EXAMPLES::
3119
3120
sage: A = matrix(ZZ, 2,3, [1..6]); A
3121
[1 2 3]
3122
[4 5 6]
3123
sage: A.randomize()
3124
sage: A
3125
[-8 2 0]
3126
[ 0 1 -1]
3127
sage: A.randomize(x=-30,y=30)
3128
sage: A
3129
[ 5 -19 24]
3130
[ 24 23 -9]
3131
"""
3132
density = float(density)
3133
if density <= 0:
3134
return
3135
if density > 1:
3136
density = float(1)
3137
3138
self.check_mutability()
3139
self.clear_cache()
3140
3141
cdef randstate rstate = current_randstate()
3142
3143
cdef Py_ssize_t i, j, k, nc, num_per_row
3144
global state, ZZ
3145
3146
cdef IntegerRing_class the_integer_ring = ZZ
3147
3148
if not nonzero:
3149
# Original code, before adding the ``nonzero`` option.
3150
sig_on()
3151
if density == 1:
3152
for i from 0 <= i < self._nrows*self._ncols:
3153
the_integer_ring._randomize_mpz(self._entries[i], x, y, \
3154
distribution)
3155
else:
3156
nc = self._ncols
3157
num_per_row = int(density * nc)
3158
for i from 0 <= i < self._nrows:
3159
for j from 0 <= j < num_per_row:
3160
k = rstate.c_random()%nc
3161
the_integer_ring._randomize_mpz(self._matrix[i][k], \
3162
x, y, distribution)
3163
sig_off()
3164
else:
3165
# New code, to implement the ``nonzero`` option. Note that this
3166
# code is almost the same as above, the only difference being that
3167
# each entry is set until it's non-zero.
3168
sig_on()
3169
if density == 1:
3170
for i from 0 <= i < self._nrows*self._ncols:
3171
while mpz_sgn(self._entries[i]) == 0:
3172
the_integer_ring._randomize_mpz(self._entries[i], \
3173
x, y, distribution)
3174
else:
3175
nc = self._ncols
3176
num_per_row = int(density * nc)
3177
for i from 0 <= i < self._nrows:
3178
for j from 0 <= j < num_per_row:
3179
k = rstate.c_random() % nc
3180
while mpz_sgn(self._matrix[i][k]) == 0:
3181
the_integer_ring._randomize_mpz(self._matrix[i][k],\
3182
x, y, distribution)
3183
sig_off()
3184
3185
#### Rank
3186
3187
def rank(self):
3188
"""
3189
Return the rank of this matrix.
3190
3191
OUTPUT:
3192
3193
3194
- ``nonnegative integer`` - the rank
3195
3196
3197
.. note::
3198
3199
The rank is cached.
3200
3201
ALGORITHM: First check if the matrix has maxim possible rank by
3202
working modulo one random prime. If not call LinBox's rank
3203
function.
3204
3205
EXAMPLES::
3206
3207
sage: a = matrix(ZZ,2,3,[1..6]); a
3208
[1 2 3]
3209
[4 5 6]
3210
sage: a.rank()
3211
2
3212
sage: a = matrix(ZZ,3,3,[1..9]); a
3213
[1 2 3]
3214
[4 5 6]
3215
[7 8 9]
3216
sage: a.rank()
3217
2
3218
3219
Here's a bigger example - the rank is of course still 2::
3220
3221
sage: a = matrix(ZZ,100,[1..100^2]); a.rank()
3222
2
3223
"""
3224
r = self.fetch('rank')
3225
if not r is None: return r
3226
3227
if self._nrows <= 6 and self._ncols <= 6 and self.height().ndigits() <= 10000:
3228
r = self._rank_pari()
3229
# Can very quickly detect full rank by working modulo p.
3230
r = self._rank_modp()
3231
if r == self._nrows or r == self._ncols:
3232
self.cache('rank', r)
3233
return r
3234
# Detecting full rank didn't work -- use LinBox's general algorithm.
3235
r = self._rank_linbox()
3236
self.cache('rank', r)
3237
return r
3238
3239
def _rank_linbox(self):
3240
"""
3241
Compute the rank of this matrix using Linbox.
3242
"""
3243
self._init_linbox()
3244
cdef unsigned long r
3245
sig_on()
3246
r = linbox.rank()
3247
sig_off()
3248
return Integer(r)
3249
3250
def _rank_modp(self, p=46337):
3251
A = self._mod_int_c(p)
3252
return A.rank()
3253
3254
#### Determinant
3255
3256
def determinant(self, algorithm='default', proof=None, stabilize=2):
3257
r"""
3258
Return the determinant of this matrix.
3259
3260
INPUT:
3261
3262
- ``algorithm``
3263
3264
- ``'default'`` -- use 'pari' when number of rows less than 50;
3265
otherwise, use 'padic'
3266
3267
- ``'padic'`` - uses a p-adic / multimodular
3268
algorithm that relies on code in IML and linbox
3269
3270
- ``'linbox'`` - calls linbox det (you *must* set
3271
proof=False to use this!)
3272
3273
- ``'ntl'`` - calls NTL's det function
3274
3275
- ``'pari'`` - uses PARI
3276
3277
- ``proof`` - bool or None; if None use
3278
proof.linear_algebra(); only relevant for the padic algorithm.
3279
3280
.. note::
3281
3282
It would be *VERY VERY* hard for det to fail even with
3283
proof=False.
3284
3285
- ``stabilize`` - if proof is False, require det to be
3286
the same for this many CRT primes in a row. Ignored if proof is
3287
True.
3288
3289
3290
ALGORITHM: The p-adic algorithm works by first finding a random
3291
vector v, then solving A\*x = v and taking the denominator
3292
`d`. This gives a divisor of the determinant. Then we
3293
compute `\det(A)/d` using a multimodular algorithm and the
3294
Hadamard bound, skipping primes that divide `d`.
3295
3296
TIMINGS: This is perhaps the fastest implementation of determinants
3297
in the world. E.g., for a 500x500 random matrix with 32-bit entries
3298
on a core2 duo 2.6Ghz running OS X, Sage takes 4.12 seconds,
3299
whereas Magma takes 62.87 seconds (both with proof False). With
3300
proof=True on the same problem Sage takes 5.73 seconds. For another
3301
example, a 200x200 random matrix with 1-digit entries takes 4.18
3302
seconds in pari, 0.18 in Sage with proof True, 0.11 in Sage with
3303
proof False, and 0.21 seconds in Magma with proof True and 0.18 in
3304
Magma with proof False.
3305
3306
EXAMPLES::
3307
3308
sage: A = matrix(ZZ,8,8,[3..66])
3309
sage: A.determinant()
3310
0
3311
3312
::
3313
3314
sage: A = random_matrix(ZZ,20,20)
3315
sage: D1 = A.determinant()
3316
sage: A._clear_cache()
3317
sage: D2 = A.determinant(algorithm='ntl')
3318
sage: D1 == D2
3319
True
3320
3321
Next we try the Linbox det. Note that we must have proof=False.
3322
3323
::
3324
3325
sage: A = matrix(ZZ,5,[1,2,3,4,5,4,6,3,2,1,7,9,7,5,2,1,4,6,7,8,3,2,4,6,7])
3326
sage: A.determinant(algorithm='linbox')
3327
Traceback (most recent call last):
3328
...
3329
RuntimeError: you must pass the proof=False option to the determinant command to use LinBox's det algorithm
3330
sage: A.determinant(algorithm='linbox',proof=False)
3331
-21
3332
sage: A._clear_cache()
3333
sage: A.determinant()
3334
-21
3335
3336
A bigger example::
3337
3338
sage: A = random_matrix(ZZ,30)
3339
sage: d = A.determinant()
3340
sage: A._clear_cache()
3341
sage: A.determinant(algorithm='linbox',proof=False) == d
3342
True
3343
"""
3344
d = self.fetch('det')
3345
if not d is None:
3346
return d
3347
if not self.is_square():
3348
raise ValueError("self must be a square matrix")
3349
n = self.nrows()
3350
3351
if n <= 3:
3352
# use generic special cased code.
3353
return matrix_dense.Matrix_dense.determinant(self)
3354
elif n == 4:
3355
return self._det_4x4_unsafe()
3356
3357
if algorithm == 'default':
3358
if n <= 50 and self.height().ndigits() <= 100:
3359
algorithm = 'pari'
3360
else:
3361
algorithm = 'padic'
3362
3363
proof = get_proof_flag(proof, "linear_algebra")
3364
3365
if algorithm == 'padic':
3366
import matrix_integer_dense_hnf
3367
return matrix_integer_dense_hnf.det_padic(self, proof=proof, stabilize=stabilize)
3368
elif algorithm == 'linbox':
3369
if proof:
3370
raise RuntimeError("you must pass the proof=False option to the determinant command to use LinBox's det algorithm")
3371
d = self._det_linbox()
3372
elif algorithm == 'pari':
3373
d = self._det_pari()
3374
elif algorithm == 'ntl':
3375
d = self._det_ntl()
3376
else:
3377
raise TypeError("algorithm '%s' not known"%(algorithm))
3378
3379
self.cache('det', d)
3380
return d
3381
3382
def _det_linbox(self):
3383
"""
3384
Compute the determinant of this matrix using Linbox.
3385
"""
3386
self._init_linbox()
3387
sig_on()
3388
d = linbox.det()
3389
sig_off()
3390
return Integer(d)
3391
3392
cdef _det_4x4_unsafe(self):
3393
"""
3394
Compute the determinant of this matrix using a special
3395
formulation for 4x4 matrices.
3396
3397
TESTS::
3398
3399
sage: A = matrix(ZZ,4,[1,2,3,4,4,3,2,1,0,5,0,1,9,1,2,3])
3400
sage: A.determinant() # indirect doctest
3401
270
3402
"""
3403
cdef Integer d = ZZ(0)
3404
sig_on()
3405
four_dim_det(d.value,self._entries)
3406
sig_off()
3407
return d
3408
3409
def _det_ntl(self):
3410
"""
3411
Compute the determinant of this matrix using NTL.
3412
"""
3413
sig_on()
3414
d = self._ntl_().determinant()
3415
sig_off()
3416
return Integer(d)
3417
3418
#### Rational kernel, via IML
3419
def _rational_kernel_iml(self):
3420
"""
3421
IML: Return the rational kernel of this matrix (acting from the
3422
left), considered as a matrix over QQ. I.e., returns a matrix K
3423
such that self\*K = 0, and the number of columns of K equals the
3424
nullity of self.
3425
3426
AUTHORS:
3427
3428
- William Stein
3429
"""
3430
if self._nrows == 0 or self._ncols == 0:
3431
return self.matrix_space(self._ncols, 0).zero_matrix()
3432
3433
cdef long dim
3434
cdef mpz_t *mp_N
3435
time = verbose('computing null space of %s x %s matrix using IML'%(self._nrows, self._ncols))
3436
sig_on()
3437
dim = nullspaceMP (self._nrows, self._ncols, self._entries, &mp_N)
3438
sig_off()
3439
P = self.matrix_space(self._ncols, dim)
3440
3441
# Now read the answer as a matrix.
3442
cdef Matrix_integer_dense M
3443
M = Matrix_integer_dense.__new__(Matrix_integer_dense, P, None, None, None)
3444
for i from 0 <= i < dim*self._ncols:
3445
mpz_init_set(M._entries[i], mp_N[i])
3446
mpz_clear(mp_N[i])
3447
sage_free(mp_N)
3448
3449
verbose("finished computing null space", time)
3450
M._initialized = True
3451
return M
3452
3453
def _invert_iml(self, use_nullspace=False, check_invertible=True):
3454
"""
3455
Invert this matrix using IML. The output matrix is an integer
3456
matrix and a denominator.
3457
3458
INPUT:
3459
3460
3461
- ``self`` - an invertible matrix
3462
3463
- ``use_nullspace`` - (default: False): whether to
3464
use nullspace algorithm, which is slower, but doesn't require
3465
checking that the matrix is invertible as a precondition.
3466
3467
- ``check_invertible`` - (default: True) whether to
3468
check that the matrix is invertible.
3469
3470
3471
OUTPUT: A, d such that A\*self = d
3472
3473
3474
- ``A`` - a matrix over ZZ
3475
3476
- ``d`` - an integer
3477
3478
3479
ALGORITHM: Uses IML's p-adic nullspace function.
3480
3481
EXAMPLES::
3482
3483
sage: a = matrix(ZZ,3,[1,2,5, 3,7,8, 2,2,1])
3484
sage: b, d = a._invert_iml(); b,d
3485
(
3486
[ 9 -8 19]
3487
[-13 9 -7]
3488
[ 8 -2 -1], 23
3489
)
3490
sage: a*b
3491
[23 0 0]
3492
[ 0 23 0]
3493
[ 0 0 23]
3494
3495
AUTHORS:
3496
3497
- William Stein
3498
"""
3499
if self._nrows != self._ncols:
3500
raise TypeError("self must be a square matrix.")
3501
3502
P = self.parent()
3503
time = verbose('computing inverse of %s x %s matrix using IML'%(self._nrows, self._ncols))
3504
if use_nullspace:
3505
A = self.augment(P.identity_matrix())
3506
K = A._rational_kernel_iml()
3507
d = -K[self._nrows,0]
3508
if K.ncols() != self._ncols or d == 0:
3509
raise ZeroDivisionError("input matrix must be nonsingular")
3510
B = K[:self._nrows]
3511
verbose("finished computing inverse using IML", time)
3512
return B, d
3513
else:
3514
if check_invertible and self.rank() != self._nrows:
3515
raise ZeroDivisionError("input matrix must be nonsingular")
3516
return self._solve_iml(P.identity_matrix(), right=True)
3517
3518
def _solve_right_nonsingular_square(self, B, check_rank=True):
3519
r"""
3520
If self is a matrix `A` of full rank, then this function
3521
returns a vector or matrix `X` such that `A X = B`.
3522
If `B` is a vector then `X` is a vector and if
3523
`B` is a matrix, then `X` is a matrix. The base
3524
ring of `X` is the integers unless a denominator is needed
3525
in which case the base ring is the rational numbers.
3526
3527
.. note::
3528
3529
In Sage one can also write ``A B`` for
3530
``A.solve_right(B)``, i.e., Sage implements the "the
3531
MATLAB/Octave backslash operator".
3532
3533
.. note::
3534
3535
This is currently only implemented when A is square.
3536
3537
INPUT:
3538
3539
3540
- ``B`` - a matrix or vector
3541
3542
- ``check_rank`` - bool (default: True); if True
3543
verify that in fact the rank is full.
3544
3545
3546
OUTPUT: a matrix or vector over `\QQ`
3547
3548
EXAMPLES::
3549
3550
sage: a = matrix(ZZ, 2, [0, -1, 1, 0])
3551
sage: v = vector(ZZ, [2, 3])
3552
sage: a \ v
3553
(3, -2)
3554
3555
Note that the output vector or matrix is always over
3556
`\QQ`.
3557
3558
::
3559
3560
sage: parent(a\v)
3561
Vector space of dimension 2 over Rational Field
3562
3563
We solve a bigger system where the answer is over the rationals.
3564
3565
::
3566
3567
sage: a = matrix(ZZ, 3, 3, [1,2,3,4, 5, 6, 8, -2, 3])
3568
sage: v = vector(ZZ, [1,2,3])
3569
sage: w = a \ v; w
3570
(2/15, -4/15, 7/15)
3571
sage: parent(w)
3572
Vector space of dimension 3 over Rational Field
3573
sage: a * w
3574
(1, 2, 3)
3575
3576
We solve a system where the right hand matrix has multiple
3577
columns.
3578
3579
::
3580
3581
sage: a = matrix(ZZ, 3, 3, [1,2,3,4, 5, 6, 8, -2, 3])
3582
sage: b = matrix(ZZ, 3, 2, [1,5, 2, -3, 3, 0])
3583
sage: w = a \ b; w
3584
[ 2/15 -19/5]
3585
[-4/15 -27/5]
3586
[ 7/15 98/15]
3587
sage: a * w
3588
[ 1 5]
3589
[ 2 -3]
3590
[ 3 0]
3591
3592
TESTS: We create a random 100x100 matrix and solve the
3593
corresponding system, then verify that the result is correct.
3594
(Note that this test is very risky without having a seeded
3595
random number generator!)
3596
3597
::
3598
3599
sage: n = 100
3600
sage: a = random_matrix(ZZ,n)
3601
sage: v = vector(ZZ,n,range(n))
3602
sage: x = a \ v
3603
sage: a * x == v
3604
True
3605
"""
3606
t = verbose('starting IML solve_right...')
3607
# It would probably be much better to rewrite linbox so it
3608
# throws an error instead of ** going into an infinite loop **
3609
# in the non-full rank case. In any case, we do this for now,
3610
# since rank is very fast and infinite loops are evil.
3611
if check_rank and self.rank() < self.nrows():
3612
raise ValueError("self must be of full rank.")
3613
3614
if not self.is_square():
3615
raise NotImplementedError("the input matrix must be square.")
3616
3617
if is_Vector(B):
3618
if self.nrows() != B.degree():
3619
raise ValueError("number of rows of self must equal degree of B.")
3620
elif self.nrows() != B.nrows():
3621
raise ValueError("number of rows of self must equal number of rows of B.")
3622
3623
if self.nrows() == 0:
3624
return B
3625
3626
matrix = True
3627
C = B
3628
if not isinstance(B, Matrix_integer_dense):
3629
if is_Vector(B):
3630
matrix = False
3631
C = self.matrix_space(self.nrows(), 1)(B.list())
3632
else:
3633
raise NotImplementedError
3634
3635
if C.ncols() >= 2*self.ncols():
3636
# likely much better to just invert then multiply
3637
X = self**(-1)*C
3638
verbose('finished solve_right (via inverse)', t)
3639
return X
3640
3641
X, d = self._solve_iml(C, right=True)
3642
if d != 1:
3643
X = (1/d) * X
3644
if not matrix:
3645
# Convert back to a vector
3646
X = (X.base_ring() ** X.nrows())(X.list())
3647
verbose('finished solve_right via IML', t)
3648
return X
3649
3650
def _solve_iml(self, Matrix_integer_dense B, right=True):
3651
"""
3652
Let A equal self be a square matrix. Given B return an integer
3653
matrix C and an integer d such that self C\*A == d\*B if right is
3654
False or A\*C == d\*B if right is True.
3655
3656
OUTPUT:
3657
3658
3659
- ``C`` - integer matrix
3660
3661
- ``d`` - integer denominator
3662
3663
3664
EXAMPLES::
3665
3666
sage: A = matrix(ZZ,4,4,[0, 1, -2, -1, -1, 1, 0, 2, 2, 2, 2, -1, 0, 2, 2, 1])
3667
sage: B = matrix(ZZ,3,4, [-1, 1, 1, 0, 2, 0, -2, -1, 0, -2, -2, -2])
3668
sage: C,d = A._solve_iml(B,right=False); C
3669
[ 6 -18 -15 27]
3670
[ 0 24 24 -36]
3671
[ 4 -12 -6 -2]
3672
3673
::
3674
3675
sage: d
3676
12
3677
3678
::
3679
3680
sage: C*A == d*B
3681
True
3682
3683
::
3684
3685
sage: A = matrix(ZZ,4,4,[0, 1, -2, -1, -1, 1, 0, 2, 2, 2, 2, -1, 0, 2, 2, 1])
3686
sage: B = matrix(ZZ,4,3, [-1, 1, 1, 0, 2, 0, -2, -1, 0, -2, -2, -2])
3687
sage: C,d = A._solve_iml(B)
3688
sage: C
3689
[ 12 40 28]
3690
[-12 -4 -4]
3691
[ -6 -25 -16]
3692
[ 12 34 16]
3693
3694
::
3695
3696
sage: d
3697
12
3698
3699
::
3700
3701
sage: A*C == d*B
3702
True
3703
3704
ALGORITHM: Uses IML.
3705
3706
AUTHORS:
3707
3708
- Martin Albrecht
3709
"""
3710
cdef int i
3711
cdef mpz_t *mp_N, mp_D
3712
cdef Matrix_integer_dense M
3713
cdef Integer D
3714
3715
if self._nrows != self._ncols:
3716
# This is *required* by the IML function we call below.
3717
raise ArithmeticError("self must be a square matrix")
3718
3719
if self.nrows() == 1:
3720
return B, self[0,0]
3721
3722
3723
if right:
3724
if self._ncols != B._nrows:
3725
raise ArithmeticError("B's number of rows must match self's number of columns")
3726
3727
n = self._ncols
3728
m = B._ncols
3729
P = self.matrix_space(n, m)
3730
if self._nrows == 0 or self._ncols == 0:
3731
return P.zero_matrix(), Integer(1)
3732
3733
if m == 0 or n == 0:
3734
return self.new_matrix(nrows = n, ncols = m), Integer(1)
3735
3736
mpz_init(mp_D)
3737
mp_N = <mpz_t *> sage_malloc( n * m * sizeof(mpz_t) )
3738
for i from 0 <= i < n * m:
3739
mpz_init( mp_N[i] )
3740
3741
nonsingSolvLlhsMM(RightSolu, n, m, self._entries, B._entries, mp_N, mp_D)
3742
3743
else: # left
3744
if self._nrows != B._ncols:
3745
raise ArithmeticError("B's number of columns must match self's number of rows")
3746
3747
n = self._ncols
3748
m = B._nrows
3749
3750
P = self.matrix_space(m, n)
3751
if self._nrows == 0 or self._ncols == 0:
3752
return P.zero_matrix(), Integer(1)
3753
3754
if m == 0 or n == 0:
3755
return self.new_matrix(nrows = m, ncols = n), Integer(1)
3756
3757
mpz_init(mp_D)
3758
mp_N = <mpz_t *> sage_malloc( n * m * sizeof(mpz_t) )
3759
for i from 0 <= i < n * m:
3760
mpz_init( mp_N[i] )
3761
3762
nonsingSolvLlhsMM(LeftSolu, n, m, self._entries, B._entries, mp_N, mp_D)
3763
3764
3765
M = Matrix_integer_dense.__new__(Matrix_integer_dense, P, None, None, None)
3766
for i from 0 <= i < n*m:
3767
mpz_init_set(M._entries[i], mp_N[i])
3768
mpz_clear(mp_N[i])
3769
sage_free(mp_N)
3770
M._initialized = True
3771
3772
D = PY_NEW(Integer)
3773
mpz_set(D.value, mp_D)
3774
mpz_clear(mp_D)
3775
3776
return M,D
3777
3778
def _rational_echelon_via_solve(self):
3779
r"""
3780
Computes information that gives the reduced row echelon form (over
3781
QQ!) of a matrix with integer entries.
3782
3783
INPUT:
3784
3785
3786
- ``self`` - a matrix over the integers.
3787
3788
3789
OUTPUT:
3790
3791
3792
- ``pivots`` - ordered list of integers that give the
3793
pivot column positions
3794
3795
- ``nonpivots`` - ordered list of the nonpivot column
3796
positions
3797
3798
- ``X`` - matrix with integer entries
3799
3800
- ``d`` - integer
3801
3802
3803
If you put standard basis vectors in order at the pivot columns,
3804
and put the matrix (1/d)\*X everywhere else, then you get the
3805
reduced row echelon form of self, without zero rows at the bottom.
3806
3807
.. note::
3808
3809
IML is the actual underlying `p`-adic solver that we
3810
use.
3811
3812
AUTHORS:
3813
3814
- William Stein
3815
3816
ALGORITHM: I came up with this algorithm from scratch. As far as I
3817
know it is new. It's pretty simple, but it is ... (fast?!).
3818
3819
Let A be the input matrix.
3820
3821
3822
#. Compute r = rank(A).
3823
3824
#. Compute the pivot columns of the transpose `A^t` of
3825
`A`. One way to do this is to choose a random prime
3826
`p` and compute the row echelon form of `A^t`
3827
modulo `p` (if the number of pivot columns is not equal to
3828
`r`, pick another prime).
3829
3830
#. Let `B` be the submatrix of `A` consisting of
3831
the rows corresponding to the pivot columns found in the previous
3832
step. Note that, aside from zero rows at the bottom, `B`
3833
and `A` have the same reduced row echelon form.
3834
3835
#. Compute the pivot columns of `B`, again possibly by
3836
choosing a random prime `p` as in [2] and computing the
3837
Echelon form modulo `p`. If the number of pivot columns is
3838
not `r`, repeat with a different prime. Note - in this step
3839
it is possible that we mistakenly choose a bad prime `p`
3840
such that there are the right number of pivot columns modulo
3841
`p`, but they are at the wrong positions - e.g., imagine
3842
the augmented matrix `[pI|I]` - modulo `p` we would
3843
miss all the pivot columns. This is OK, since in the next step we
3844
would detect this, as the matrix we would obtain would not be in
3845
echelon form.
3846
3847
#. Let `C` be the submatrix of `B` of pivot
3848
columns. Let `D` be the complementary submatrix of
3849
`B` of all all non-pivot columns. Use a `p`-adic
3850
solver to find the matrix `X` and integer `d` such
3851
that `C (1/d) X=D`. I.e., solve a bunch of linear systems
3852
of the form `Cx = v`, where the columns of `X` are
3853
the solutions.
3854
3855
#. Verify that we had chosen the correct pivot columns. Inspect the
3856
matrix `X` obtained in step 5. If when used to construct
3857
the echelon form of `B`, `X` indeed gives a matrix
3858
in reduced row echelon form, then we are done - output the pivot
3859
columns, `X`, and `d`. To tell if `X` is
3860
correct, do the following: For each column of `X`
3861
(corresponding to non-pivot column `i` of `B`),
3862
read up the column of `X` until finding the first nonzero
3863
position `j`; then verify that `j` is strictly less
3864
than the number of pivot columns of `B` that are strictly
3865
less than `i`. Otherwise, we got the pivots of `B`
3866
wrong - try again starting at step 4, but with a different random
3867
prime.
3868
"""
3869
if self._nrows == 0:
3870
pivots = []
3871
nonpivots = range(self._ncols)
3872
X = self.__copy__()
3873
d = Integer(1)
3874
return pivots, nonpivots, X, d
3875
elif self._ncols == 0:
3876
pivots = []
3877
nonpivots = []
3878
X = self.__copy__()
3879
d = Integer(1)
3880
return pivots, nonpivots, X, d
3881
3882
from matrix_modn_dense import MAX_MODULUS
3883
A = self
3884
# Step 1: Compute the rank
3885
3886
t = verbose('computing rank', level=2, caller_name='p-adic echelon')
3887
r = A.rank()
3888
verbose('done computing rank', level=2, t=t, caller_name='p-adic echelon')
3889
3890
cdef randstate rstate = current_randstate()
3891
3892
if r == self._nrows:
3893
# The input matrix already has full rank.
3894
B = A
3895
else:
3896
# Steps 2 and 3: Extract out a submatrix of full rank.
3897
i = 0
3898
while True:
3899
p = previous_prime(rstate.c_random() % (MAX_MODULUS-15000) + 10000)
3900
P = A._mod_int(p).transpose().pivots()
3901
if len(P) == r:
3902
B = A.matrix_from_rows(P)
3903
break
3904
else:
3905
i += 1
3906
if i == 50:
3907
raise RuntimeError("Bug in _rational_echelon_via_solve in finding linearly independent rows.")
3908
3909
_i = 0
3910
while True:
3911
_i += 1
3912
if _i == 50:
3913
raise RuntimeError("Bug in _rational_echelon_via_solve -- pivot columns keep being wrong.")
3914
3915
# Step 4: Now we instead worry about computing the reduced row echelon form of B.
3916
i = 0
3917
while True:
3918
p = previous_prime(rstate.c_random() % (MAX_MODULUS-15000) + 10000)
3919
pivots = B._mod_int(p).pivots()
3920
if len(pivots) == r:
3921
break
3922
else:
3923
i += 1
3924
if i == 50:
3925
raise RuntimeError("Bug in _rational_echelon_via_solve in finding pivot columns.")
3926
3927
# Step 5: Apply p-adic solver
3928
C = B.matrix_from_columns(pivots)
3929
pivots_ = set(pivots)
3930
non_pivots = [i for i in range(B.ncols()) if not i in pivots_]
3931
D = B.matrix_from_columns(non_pivots)
3932
t = verbose('calling IML solver', level=2, caller_name='p-adic echelon')
3933
X, d = C._solve_iml(D, right=True)
3934
t = verbose('finished IML solver', level=2, caller_name='p-adic echelon', t=t)
3935
3936
# Step 6: Verify that we had chosen the correct pivot columns.
3937
pivots_are_right = True
3938
for z in range(X.ncols()):
3939
if not pivots_are_right:
3940
break
3941
i = non_pivots[z]
3942
np = len([k for k in pivots if k < i])
3943
for j in reversed(range(X.nrows())):
3944
if X[j,z] != 0:
3945
if j < np:
3946
break # we're good -- go on to next column of X
3947
else:
3948
pivots_are_right = False
3949
break
3950
if pivots_are_right:
3951
break
3952
3953
#end while
3954
3955
3956
# Finally, return the answer.
3957
return pivots, non_pivots, X, d
3958
3959
def decomposition(self, **kwds):
3960
"""
3961
Returns the decomposition of the free module on which this matrix A
3962
acts from the right (i.e., the action is x goes to x A), along with
3963
whether this matrix acts irreducibly on each factor. The factors
3964
are guaranteed to be sorted in the same way as the corresponding
3965
factors of the characteristic polynomial, and are saturated as ZZ
3966
modules.
3967
3968
INPUT:
3969
3970
3971
- ``self`` - a matrix over the integers
3972
3973
- ``**kwds`` - these are passed onto to the
3974
decomposition over QQ command.
3975
3976
3977
EXAMPLES::
3978
3979
sage: t = ModularSymbols(11,sign=1).hecke_matrix(2)
3980
sage: w = t.change_ring(ZZ)
3981
sage: w.list()
3982
[3, -1, 0, -2]
3983
"""
3984
F = self.charpoly().factor()
3985
if len(F) == 1:
3986
V = self.base_ring()**self.nrows()
3987
return decomp_seq([(V, F[0][1]==1)])
3988
3989
A = self.change_ring(QQ)
3990
X = A.decomposition(**kwds)
3991
V = ZZ**self.nrows()
3992
if isinstance(X, tuple):
3993
D, E = X
3994
D = [(W.intersection(V), t) for W, t in D]
3995
E = [(W.intersection(V), t) for W, t in E]
3996
return decomp_seq(D), decomp_seq(E)
3997
else:
3998
return decomp_seq([(W.intersection(V), t) for W, t in X])
3999
4000
def _add_row_and_maintain_echelon_form(self, row, pivots):
4001
"""
4002
Assuming self is a full rank n x m matrix in reduced row Echelon
4003
form over ZZ and row is a vector of degree m, this function creates
4004
a new matrix that is the echelon form of self with row appended to
4005
the bottom.
4006
4007
.. warning::
4008
4009
It is assumed that self is in echelon form.
4010
4011
INPUT:
4012
4013
4014
- ``row`` - a vector of degree m over ZZ
4015
4016
- ``pivots`` - a list of integers that are the pivot
4017
columns of self.
4018
4019
4020
OUTPUT:
4021
4022
4023
- ``matrix`` - a matrix of in reduced row echelon form
4024
over ZZ
4025
4026
- ``pivots`` - list of integers
4027
4028
4029
ALGORITHM: For each pivot column of self, we use the extended
4030
Euclidean algorithm to clear the column. The result is a new matrix
4031
B whose row span is the same as self.stack(row), and whose last row
4032
is 0 if and only if row is in the QQ-span of the rows of self. If
4033
row is not in the QQ-span of the rows of self, then row is nonzero
4034
and suitable to be inserted into the top n rows of A to form a new
4035
matrix that is in reduced row echelon form. We then clear that
4036
corresponding new pivot column.
4037
4038
EXAMPLES::
4039
4040
sage: a = matrix(ZZ, 3, [1, 0, 110, 0, 3, 112, 0, 0, 221]); a
4041
[ 1 0 110]
4042
[ 0 3 112]
4043
[ 0 0 221]
4044
sage: a._add_row_and_maintain_echelon_form(vector(ZZ,[1,2,3]),[0,1,2])
4045
(
4046
[1 0 0]
4047
[0 1 0]
4048
[0 0 1], [0, 1, 2]
4049
)
4050
sage: a._add_row_and_maintain_echelon_form(vector(ZZ,[0,0,0]),[0,1,2])
4051
(
4052
[ 1 0 110]
4053
[ 0 3 112]
4054
[ 0 0 221], [0, 1, 2]
4055
)
4056
sage: a = matrix(ZZ, 2, [1, 0, 110, 0, 3, 112])
4057
sage: a._add_row_and_maintain_echelon_form(vector(ZZ,[1,2,3]),[0,1])
4058
(
4059
[ 1 0 110]
4060
[ 0 1 219]
4061
[ 0 0 545], [0, 1, 2]
4062
)
4063
"""
4064
from sage.all import get_memory_usage
4065
cdef Py_ssize_t i, j, piv, n = self._nrows, m = self._ncols
4066
4067
import constructor
4068
4069
# 0. Base case
4070
if self.nrows() == 0:
4071
pos = row.nonzero_positions()
4072
if len(pos) > 0:
4073
pivots = [pos[0]]
4074
if row[pivots[0]] < 0:
4075
row *= -1
4076
else:
4077
pivots = []
4078
return constructor.matrix([row]), pivots
4079
4080
4081
if row == 0:
4082
return self, pivots
4083
# 1. Create a new matrix that has row as the last row.
4084
row_mat = constructor.matrix(row)
4085
A = self.stack(row_mat)
4086
# 2. Working from the left, clear each column to put
4087
# the resulting matrix back in echelon form.
4088
for i, p in enumerate(pivots):
4089
# p is the i-th pivot
4090
b = A[n,p]
4091
if not b:
4092
continue
4093
4094
# (a). Take xgcd of pivot positions in last row and in ith
4095
# row.
4096
4097
# TODO (optimize) -- change to use direct call to gmp and
4098
# no bounds checking!
4099
a = A[i,p]
4100
if not a:
4101
raise ZeroDivisionError("claimed pivot is not a pivot")
4102
if b % a == 0:
4103
# (b) Subtract a multiple of row i from row n.
4104
c = b // a
4105
if c:
4106
for j in range(m):
4107
A[n,j] -= c * A[i,j]
4108
else:
4109
# (b). More elaborate.
4110
# Replace the ith row by s*A[i] + t*A[n], which will
4111
# have g in the i,p position, and replace the last row by
4112
# (b//g)*A[i] - (a//g)*A[n], which will have 0 in the i,p
4113
# position.
4114
g, s, t = a.xgcd(b)
4115
if not g:
4116
raise ZeroDivisionError("claimed pivot is not a pivot (got a 0 gcd)")
4117
4118
row_i = A.row(i)
4119
row_n = A.row(n)
4120
4121
ag = a//g; bg = b//g
4122
4123
new_top = s*row_i + t*row_n
4124
new_bot = bg*row_i - ag*row_n
4125
4126
4127
# OK -- now we have to make sure the top part of the matrix
4128
# but with row i replaced by
4129
# r = s*row_i[j] + t*row_n[j]
4130
# is put in rref. We do this by recursively calling this
4131
# function with the top part of A (all but last row) and the
4132
# row r.
4133
4134
zz = range(A.nrows()-1)
4135
del zz[i]
4136
top_mat = A.matrix_from_rows(zz)
4137
new_pivots = list(pivots)
4138
del new_pivots[i]
4139
4140
top_mat, pivots = top_mat._add_row_and_maintain_echelon_form(new_top, new_pivots)
4141
w = top_mat._add_row_and_maintain_echelon_form(new_bot, pivots)
4142
return w
4143
# 3. If it turns out that the last row is nonzero,
4144
# insert last row in A sliding other rows down.
4145
v = A.row(n)
4146
new_pivots = list(pivots)
4147
if v != 0:
4148
i = v.nonzero_positions()[0]
4149
assert not (i in pivots), 'WARNING: bug in add_row -- i (=%s) should not be a pivot'%i
4150
4151
# If pivot entry is negative negate this row.
4152
if v[i] < 0:
4153
v = -v
4154
4155
# Determine where the last row should be inserted.
4156
new_pivots.append(i)
4157
new_pivots.sort()
4158
import bisect
4159
j = bisect.bisect(pivots, i)
4160
# The new row should go *before* row j, so it becomes row j
4161
A = A.insert_row(j, v)
4162
try:
4163
_clear_columns(A, new_pivots, A.nrows())
4164
except RuntimeError:
4165
raise ZeroDivisionError("mistake in claimed pivots")
4166
if A.row(A.nrows() - 1) == 0:
4167
A = A.matrix_from_rows(range(A.nrows()-1))
4168
return A, new_pivots
4169
4170
#####################################################################################
4171
# Hermite form modulo D
4172
# This code below is by E. Burcin. Thanks!
4173
#####################################################################################
4174
cdef _new_uninitialized_matrix(self, Py_ssize_t nrows, Py_ssize_t ncols):
4175
"""
4176
Return a new matrix over the integers with the given number of rows
4177
and columns. All memory is allocated for this matrix, but its
4178
entries have not yet been filled in.
4179
"""
4180
P = self._parent.matrix_space(nrows, ncols)
4181
return Matrix_integer_dense.__new__(Matrix_integer_dense, P, None, None, None)
4182
4183
def _hnf_mod(self, D):
4184
"""
4185
INPUT:
4186
4187
4188
- ``D`` - a small integer that is assumed to be a
4189
multiple of 2\*det(self)
4190
4191
4192
OUTPUT:
4193
4194
4195
- ``matrix`` - the Hermite normal form of self.
4196
"""
4197
t = verbose('hermite mod %s'%D, caller_name='matrix_integer_dense')
4198
cdef Matrix_integer_dense res = self._new_uninitialized_matrix(self._nrows, self._ncols)
4199
self._hnf_modn(res, D)
4200
verbose('finished hnf mod', t, caller_name='matrix_integer_dense')
4201
return res
4202
4203
cdef int _hnf_modn(Matrix_integer_dense self, Matrix_integer_dense res,
4204
mod_int det) except -1:
4205
"""
4206
Puts self into HNT form modulo det. Changes self in place.
4207
"""
4208
cdef long long *res_l
4209
cdef Py_ssize_t i,j,k
4210
res_l = self._hnf_modn_impl(det, self._nrows, self._ncols)
4211
k = 0
4212
for i from 0 <= i < self._nrows:
4213
for j from 0 <= j < self._ncols:
4214
mpz_init_set_si(res._matrix[i][j], res_l[k])
4215
k += 1
4216
res._initialized = True
4217
sage_free(res_l)
4218
4219
4220
cdef long long* _hnf_modn_impl(Matrix_integer_dense self, mod_int det,
4221
Py_ssize_t nrows, Py_ssize_t ncols) except NULL:
4222
cdef long long *res, *T_ent, **res_rows, **T_rows, *B
4223
cdef Py_ssize_t i, j, k
4224
cdef long long R, mod, T_i_i, T_j_i, c1, c2, q, t
4225
cdef int u, v, d
4226
cdef mpz_t m
4227
4228
# allocate memory for result matrix
4229
res = <long long*> sage_malloc(sizeof(long long)*ncols*nrows)
4230
if res == NULL:
4231
raise MemoryError("out of memory allocating a matrix")
4232
res_rows = <long long**> sage_malloc(sizeof(long long*)*nrows)
4233
if res_rows == NULL:
4234
sage_free(res)
4235
raise MemoryError("out of memory allocating a matrix")
4236
4237
# allocate memory for temporary matrix
4238
T_ent = <long long*> sage_malloc(sizeof(long long)*ncols*nrows)
4239
if T_ent == NULL:
4240
sage_free(res)
4241
sage_free(res_rows)
4242
raise MemoryError("out of memory allocating a matrix")
4243
T_rows = <long long**> sage_malloc(sizeof(long long*)*nrows)
4244
if T_rows == NULL:
4245
sage_free(res)
4246
sage_free(res_rows)
4247
sage_free(T_ent)
4248
raise MemoryError("out of memory allocating a matrix")
4249
4250
# allocate memory for temporary row vector
4251
B = <long long*>sage_malloc(sizeof(long long)*nrows)
4252
if B == NULL:
4253
sage_free(res)
4254
sage_free(res_rows)
4255
sage_free(T_ent)
4256
sage_free(T_rows)
4257
raise MemoryError("out of memory allocating a matrix")
4258
4259
# initialize the row pointers
4260
k = 0
4261
for i from 0 <= i < nrows:
4262
res_rows[i] = res + k
4263
T_rows[i] = T_ent + k
4264
k += nrows
4265
4266
4267
mpz_init(m)
4268
# copy entries from self to temporary matrix
4269
k = 0
4270
for i from 0 <= i < nrows:
4271
for j from 0 <= j < ncols:
4272
mpz_mod_ui(m, self._matrix[i][j], det)
4273
T_ent[k] = mpz_get_si(m)
4274
k += 1
4275
mpz_clear(m)
4276
4277
4278
# initialize variables
4279
i = 0
4280
j = 0
4281
R = det
4282
4283
while 1:
4284
if j == nrows-1:
4285
T_i_i = T_rows[i][i]
4286
d = ai.c_xgcd_int(T_i_i, R, &u, &v)
4287
for k from 0 <= k < i:
4288
res_rows[i][k] = 0
4289
for k from i <= k < ncols:
4290
t = (u*T_rows[i][k])%R
4291
if t < 0:
4292
t += R
4293
res_rows[i][k] = t
4294
if res_rows[i][i] == 0:
4295
res_rows[i][i] = R
4296
d = res_rows[i][i]
4297
for j from 0 <= j < i:
4298
q = res_rows[j][i]/d
4299
for k from i <= k < ncols:
4300
u = (res_rows[j][k] - q*res_rows[i][k])%R
4301
if u < 0:
4302
u += R
4303
res_rows[j][k] = u
4304
4305
R = R/d
4306
i += 1
4307
j = i
4308
if i == nrows :
4309
break # return res
4310
if T_rows[i][i] == 0:
4311
T_rows[i][i] = R
4312
continue
4313
4314
4315
j += 1
4316
if T_rows[j][i] == 0:
4317
continue
4318
4319
T_i_i = T_rows[i][i]
4320
T_j_i = T_rows[j][i]
4321
d = ai.c_xgcd_int(T_i_i , T_j_i, &u, &v)
4322
if d != T_i_i:
4323
for k from i <= k < ncols:
4324
B[k] = (u*T_rows[i][k] + v*T_rows[j][k])
4325
c1 = T_i_i/d
4326
c2 = -T_j_i/d
4327
for k from i <= k < ncols:
4328
T_rows[j][k] = (c1*T_rows[j][k] + c2*T_rows[i][k])%R
4329
if d != T_i_i:
4330
for k from i <= k < ncols:
4331
T_rows[i][k] = B[k]%R
4332
4333
sage_free(B)
4334
sage_free(res_rows)
4335
sage_free(T_ent)
4336
sage_free(T_rows)
4337
return res
4338
4339
4340
#####################################################################################
4341
# operations with matrices
4342
#####################################################################################
4343
def stack(self, bottom, subdivide=False):
4344
r"""
4345
Return the matrix self on top of bottom: [ self ] [ bottom ]
4346
4347
EXAMPLES::
4348
4349
sage: M = Matrix(ZZ, 2, 3, range(6))
4350
sage: N = Matrix(ZZ, 1, 3, [10,11,12])
4351
sage: M.stack(N)
4352
[ 0 1 2]
4353
[ 3 4 5]
4354
[10 11 12]
4355
4356
A vector may be stacked below a matrix. ::
4357
4358
sage: A = matrix(ZZ, 2, 4, range(8))
4359
sage: v = vector(ZZ, 4, range(4))
4360
sage: A.stack(v)
4361
[0 1 2 3]
4362
[4 5 6 7]
4363
[0 1 2 3]
4364
4365
The ``subdivide`` option will add a natural subdivision between
4366
``self`` and ``bottom``. For more details about how subdivisions
4367
are managed when stacking, see
4368
:meth:`sage.matrix.matrix1.Matrix.stack`. ::
4369
4370
sage: A = matrix(ZZ, 3, 4, range(12))
4371
sage: B = matrix(ZZ, 2, 4, range(8))
4372
sage: A.stack(B, subdivide=True)
4373
[ 0 1 2 3]
4374
[ 4 5 6 7]
4375
[ 8 9 10 11]
4376
[-----------]
4377
[ 0 1 2 3]
4378
[ 4 5 6 7]
4379
4380
TESTS:
4381
4382
Stacking a dense matrix atop a sparse one should work::
4383
4384
sage: M = Matrix(ZZ, 2, 3, range(6))
4385
sage: M.is_sparse()
4386
False
4387
sage: N = diagonal_matrix([10,11,12], sparse=True)
4388
sage: N.is_sparse()
4389
True
4390
sage: P = M.stack(N); P
4391
[ 0 1 2]
4392
[ 3 4 5]
4393
[10 0 0]
4394
[ 0 11 0]
4395
[ 0 0 12]
4396
sage: P.is_sparse()
4397
False
4398
"""
4399
if hasattr(bottom, '_vector_'):
4400
bottom = bottom.row()
4401
if self._ncols != bottom.ncols():
4402
raise TypeError("number of columns must be the same")
4403
if not (self._base_ring is bottom.base_ring()):
4404
bottom = bottom.change_ring(self._base_ring)
4405
cdef Matrix_integer_dense other = bottom.dense_matrix()
4406
cdef Matrix_integer_dense M
4407
M = self.new_matrix(nrows = self._nrows + other._nrows, ncols = self.ncols())
4408
cdef Py_ssize_t i, k
4409
k = self._nrows * self._ncols
4410
for i from 0 <= i < k:
4411
mpz_set(M._entries[i], self._entries[i])
4412
for i from 0 <= i < other._nrows * other._ncols:
4413
mpz_set(M._entries[k + i], other._entries[i])
4414
if subdivide:
4415
M._subdivide_on_stack(self, other)
4416
return M
4417
4418
def augment(self, right, subdivide=False):
4419
r"""
4420
Returns a new matrix formed by appending the matrix
4421
(or vector) ``right`` on the right side of ``self``.
4422
4423
INPUT:
4424
4425
- ``right`` - a matrix, vector or free module element, whose
4426
dimensions are compatible with ``self``.
4427
4428
- ``subdivide`` - default: ``False`` - request the resulting
4429
matrix to have a new subdivision, separating ``self`` from ``right``.
4430
4431
OUTPUT:
4432
4433
A new matrix formed by appending ``right`` onto the right side of ``self``.
4434
If ``right`` is a vector (or free module element) then in this context
4435
it is appropriate to consider it as a column vector. (The code first
4436
converts a vector to a 1-column matrix.)
4437
4438
EXAMPLES::
4439
4440
sage: A = matrix(ZZ, 4, 5, range(20))
4441
sage: B = matrix(ZZ, 4, 3, range(12))
4442
sage: A.augment(B)
4443
[ 0 1 2 3 4 0 1 2]
4444
[ 5 6 7 8 9 3 4 5]
4445
[10 11 12 13 14 6 7 8]
4446
[15 16 17 18 19 9 10 11]
4447
4448
A vector may be augmented to a matrix. ::
4449
4450
sage: A = matrix(ZZ, 3, 5, range(15))
4451
sage: v = vector(ZZ, 3, range(3))
4452
sage: A.augment(v)
4453
[ 0 1 2 3 4 0]
4454
[ 5 6 7 8 9 1]
4455
[10 11 12 13 14 2]
4456
4457
The ``subdivide`` option will add a natural subdivision between
4458
``self`` and ``right``. For more details about how subdivisions
4459
are managed when augmenting, see
4460
:meth:`sage.matrix.matrix1.Matrix.augment`. ::
4461
4462
sage: A = matrix(ZZ, 3, 5, range(15))
4463
sage: B = matrix(ZZ, 3, 3, range(9))
4464
sage: A.augment(B, subdivide=True)
4465
[ 0 1 2 3 4| 0 1 2]
4466
[ 5 6 7 8 9| 3 4 5]
4467
[10 11 12 13 14| 6 7 8]
4468
4469
Errors are raised if the sizes are incompatible. ::
4470
4471
sage: A = matrix(ZZ, [[1, 2],[3, 4]])
4472
sage: B = matrix(ZZ, [[10, 20], [30, 40], [50, 60]])
4473
sage: A.augment(B)
4474
Traceback (most recent call last):
4475
...
4476
TypeError: number of rows must be the same, not 2 != 3
4477
"""
4478
if hasattr(right, '_vector_'):
4479
right = right.column()
4480
if self._nrows != right.nrows():
4481
raise TypeError('number of rows must be the same, not {0} != {1}'.format(self._nrows, right.nrows()))
4482
if not (self._base_ring is right.base_ring()):
4483
right = right.change_ring(self._base_ring)
4484
4485
cdef Matrix_integer_dense other = right.dense_matrix()
4486
m = self._nrows
4487
ns, na = self._ncols, other._ncols
4488
n = ns + na
4489
4490
cdef Matrix_integer_dense Z
4491
Z = self.new_matrix(nrows = m, ncols = n)
4492
cdef Py_ssize_t i, j, p, qs, qa
4493
p, qs, qa = 0, 0, 0
4494
for i from 0 <= i < m:
4495
for j from 0 <= j < ns:
4496
mpz_set(Z._entries[p], self._entries[qs])
4497
p = p + 1
4498
qs = qs + 1
4499
for j from 0 <= j < na:
4500
mpz_set(Z._entries[p], other._entries[qa])
4501
p = p + 1
4502
qa = qa + 1
4503
if subdivide:
4504
Z._subdivide_on_augment(self, other)
4505
return Z
4506
4507
def insert_row(self, Py_ssize_t index, row):
4508
"""
4509
Create a new matrix from self with.
4510
4511
INPUT:
4512
4513
- ``index`` - integer
4514
4515
- ``row`` - a vector
4516
4517
EXAMPLES::
4518
4519
sage: X = matrix(ZZ,3,range(9)); X
4520
[0 1 2]
4521
[3 4 5]
4522
[6 7 8]
4523
sage: X.insert_row(1, [1,5,-10])
4524
[ 0 1 2]
4525
[ 1 5 -10]
4526
[ 3 4 5]
4527
[ 6 7 8]
4528
sage: X.insert_row(0, [1,5,-10])
4529
[ 1 5 -10]
4530
[ 0 1 2]
4531
[ 3 4 5]
4532
[ 6 7 8]
4533
sage: X.insert_row(3, [1,5,-10])
4534
[ 0 1 2]
4535
[ 3 4 5]
4536
[ 6 7 8]
4537
[ 1 5 -10]
4538
"""
4539
cdef Matrix_integer_dense res = self._new_uninitialized_matrix(self._nrows + 1, self._ncols)
4540
cdef Py_ssize_t j, k
4541
cdef Integer z
4542
if index < 0:
4543
raise ValueError("index must be nonnegative")
4544
if index > self._nrows:
4545
raise ValueError("index must be less than number of rows")
4546
for j from 0 <= j < self._ncols * index:
4547
mpz_init_set(res._entries[j], self._entries[j])
4548
4549
k = 0
4550
for j from self._ncols * index <= j < self._ncols * (index+1):
4551
z = row[k]
4552
mpz_init_set(res._entries[j], z.value)
4553
k += 1
4554
4555
for j from self._ncols * (index+1) <= j < (self._nrows + 1)*self._ncols:
4556
mpz_init_set(res._entries[j], self._entries[j - self._ncols])
4557
4558
res._initialized = True
4559
return res
4560
4561
def _delete_zero_columns(self):
4562
"""
4563
Return matrix obtained from self by deleting all zero columns along
4564
with the positions of those columns.
4565
4566
OUTPUT: matrix list of integers
4567
4568
EXAMPLES::
4569
4570
sage: a = matrix(ZZ, 2,3, [1,0,3,-1,0,5]); a
4571
[ 1 0 3]
4572
[-1 0 5]
4573
sage: a._delete_zero_columns()
4574
(
4575
[ 1 3]
4576
[-1 5], [1]
4577
)
4578
"""
4579
C = self.columns()
4580
zero_cols = [i for i,v in enumerate(self.columns()) if v.is_zero()]
4581
s = set(zero_cols)
4582
nonzero_cols = [i for i in range(self.ncols()) if not (i in s)]
4583
return self.matrix_from_columns(nonzero_cols), zero_cols
4584
4585
def _insert_zero_columns(self, cols):
4586
"""
4587
Return matrix obtained by self by inserting zero columns so that
4588
the columns with positions specified in cols are all 0.
4589
4590
INPUT:
4591
4592
- ``cols`` - list of nonnegative integers
4593
4594
OUTPUT: matrix
4595
4596
EXAMPLES::
4597
4598
sage: a = matrix(ZZ, 2,3, [1,0,3,-1,0,5]); a
4599
[ 1 0 3]
4600
[-1 0 5]
4601
sage: b, cols = a._delete_zero_columns()
4602
sage: b
4603
[ 1 3]
4604
[-1 5]
4605
sage: cols
4606
[1]
4607
sage: b._insert_zero_columns(cols)
4608
[ 1 0 3]
4609
[-1 0 5]
4610
"""
4611
if len(cols) == 0:
4612
return self
4613
cdef Py_ssize_t i, c, r, nc = max(self._ncols + len(cols), max(cols)+1)
4614
cdef Matrix_integer_dense A = self.new_matrix(self._nrows, nc)
4615
# Now fill in the entries of A that come from self.
4616
cols_set = set(cols)
4617
cols_ins = [j for j in range(nc) if j not in cols_set]
4618
for r from 0 <= r < self._nrows:
4619
i = 0
4620
for c in cols_ins:
4621
# The following does this quickly: A[r,c] = self[r,i]
4622
mpz_set(A._matrix[r][c], self._matrix[r][i])
4623
i += 1
4624
return A
4625
4626
def _factor_out_common_factors_from_each_row(self):
4627
"""
4628
Very very quickly modifies self so that the gcd of the entries in
4629
each row is 1 by dividing each row by the common gcd.
4630
4631
EXAMPLES::
4632
4633
sage: a = matrix(ZZ, 3, [-9, 3, -3, -36, 18, -5, -40, -5, -5, -20, -45, 15, 30, -15, 180])
4634
sage: a
4635
[ -9 3 -3 -36 18]
4636
[ -5 -40 -5 -5 -20]
4637
[-45 15 30 -15 180]
4638
sage: a._factor_out_common_factors_from_each_row()
4639
sage: a
4640
[ -3 1 -1 -12 6]
4641
[ -1 -8 -1 -1 -4]
4642
[ -3 1 2 -1 12]
4643
"""
4644
self.check_mutability()
4645
4646
cdef mpz_t g
4647
mpz_init(g)
4648
cdef Py_ssize_t i, j
4649
cdef mpz_t* row
4650
4651
for i from 0 <= i < self._nrows:
4652
mpz_set_ui(g, 0)
4653
row = self._matrix[i]
4654
for j from 0 <= j < self._ncols:
4655
mpz_gcd(g, g, row[j])
4656
if mpz_cmp_ui(g, 1) == 0:
4657
break
4658
if mpz_cmp_ui(g, 1) != 0:
4659
# divide through row
4660
for j from 0 <= j < self._ncols:
4661
mpz_divexact(row[j], row[j], g)
4662
mpz_clear(g)
4663
4664
def gcd(self):
4665
"""
4666
Return the gcd of all entries of self; very fast.
4667
4668
EXAMPLES::
4669
4670
sage: a = matrix(ZZ,2, [6,15,-6,150])
4671
sage: a.gcd()
4672
3
4673
"""
4674
cdef Integer g = Integer(0)
4675
cdef Py_ssize_t i, j
4676
cdef mpz_t* row
4677
4678
for i from 0 <= i < self._nrows:
4679
row = self._matrix[i]
4680
for j from 0 <= j < self._ncols:
4681
mpz_gcd(g.value, g.value, row[j])
4682
if mpz_cmp_ui(g.value, 1) == 0:
4683
return g
4684
return g
4685
4686
def _change_ring(self, ring):
4687
"""
4688
Return the matrix obtained by coercing the entries of this matrix
4689
into the given ring.
4690
4691
EXAMPLES::
4692
4693
sage: a = matrix(ZZ,2,[1,-7,3,5])
4694
sage: a._change_ring(RDF)
4695
[ 1.0 -7.0]
4696
[ 3.0 5.0]
4697
"""
4698
if ring == RDF:
4699
import change_ring
4700
return change_ring.integer_to_real_double_dense(self)
4701
else:
4702
raise NotImplementedError
4703
4704
def _singular_(self, singular=None):
4705
r"""
4706
Return Singular representation of this integer matrix.
4707
4708
INPUT:
4709
4710
4711
- ``singular`` - Singular interface instance (default:
4712
None)
4713
4714
4715
EXAMPLE::
4716
4717
sage: A = random_matrix(ZZ,3,3)
4718
sage: As = singular(A); As
4719
-8 2 0
4720
0 1 -1
4721
2 1 -95
4722
sage: As.type()
4723
'intmat'
4724
"""
4725
if singular is None:
4726
from sage.interfaces.singular import singular as singular_default
4727
singular = singular_default
4728
4729
name = singular._next_var_name()
4730
values = str(self.list())[1:-1]
4731
singular.eval("intmat %s[%d][%d] = %s"%(name, self.nrows(), self.ncols(), values))
4732
4733
from sage.interfaces.singular import SingularElement
4734
return SingularElement(singular, 'foobar', name, True)
4735
4736
def transpose(self):
4737
"""
4738
Returns the transpose of self, without changing self.
4739
4740
EXAMPLES:
4741
4742
We create a matrix, compute its transpose, and note that the
4743
original matrix is not changed.
4744
4745
::
4746
4747
sage: A = matrix(ZZ,2,3,xrange(6))
4748
sage: type(A)
4749
<type 'sage.matrix.matrix_integer_dense.Matrix_integer_dense'>
4750
sage: B = A.transpose()
4751
sage: print B
4752
[0 3]
4753
[1 4]
4754
[2 5]
4755
sage: print A
4756
[0 1 2]
4757
[3 4 5]
4758
4759
``.T`` is a convenient shortcut for the transpose::
4760
4761
sage: A.T
4762
[0 3]
4763
[1 4]
4764
[2 5]
4765
4766
::
4767
4768
sage: A.subdivide(None, 1); A
4769
[0|1 2]
4770
[3|4 5]
4771
sage: A.transpose()
4772
[0 3]
4773
[---]
4774
[1 4]
4775
[2 5]
4776
"""
4777
cdef Matrix_integer_dense A
4778
A = Matrix_integer_dense.__new__(Matrix_integer_dense,
4779
self._parent.matrix_space(self._ncols,self._nrows),
4780
0,False,False)
4781
cdef Py_ssize_t i,j
4782
sig_on()
4783
for i from 0 <= i < self._nrows:
4784
for j from 0 <= j < self._ncols:
4785
mpz_init_set(A._matrix[j][i], self._matrix[i][j])
4786
sig_off()
4787
A._initialized = True
4788
if self._subdivisions is not None:
4789
row_divs, col_divs = self.subdivisions()
4790
A.subdivide(col_divs, row_divs)
4791
return A
4792
4793
def antitranspose(self):
4794
"""
4795
Returns the antitranspose of self, without changing self.
4796
4797
EXAMPLES::
4798
4799
sage: A = matrix(2,3,range(6))
4800
sage: type(A)
4801
<type 'sage.matrix.matrix_integer_dense.Matrix_integer_dense'>
4802
sage: A.antitranspose()
4803
[5 2]
4804
[4 1]
4805
[3 0]
4806
sage: A
4807
[0 1 2]
4808
[3 4 5]
4809
4810
sage: A.subdivide(1,2); A
4811
[0 1|2]
4812
[---+-]
4813
[3 4|5]
4814
sage: A.antitranspose()
4815
[5|2]
4816
[-+-]
4817
[4|1]
4818
[3|0]
4819
"""
4820
nr , nc = (self._nrows, self._ncols)
4821
4822
cdef Matrix_integer_dense A
4823
A = Matrix_integer_dense.__new__(Matrix_integer_dense,
4824
self._parent.matrix_space(nc,nr),
4825
0,False,False)
4826
4827
cdef Py_ssize_t i,j
4828
cdef Py_ssize_t ri,rj # reversed i and j
4829
sig_on()
4830
ri = nr
4831
for i from 0 <= i < nr:
4832
rj = nc
4833
ri = ri-1
4834
for j from 0 <= j < nc:
4835
rj = rj-1
4836
mpz_init_set(A._matrix[rj][ri], self._matrix[i][j])
4837
sig_off()
4838
A._initialized = True
4839
4840
if self._subdivisions is not None:
4841
row_divs, col_divs = self.subdivisions()
4842
A.subdivide([nc - t for t in reversed(col_divs)],
4843
[nr - t for t in reversed(row_divs)])
4844
return A
4845
4846
def _pari_(self):
4847
"""
4848
Return PARI C-library version of this matrix.
4849
4850
EXAMPLES::
4851
4852
sage: a = matrix(ZZ,2,2,[1,2,3,4])
4853
sage: a._pari_()
4854
[1, 2; 3, 4]
4855
sage: pari(a)
4856
[1, 2; 3, 4]
4857
sage: type(pari(a))
4858
<type 'sage.libs.pari.gen.gen'>
4859
"""
4860
cdef PariInstance P = sage.libs.pari.gen.pari
4861
return P.integer_matrix(self._matrix, self._nrows, self._ncols, 0)
4862
4863
def _det_pari(self, int flag=0):
4864
"""
4865
Determinant of this matrix using Gauss-Bareiss. If (optional)
4866
flag is set to 1, use classical Gaussian elimination.
4867
4868
For efficiency purposes, this det is computed entirely on the
4869
PARI stack then the PARI stack is cleared. This function is
4870
most useful for very small matrices.
4871
4872
EXAMPLES::
4873
4874
sage: matrix(ZZ,3,[1..9])._det_pari()
4875
0
4876
sage: matrix(ZZ,3,[1..9])._det_pari(1)
4877
0
4878
"""
4879
cdef PariInstance P = sage.libs.pari.gen.pari
4880
sig_on()
4881
cdef GEN d = det0(pari_GEN(self), flag)
4882
# now convert d to a Sage integer e
4883
cdef Integer e = Integer()
4884
t_INT_to_ZZ(e.value, d)
4885
P.clear_stack()
4886
return e
4887
4888
def _rank_pari(self):
4889
"""
4890
Rank of this matrix, computed using PARI. The computation is
4891
done entirely on the PARI stack, then the PARI stack is
4892
cleared. This function is most useful for very small
4893
matrices.
4894
4895
EXAMPLES::
4896
sage: matrix(ZZ,3,[1..9])._rank_pari()
4897
2
4898
"""
4899
cdef PariInstance P = sage.libs.pari.gen.pari
4900
sig_on()
4901
cdef long r = rank(pari_GEN(self))
4902
P.clear_stack()
4903
return r
4904
4905
def _hnf_pari(self, int flag=0, bint include_zero_rows=True):
4906
"""
4907
Hermite form of this matrix, computed using PARI. The
4908
computation is done entirely on the PARI stack, then the PARI
4909
stack is cleared. This function is only useful for small
4910
matrices, and can crash on large matrices (e.g., if the PARI
4911
stack overflows).
4912
4913
INPUT:
4914
4915
- ``flag`` -- 0 (default), 1, 3 or 4 (see docstring for
4916
gp.mathnf).
4917
4918
- ``include_zero_rows`` -- boolean. if False, do not include
4919
any of the zero rows at the bottom of the matrix in the
4920
output.
4921
4922
.. NOTE::
4923
4924
In no cases is the transformation matrix returned by this
4925
function.
4926
4927
EXAMPLES::
4928
4929
sage: matrix(ZZ,3,[1..9])._hnf_pari()
4930
[1 2 3]
4931
[0 3 6]
4932
[0 0 0]
4933
sage: matrix(ZZ,3,[1..9])._hnf_pari(1)
4934
[1 2 3]
4935
[0 3 6]
4936
[0 0 0]
4937
sage: matrix(ZZ,3,[1..9])._hnf_pari(3)
4938
[1 2 3]
4939
[0 3 6]
4940
[0 0 0]
4941
sage: matrix(ZZ,3,[1..9])._hnf_pari(4)
4942
[1 2 3]
4943
[0 3 6]
4944
[0 0 0]
4945
4946
Check that ``include_zero_rows=False`` works correctly::
4947
4948
sage: matrix(ZZ,3,[1..9])._hnf_pari(0, include_zero_rows=False)
4949
[1 2 3]
4950
[0 3 6]
4951
sage: matrix(ZZ,3,[1..9])._hnf_pari(1, include_zero_rows=False)
4952
[1 2 3]
4953
[0 3 6]
4954
sage: matrix(ZZ,3,[1..9])._hnf_pari(3, include_zero_rows=False)
4955
[1 2 3]
4956
[0 3 6]
4957
sage: matrix(ZZ,3,[1..9])._hnf_pari(4, include_zero_rows=False)
4958
Traceback (most recent call last):
4959
...
4960
NotImplementedError: Pari flag=4 is currently broken.
4961
4962
The following tests for the Pari bug in trac #12280. Expected
4963
output is ``Mat(1), [1, 0; 0, 1]]``. Once this gets fixed we
4964
can remove the ``NotImplementedError`` below. This is trac
4965
#12346 ::
4966
4967
sage: pari('mathnf(Mat([0,1]), 4)')
4968
[Mat([0, 1]), [1, 0; 0, 1]]
4969
"""
4970
if not include_zero_rows and flag==4:
4971
raise NotImplementedError('Pari flag=4 is currently broken.')
4972
cdef PariInstance P = sage.libs.pari.gen.pari
4973
cdef GEN A
4974
sig_on()
4975
A = P._new_GEN_from_mpz_t_matrix_rotate90(self._matrix, self._nrows, self._ncols)
4976
cdef GEN H = mathnf0(A, flag)
4977
B = self.extract_hnf_from_pari_matrix(H, flag, include_zero_rows)
4978
P.clear_stack() # This calls sig_off()
4979
return B
4980
4981
4982
def _hnf_pari_big(self, int flag=0, bint include_zero_rows=True):
4983
"""
4984
Hermite form of this matrix, computed using PARI.
4985
4986
INPUT:
4987
4988
- ``flag`` -- 0 (default), 1, 3 or 4 (see docstring for
4989
gp.mathnf).
4990
4991
- ``include_zero_rows`` -- boolean. if False, do not include
4992
any of the zero rows at the bottom of the matrix in the
4993
output.
4994
4995
.. NOTE::
4996
4997
In no cases is the transformation matrix returned by this
4998
function.
4999
5000
EXAMPLES::
5001
5002
sage: a = matrix(ZZ,3,3,[1..9])
5003
sage: a._hnf_pari_big(flag=0, include_zero_rows=True)
5004
[1 2 3]
5005
[0 3 6]
5006
[0 0 0]
5007
sage: a._hnf_pari_big(flag=1, include_zero_rows=True)
5008
[1 2 3]
5009
[0 3 6]
5010
[0 0 0]
5011
sage: a._hnf_pari_big(flag=3, include_zero_rows=True)
5012
[1 2 3]
5013
[0 3 6]
5014
[0 0 0]
5015
sage: a._hnf_pari_big(flag=4, include_zero_rows=True)
5016
[1 2 3]
5017
[0 3 6]
5018
[0 0 0]
5019
5020
Check that ``include_zero_rows=False`` works correctly::
5021
5022
sage: matrix(ZZ,3,[1..9])._hnf_pari_big(0, include_zero_rows=False)
5023
[1 2 3]
5024
[0 3 6]
5025
sage: matrix(ZZ,3,[1..9])._hnf_pari_big(1, include_zero_rows=False)
5026
[1 2 3]
5027
[0 3 6]
5028
sage: matrix(ZZ,3,[1..9])._hnf_pari_big(3, include_zero_rows=False)
5029
[1 2 3]
5030
[0 3 6]
5031
sage: matrix(ZZ,3,[1..9])._hnf_pari_big(4, include_zero_rows=False)
5032
Traceback (most recent call last):
5033
...
5034
NotImplementedError: Pari flag=4 is currently broken.
5035
5036
The following tests for the Pari bug in trac #12280. Expected output
5037
is ``Mat(1), [1, 0; 0, 1]]``. If this gets fixed we can remove
5038
the ``NotImplementedError`` below. This is trac #12346 ::
5039
5040
sage: pari('mathnf(Mat([0,1]), 4)')
5041
[Mat([0, 1]), [1, 0; 0, 1]]
5042
"""
5043
if (not include_zero_rows and flag==4):
5044
raise NotImplementedError('Pari flag=4 is currently broken.')
5045
cdef PariInstance P = sage.libs.pari.gen.pari
5046
cdef gen H = P.integer_matrix(self._matrix, self._nrows, self._ncols, 1)
5047
H = H.mathnf(flag)
5048
return self.extract_hnf_from_pari_matrix(H.g, flag, include_zero_rows)
5049
5050
cdef extract_hnf_from_pari_matrix(self, GEN H, int flag, bint include_zero_rows):
5051
# Throw away the transformation matrix (yes, we should later
5052
# code this to keep track of it).
5053
if flag > 0:
5054
H = gel(H,1)
5055
5056
# Figure out how many columns we got back.
5057
cdef Py_ssize_t H_nc = glength(H) # number of columns
5058
# Now get the resulting Hermite form matrix back to Sage, suitably re-arranged.
5059
cdef Matrix_integer_dense B
5060
if include_zero_rows:
5061
B = self.new_matrix()
5062
else:
5063
B = self.new_matrix(nrows=H_nc)
5064
for i in range(self._ncols):
5065
for j in range(H_nc):
5066
t_INT_to_ZZ(B._matrix[j][self._ncols-i-1], gcoeff(H, i+1, H_nc-j))
5067
return B
5068
5069
cdef inline GEN pari_GEN(Matrix_integer_dense B):
5070
r"""
5071
Create the PARI GEN object on the stack defined by the integer
5072
matrix B. This is used internally by the function for conversion
5073
of matrices to PARI.
5074
5075
For internal use only; this directly uses the PARI stack.
5076
One should call ``sig_on()`` before and ``sig_off()`` after.
5077
"""
5078
cdef PariInstance P = sage.libs.pari.gen.pari
5079
cdef GEN A
5080
A = P._new_GEN_from_mpz_t_matrix(B._matrix, B._nrows, B._ncols)
5081
return A
5082
5083
5084
#####################################################################################
5085
5086
cdef _clear_columns(Matrix_integer_dense A, pivots, Py_ssize_t n):
5087
# Clear all columns
5088
cdef Py_ssize_t i, k, p, l, m = A._ncols
5089
cdef mpz_t** matrix = A._matrix
5090
cdef mpz_t c, t
5091
sig_on()
5092
mpz_init(c)
5093
mpz_init(t)
5094
for i from 0 <= i < len(pivots):
5095
p = pivots[i]
5096
for k from 0 <= k < n:
5097
if k != i:
5098
if mpz_cmp_si(matrix[k][p],0):
5099
mpz_fdiv_q(c, matrix[k][p], matrix[i][p])
5100
# subtract off c*v from row k; resulting A[k,i] entry will be < b, hence in Echelon form.
5101
for l from 0 <= l < m:
5102
mpz_mul(t, c, matrix[i][l])
5103
mpz_sub(matrix[k][l], matrix[k][l], t)
5104
mpz_clear(c)
5105
mpz_clear(t)
5106
sig_off()
5107
5108
###############################################################
5109
5110
5111
5112
5113
5114
def _lift_crt(Matrix_integer_dense M, residues, moduli=None):
5115
"""
5116
TESTS::
5117
5118
sage: from sage.matrix.matrix_integer_dense import _lift_crt
5119
sage: T1 = Matrix(Zmod(5), 4, 4, [1, 4, 4, 0, 2, 0, 1, 4, 2, 0, 4, 1, 1, 4, 0, 3])
5120
sage: T2 = Matrix(Zmod(7), 4, 4, [1, 4, 6, 0, 2, 0, 1, 2, 4, 0, 6, 6, 1, 6, 0, 5])
5121
sage: T3 = Matrix(Zmod(11), 4, 4, [1, 4, 10, 0, 2, 0, 1, 9, 8, 0, 10, 6, 1, 10, 0, 9])
5122
sage: _lift_crt(Matrix(ZZ, 4, 4), [T1, T2, T3])
5123
[ 1 4 -1 0]
5124
[ 2 0 1 9]
5125
[-3 0 -1 6]
5126
[ 1 -1 0 -2]
5127
5128
sage: from sage.ext.multi_modular import MultiModularBasis
5129
sage: mm = MultiModularBasis([5,7,11])
5130
sage: _lift_crt(Matrix(ZZ, 4, 4), [T1, T2, T3], mm)
5131
[ 1 4 -1 0]
5132
[ 2 0 1 9]
5133
[-3 0 -1 6]
5134
[ 1 -1 0 -2]
5135
"""
5136
5137
cdef size_t n, i, j, k
5138
cdef Py_ssize_t nr, nc
5139
5140
n = len(residues)
5141
if n == 0: # special case: obviously residues[0] wouldn't make sense here.
5142
return M
5143
nr = residues[0].nrows()
5144
nc = residues[0].ncols()
5145
5146
if moduli is None:
5147
moduli = MultiModularBasis([m.base_ring().order() for m in residues])
5148
else:
5149
if len(residues) != len(moduli):
5150
raise IndexError("Number of residues (%s) does not match number of moduli (%s)"%(len(residues), len(moduli)))
5151
5152
cdef MultiModularBasis mm
5153
mm = moduli
5154
5155
for b in residues:
5156
if not is_Matrix_modn_dense(b):
5157
raise TypeError("Can only perform CRT on list of matrices mod n.")
5158
5159
cdef mod_int **row_list
5160
row_list = <mod_int**>sage_malloc(sizeof(mod_int*) * n)
5161
if row_list == NULL:
5162
raise MemoryError("out of memory allocating multi-modular coefficient list")
5163
5164
sig_on()
5165
for k in range(n):
5166
row_list[k] = <mod_int *>sage_malloc(sizeof(mod_int) * nc)
5167
if row_list[k] == NULL:
5168
raise MemoryError("out of memory allocating multi-modular coefficient list")
5169
5170
for i in range(nr):
5171
for k in range(n):
5172
(<Matrix_modn_dense_template>residues[k])._copy_row_to_mod_int_array(row_list[k],i)
5173
mm.mpz_crt_vec(M._matrix[i], row_list, nc)
5174
5175
for k in range(n):
5176
sage_free(row_list[k])
5177
sage_free(row_list)
5178
5179
sig_off()
5180
return M
5181
5182
#######################################################
5183
5184
# Conclusions:
5185
# On OS X Intel, at least:
5186
# - if log_2(height) >= 0.70 * nrows, use classical
5187
5188
def tune_multiplication(k, nmin=10, nmax=200, bitmin=2,bitmax=64):
5189
"""
5190
Compare various multiplication algorithms.
5191
5192
INPUT:
5193
5194
- ``k`` - integer; affects numbers of trials
5195
5196
- ``nmin`` - integer; smallest matrix to use
5197
5198
- ``nmax`` - integer; largest matrix to use
5199
5200
- ``bitmin`` - integer; smallest bitsize
5201
5202
- ``bitmax`` - integer; largest bitsize
5203
5204
OUTPUT:
5205
5206
- ``prints what doing then who wins`` - multimodular
5207
or classical
5208
5209
EXAMPLES::
5210
5211
sage: from sage.matrix.matrix_integer_dense import tune_multiplication
5212
sage: tune_multiplication(2, nmin=10, nmax=60, bitmin=2,bitmax=8)
5213
10 2 0.2
5214
...
5215
"""
5216
from constructor import random_matrix
5217
from sage.rings.integer_ring import ZZ
5218
for n in range(nmin,nmax,10):
5219
for i in range(bitmin, bitmax, 4):
5220
A = random_matrix(ZZ, n, n, x = 2**i)
5221
B = random_matrix(ZZ, n, n, x = 2**i)
5222
t0 = cputime()
5223
for j in range(k//n + 1):
5224
C = A._multiply_classical(B)
5225
t0 = cputime(t0)
5226
t1 = cputime()
5227
for j in range(k//n+1):
5228
C = A._multiply_multi_modular(B)
5229
t1 = cputime(t1)
5230
print n, i, float(i)/float(n)
5231
if t0 < t1:
5232
print 'classical'
5233
else:
5234
print 'multimod'
5235
5236
5237
##############################################################
5238
# Some people really really really want to make sure their
5239
# 4x4 determinant is really really really fast.
5240
##############################################################
5241
5242
cdef void four_dim_det(mpz_t r,mpz_t *x):
5243
"""
5244
Internal function used in computing determinants of 4x4 matrices.
5245
5246
TESTS::
5247
5248
sage: A = matrix(ZZ,4,[1,0,3,0,4,3,2,1,0,5,0,0,9,1,2,3])
5249
sage: A.determinant() # indirect doctest
5250
25
5251
"""
5252
cdef mpz_t a,b
5253
mpz_init(a)
5254
mpz_init(b)
5255
5256
mpz_mul(a,x[3], x[6] ); mpz_submul(a,x[2], x[7] )
5257
mpz_mul(b,x[9], x[12]); mpz_submul(b,x[8], x[13])
5258
mpz_mul(r,a,b)
5259
mpz_mul(a,x[1], x[7] ); mpz_submul(a,x[3], x[5] )
5260
mpz_mul(b,x[10],x[12]); mpz_submul(b,x[8], x[14])
5261
mpz_addmul(r,a,b)
5262
mpz_mul(a,x[2], x[5] ); mpz_submul(a,x[1], x[6] )
5263
mpz_mul(b,x[11],x[12]); mpz_submul(b,x[8], x[15])
5264
mpz_addmul(r,a,b)
5265
mpz_mul(a,x[3], x[4] ); mpz_submul(a,x[0], x[7] )
5266
mpz_mul(b,x[10],x[13]); mpz_submul(b,x[9], x[14])
5267
mpz_addmul(r,a,b)
5268
mpz_mul(a,x[0], x[6] ); mpz_submul(a,x[2], x[4] )
5269
mpz_mul(b,x[11],x[13]); mpz_submul(b,x[9], x[15])
5270
mpz_addmul(r,a,b)
5271
mpz_mul(a,x[1], x[4] ); mpz_submul(a,x[0], x[5] )
5272
mpz_mul(b,x[11],x[14]); mpz_submul(b,x[10],x[15])
5273
mpz_addmul(r,a,b)
5274
5275
mpz_clear(a)
5276
mpz_clear(b)
5277
5278
#The above was generated by the following Sage code:
5279
#def idx(x):
5280
# return [i for i in range(16) if x[i]]
5281
#
5282
#def Det4Maker():
5283
# Q = PolynomialRing(QQ,['x%s'%ZZ(i).str(16) for i in range(16)])
5284
# M = Matrix(Q,4,4,Q.gens())
5285
# D = M.det()
5286
# Dm = [(m.exponents()[0],D[m]) for m in D.monomials()]
5287
# Dm.sort(reverse=True)
5288
# MM = [[Dm[i],Dm[i+1]] for i in range(0,len(Dm),2)]
5289
#
5290
# S = []
5291
# for j,((t,s),(r,o)) in enumerate(MM):
5292
# a,b,c,d = [ZZ(i).str(16) for i in range(16) if t[i]]
5293
# e,f,g,h = [ZZ(i).str(16) for i in range(16) if r[i]]
5294
# S.append((c+d+g+h,j))
5295
# S.sort(lambda x,y: cmp(x[0],y[0]))
5296
# MM = [MM[s[1]] for s in S]
5297
# MMM = [[MM[i],MM[i+1]] for i in range(0,len(MM),2)]
5298
#
5299
# N = 0
5300
# Cstrux = ""
5301
# Pstrux = ""
5302
# for ((t1,s1),(t2,s2)),((t3,s3),(t4,s4)) in MMM:
5303
# a,b,c,d = idx(t1)
5304
# e,f = idx(t2)[2:]
5305
# h,i = idx(t3)[:2]
5306
#
5307
# if s1 == 1:
5308
# a,b,h,i = h,i,a,b
5309
#
5310
# Pstrux+= 'a = x[%s]*x[%s]; '%(a,b)
5311
# Cstrux+= 'mpz_mul(a,x[%s],x[%s]); '%(a,b)
5312
#
5313
# Pstrux+= 'a-=x[%s]*x[%s]; '%(h,i)
5314
# Cstrux+= 'mpz_submul(a,x[%s],x[%s])\n'%(h,i)
5315
#
5316
# if s4*s1 == 1:
5317
# c,d,e,f = e,f,c,d
5318
#
5319
# Pstrux+= 'b = x[%s]*x[%s]; '%(c,d)
5320
# Cstrux+= 'mpz_mul(b,x[%s],x[%s]); '%(c,d)
5321
#
5322
# Pstrux+= 'b-=x[%s]*x[%s]; '%(e,f)
5323
# Cstrux+= 'mpz_submul(b,x[%s],x[%s])\n'%(e,f)
5324
#
5325
#
5326
# if N:
5327
# Pstrux+= 'r+= a*b\n'
5328
# Cstrux+= 'mpz_addmul(r,a,b)\n'
5329
# else:
5330
# Pstrux+= 'r = a*b\n'
5331
# Cstrux+= 'mpz_mul(r,a,b)\n'
5332
# N = 1
5333
# return Cstrux,Pstrux
5334
#
5335
#print Det4Maker()[0]
5336
5337
#Note, one can prove correctness of the above by setting
5338
# sage: Q = PolynomialRing(QQ,['x%s'%ZZ(i).str(16) for i in range(16)])
5339
# sage: M = Matrix(Q,4,4,Q.gens())
5340
# sage: D = M.det()
5341
# sage: x = Q.gens()
5342
#and then evaluating the contents of Det4Maker()[1]...
5343
# sage: a = x[3]*x[6]; a-=x[2]*x[7]; b = x[9]*x[12]; b-=x[8]*x[13]; r = a*b
5344
# sage: a = x[1]*x[7]; a-=x[3]*x[5]; b = x[10]*x[12]; b-=x[8]*x[14]; r+= a*b
5345
# sage: a = x[2]*x[5]; a-=x[1]*x[6]; b = x[11]*x[12]; b-=x[8]*x[15]; r+= a*b
5346
# sage: a = x[3]*x[4]; a-=x[0]*x[7]; b = x[10]*x[13]; b-=x[9]*x[14]; r+= a*b
5347
# sage: a = x[0]*x[6]; a-=x[2]*x[4]; b = x[11]*x[13]; b-=x[9]*x[15]; r+= a*b
5348
# sage: a = x[1]*x[4]; a-=x[0]*x[5]; b = x[11]*x[14]; b-=x[10]*x[15]; r+= a*b
5349
#and comparing results:
5350
# sage: r-D
5351
# 0
5352
#bingo!
5353
5354
5355