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