Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/matrix/matrix_double_dense.pyx
4059 views
1
"""
2
Dense matrices using a NumPy backend.
3
4
5
This serves as a base class for dense matrices over
6
Real Double Field and Complex Double Field.
7
8
AUTHORS:
9
10
- Jason Grout, Sep 2008: switch to NumPy backend, factored out the Matrix_double_dense class
11
12
- Josh Kantor
13
14
- William Stein: many bug fixes and touch ups.
15
16
17
EXAMPLES::
18
19
sage: b=Mat(RDF,2,3).basis()
20
sage: b[0]
21
[1.0 0.0 0.0]
22
[0.0 0.0 0.0]
23
24
25
We deal with the case of zero rows or zero columns::
26
27
sage: m = MatrixSpace(RDF,0,3)
28
sage: m.zero_matrix()
29
[]
30
31
TESTS::
32
33
sage: a = matrix(RDF,2,range(4), sparse=False)
34
sage: TestSuite(a).run()
35
sage: a = matrix(CDF,2,range(4), sparse=False)
36
sage: TestSuite(a).run()
37
"""
38
39
#*****************************************************************************
40
# Copyright (C) 2004,2005,2006 Joshua Kantor <[email protected]>
41
#
42
# Distributed under the terms of the GNU General Public License (GPL)
43
# as published by the Free Software Foundation; either version 2 of
44
# the License, or (at your option) any later version.
45
# http://www.gnu.org/licenses/
46
#*****************************************************************************
47
48
import math
49
50
import sage.rings.real_double
51
import sage.rings.complex_double
52
53
from matrix cimport Matrix
54
from sage.structure.element cimport ModuleElement,Vector
55
from constructor import matrix
56
from sage.modules.free_module_element import vector
57
cimport sage.structure.element
58
from matrix_space import MatrixSpace
59
from sage.misc.decorators import rename_keyword
60
61
cimport numpy as cnumpy
62
63
numpy=None
64
scipy=None
65
66
# This is for the Numpy C API to work
67
cnumpy.import_array()
68
69
70
cdef class Matrix_double_dense(matrix_dense.Matrix_dense):
71
"""
72
Base class for matrices over the Real Double Field and the Complex
73
Double Field. These are supposed to be fast matrix operations
74
using C doubles. Most operations are implemented using numpy which
75
will call the underlying BLAS on the system.
76
77
This class cannot be instantiated on its own. The numpy matrix
78
creation depends on several variables that are set in the
79
subclasses.
80
81
EXAMPLES::
82
83
sage: m = Matrix(RDF, [[1,2],[3,4]])
84
sage: m**2
85
[ 7.0 10.0]
86
[15.0 22.0]
87
sage: n= m^(-1); n
88
[-2.0 1.0]
89
[ 1.5 -0.5]
90
"""
91
92
93
########################################################################
94
# LEVEL 1 functionality
95
# * __cinit__
96
# * __dealloc__
97
# * __init__
98
# * set_unsafe
99
# * get_unsafe
100
# * __richcmp__ -- always the same
101
# * __hash__ -- always simple
102
########################################################################
103
def __cinit__(self, parent, entries, copy, coerce):
104
"""
105
Set up a new matrix
106
"""
107
matrix_dense.Matrix_dense.__init__(self,parent)
108
return
109
110
def __create_matrix__(self):
111
"""
112
Create a new uninitialized numpy matrix to hold the data for the class.
113
114
This function assumes that self._numpy_dtypeint and
115
self._nrows and self._ncols have already been initialized.
116
117
EXAMPLE:
118
In this example, we throw away the current matrix and make a
119
new uninitialized matrix representing the data for the class.::
120
121
sage: a=matrix(RDF, 3, range(9))
122
sage: a.__create_matrix__()
123
"""
124
cdef cnumpy.npy_intp dims[2]
125
dims[0] = self._nrows
126
dims[1] = self._ncols
127
self._matrix_numpy = cnumpy.PyArray_SimpleNew(2, dims, self._numpy_dtypeint)
128
return
129
130
def __dealloc__(self):
131
""" Deallocate any memory that was initialized."""
132
return
133
134
def __richcmp__(Matrix self, right, int op): # always need for mysterious reasons.
135
return self._richcmp(right, op)
136
137
def __hash__(self):
138
"""
139
Hash this matrix if it's immutable.
140
141
EXAMPLES::
142
143
sage: A = matrix(RDF,3,range(1,10))
144
sage: hash(A)
145
Traceback (most recent call last):
146
...
147
TypeError: mutable matrices are unhashable
148
sage: A.set_immutable()
149
sage: hash(A)
150
88
151
sage: A = matrix(CDF,3,range(1,10))
152
sage: hash(A)
153
Traceback (most recent call last):
154
...
155
TypeError: mutable matrices are unhashable
156
sage: A.set_immutable()
157
sage: hash(A)
158
88
159
"""
160
return self._hash()
161
162
def LU_valid(self):
163
r"""
164
Returns ``True`` if the LU form of this matrix has
165
already been computed.
166
167
EXAMPLES::
168
169
sage: A = random_matrix(RDF,3) ; A.LU_valid()
170
False
171
sage: P, L, U = A.LU()
172
sage: A.LU_valid()
173
True
174
"""
175
return self.fetch('PLU_factors') is not None
176
177
def __init__(self, parent, entries, copy, coerce):
178
"""
179
Fill the matrix with entries.
180
181
The numpy matrix must have already been allocated.
182
183
EXAMPLES::
184
185
sage: matrix(RDF,3,range(9))
186
[0.0 1.0 2.0]
187
[3.0 4.0 5.0]
188
[6.0 7.0 8.0]
189
sage: matrix(CDF,3,3,2)
190
[2.0 0.0 0.0]
191
[0.0 2.0 0.0]
192
[0.0 0.0 2.0]
193
194
TESTS::
195
196
sage: matrix(RDF,3,0)
197
[]
198
sage: matrix(RDF,3,3,0)
199
[0.0 0.0 0.0]
200
[0.0 0.0 0.0]
201
[0.0 0.0 0.0]
202
sage: matrix(RDF,3,3,1)
203
[1.0 0.0 0.0]
204
[0.0 1.0 0.0]
205
[0.0 0.0 1.0]
206
sage: matrix(RDF,3,3,2)
207
[2.0 0.0 0.0]
208
[0.0 2.0 0.0]
209
[0.0 0.0 2.0]
210
sage: matrix(CDF,3,0)
211
[]
212
sage: matrix(CDF,3,3,0)
213
[0.0 0.0 0.0]
214
[0.0 0.0 0.0]
215
[0.0 0.0 0.0]
216
sage: matrix(CDF,3,3,1)
217
[1.0 0.0 0.0]
218
[0.0 1.0 0.0]
219
[0.0 0.0 1.0]
220
sage: matrix(CDF,3,3,range(9))
221
[0.0 1.0 2.0]
222
[3.0 4.0 5.0]
223
[6.0 7.0 8.0]
224
sage: matrix(CDF,2,2,[CDF(1+I)*j for j in range(4)])
225
[ 0.0 1.0 + 1.0*I]
226
[2.0 + 2.0*I 3.0 + 3.0*I]
227
"""
228
cdef Py_ssize_t i,j
229
cdef cnumpy.npy_intp dims[2]
230
dims[0] = self._nrows
231
dims[1] = self._ncols
232
if isinstance(entries,(tuple, list)):
233
if len(entries)!=self._nrows*self._ncols:
234
raise TypeError("entries has wrong length")
235
236
if coerce:
237
for i from 0<=i<self._nrows:
238
for j from 0<=j<self._ncols:
239
self.set_unsafe(i,j,self._python_dtype(entries[i*self._ncols+j]))
240
else:
241
for i from 0<=i<self._nrows:
242
for j from 0<=j<self._ncols:
243
self.set_unsafe(i,j,entries[i*self._ncols+j])
244
245
else:
246
cnumpy.PyArray_FILLWBYTE(self._matrix_numpy, 0)
247
248
if entries is None:
249
z = self._python_dtype(0.0)
250
else:
251
try:
252
z = self._python_dtype(entries)
253
except TypeError:
254
raise TypeError("entries must be coercible to a list or float")
255
if z != 0:
256
if self._nrows != self._ncols:
257
raise TypeError("scalar matrix must be square")
258
for i from 0<=i<self._ncols:
259
self.set_unsafe(i,i,z)
260
261
262
263
cdef set_unsafe(self, Py_ssize_t i, Py_ssize_t j, object value):
264
"""
265
Set the (i,j) entry to value without any bounds checking,
266
mutability checking, etc.
267
"""
268
# We assume that Py_ssize_t is the same as cnumpy.npy_intp
269
270
# We must patch the ndarrayobject.h file so that the SETITEM
271
# macro does not have a semicolon at the end for this to work.
272
# Cython wraps the macro in a function that converts the
273
# returned int to a python object, which leads to compilation
274
# errors because after preprocessing you get something that
275
# looks like "););". This is bug
276
# http://scipy.org/scipy/numpy/ticket/918
277
278
# We call the self._python_dtype function on the value since
279
# numpy does not know how to deal with complex numbers other
280
# than the built-in complex number type.
281
cdef int status
282
status = cnumpy.PyArray_SETITEM(self._matrix_numpy,
283
cnumpy.PyArray_GETPTR2(self._matrix_numpy, i, j),
284
self._python_dtype(value))
285
#TODO: Throw an error if status == -1
286
287
288
cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j):
289
"""
290
Get the (i,j) entry without any bounds checking, etc.
291
"""
292
# We assume that Py_ssize_t is the same as cnumpy.npy_intp
293
return self._sage_dtype(cnumpy.PyArray_GETITEM(self._matrix_numpy,
294
cnumpy.PyArray_GETPTR2(self._matrix_numpy, i, j)))
295
296
cdef Matrix_double_dense _new(self, int nrows=-1, int ncols=-1):
297
"""
298
Return a new uninitialized matrix with same parent as self.
299
300
INPUT:
301
302
nrows -- (default self._nrows) number of rows in returned matrix
303
ncols -- (default self._ncols) number of columns in returned matrix
304
305
"""
306
cdef Matrix_double_dense m
307
if nrows == -1:
308
nrows = self._nrows
309
if ncols == -1:
310
ncols = self._ncols
311
parent = self.matrix_space(nrows, ncols)
312
m = self.__class__.__new__(self.__class__,parent,None,None,None)
313
return m
314
315
316
317
318
########################################################################
319
# LEVEL 2 functionality
320
# * def _pickle
321
# * def _unpickle
322
cpdef ModuleElement _add_(self, ModuleElement right):
323
"""
324
Add two matrices together.
325
326
EXAMPLES::
327
328
sage: A = matrix(RDF,3,range(1,10))
329
sage: A+A
330
[ 2.0 4.0 6.0]
331
[ 8.0 10.0 12.0]
332
[14.0 16.0 18.0]
333
"""
334
if self._nrows == 0 or self._ncols == 0:
335
return self.__copy__()
336
337
cdef Matrix_double_dense M, _right, _left
338
_right = right
339
_left = self
340
341
M = self._new()
342
M._matrix_numpy = _left._matrix_numpy + _right._matrix_numpy
343
return M
344
345
cpdef ModuleElement _sub_(self, ModuleElement right):
346
"""
347
Return self - right
348
349
350
EXAMPLES::
351
352
sage: A = matrix(RDF,3,range(1,10))
353
sage: (A-A).is_zero()
354
True
355
"""
356
if self._nrows == 0 or self._ncols == 0:
357
return self.__copy__()
358
359
cdef Matrix_double_dense M,_right,_left
360
_right = right
361
_left = self
362
363
M = self._new()
364
M._matrix_numpy = _left._matrix_numpy - _right._matrix_numpy
365
return M
366
367
def __neg__(self):
368
"""
369
Negate this matrix
370
371
EXAMPLES::
372
373
sage: A = matrix(RDF,3,range(1,10))
374
sage: -A
375
[-1.0 -2.0 -3.0]
376
[-4.0 -5.0 -6.0]
377
[-7.0 -8.0 -9.0]
378
sage: B = -A ; (A+B).is_zero()
379
True
380
"""
381
if self._nrows == 0 or self._ncols == 0:
382
return self.__copy__()
383
384
cdef Matrix_double_dense M
385
M = self._new()
386
M._matrix_numpy = -self._matrix_numpy
387
return M
388
389
390
# * cdef _cmp_c_impl
391
# x * __copy__
392
# * _list -- list of underlying elements (need not be a copy)
393
# * _dict -- sparse dictionary of underlying elements (need not be a copy)
394
########################################################################
395
# def _pickle(self): #unsure how to implement
396
# def _unpickle(self, data, int version): # use version >= 0 #unsure how to implement
397
######################################################################
398
cdef sage.structure.element.Matrix _matrix_times_matrix_(self, sage.structure.element.Matrix right):
399
"""
400
Multiply self*right as matrices.
401
402
EXAMPLES::
403
404
sage: A = matrix(RDF,3,range(1,10))
405
sage: B = matrix(RDF,3,range(1,13))
406
sage: A*B
407
[ 38.0 44.0 50.0 56.0]
408
[ 83.0 98.0 113.0 128.0]
409
[128.0 152.0 176.0 200.0]
410
"""
411
if self._ncols!=right._nrows:
412
raise IndexError("Number of columns of self must equal number of rows of right")
413
414
if self._nrows == 0 or self._ncols == 0 or right._nrows == 0 or right._ncols == 0:
415
return self.matrix_space(self._nrows, right._ncols).zero_matrix()
416
417
cdef Matrix_double_dense M,_right,_left
418
M = self._new(self._nrows, right._ncols)
419
_right = right
420
_left = self
421
global numpy
422
if numpy is None:
423
import numpy
424
425
M._matrix_numpy = numpy.dot(_left._matrix_numpy, _right._matrix_numpy)
426
return M
427
428
# cdef int _cmp_c_impl(self, Matrix right) except -2:
429
def __invert__(self):
430
"""
431
Invert this matrix.
432
433
EXAMPLES::
434
435
sage: A = Matrix(RDF, [[10, 0], [0, 100]])
436
sage: (~A).det()
437
0.001
438
439
sage: A = matrix(RDF,3,[2,3,5,7,8,9,11,13,17]);A
440
[ 2.0 3.0 5.0]
441
[ 7.0 8.0 9.0]
442
[11.0 13.0 17.0]
443
sage: ~A
444
[ -2.71428571429 -2.0 1.85714285714]
445
[ 2.85714285714 3.0 -2.42857142857]
446
[-0.428571428571 -1.0 0.714285714286]
447
448
Note that if this matrix is (nearly) singular, finding
449
its inverse will not help much and will give slightly different
450
answers on similar platforms depending on the hardware
451
and tuning options given to ATLAS::
452
453
sage: A = matrix(RDF,3,range(1,10));A
454
[1.0 2.0 3.0]
455
[4.0 5.0 6.0]
456
[7.0 8.0 9.0]
457
458
sage: A.determinant() < 10e-12
459
True
460
461
462
TESTS::
463
464
sage: ~Matrix(RDF, 0,0)
465
[]
466
sage: ~Matrix(RDF, 0,3)
467
Traceback (most recent call last):
468
...
469
ArithmeticError: self must be a square matrix
470
"""
471
# see trac ticket 4502 --- there is an issue with the "#random" pragma that needs to be fixed
472
# as for the mathematical side, scipy v0.7 is expected to fix the invertibility failures
473
#
474
# sage: A = Matrix(RDF, [[1, 0], [0, 0]])
475
# sage: A.inverse().det() # random - on some computers, this will be invertible due to numerical error.
476
# Traceback (most recent call last):
477
# ...
478
# LinAlgError: singular matrix
479
# sage: A = matrix(RDF,3,range(1,10));A
480
# [1.0 2.0 3.0]
481
# [4.0 5.0 6.0]
482
# [7.0 8.0 9.0]
483
#
484
# sage: A.determinant() < 10e-12
485
# True
486
# sage: ~A # random - on some computers, this will be invertible due to numerical error.
487
# Traceback (most recent call last):
488
# ...
489
# ZeroDivisionError: singular matrix
490
#
491
if self._nrows != self._ncols:
492
raise ArithmeticError("self must be a square matrix")
493
if self._nrows == 0 and self._ncols == 0:
494
return self.__copy__()
495
496
# Maybe we should cache the (P)LU decomposition and use scipy.lu_solve?
497
cdef Matrix_double_dense M
498
M = self._new()
499
global scipy
500
if scipy is None:
501
import scipy
502
import scipy.linalg
503
from numpy.linalg import LinAlgError
504
try: ## Standard error reporting for Sage.
505
M._matrix_numpy = scipy.linalg.inv(self._matrix_numpy)
506
except LinAlgError:
507
raise ZeroDivisionError("input matrix must be nonsingular")
508
return M
509
510
def __copy__(self):
511
r"""
512
Returns a new copy of this matrix.
513
514
EXAMPLES::
515
516
sage: a = matrix(RDF,1,3, [1,2,-3])
517
sage: a
518
[ 1.0 2.0 -3.0]
519
sage: b = a.__copy__()
520
sage: b
521
[ 1.0 2.0 -3.0]
522
sage: b is a
523
False
524
sage: b == a
525
True
526
sage: b[0,0] = 3
527
sage: a[0,0] # note that a hasn't changed
528
1.0
529
530
::
531
532
sage: copy(MatrixSpace(RDF,0,0,sparse=False).zero_matrix())
533
[]
534
"""
535
if self._nrows == 0 or self._ncols == 0:
536
# Create a brand new empy matrix. This is needed to prevent a
537
# recursive loop: a copy of zero_matrix is asked otherwise.
538
return self.__class__(self.parent(), [], self._nrows, self._ncols)
539
540
cdef Matrix_double_dense A
541
A = self._new(self._nrows, self._ncols)
542
A._matrix_numpy = self._matrix_numpy.copy()
543
if self._subdivisions is not None:
544
A.subdivide(*self.subdivisions())
545
return A
546
547
548
# def _list(self):
549
# def _dict(self):
550
551
552
########################################################################
553
# LEVEL 3 functionality (Optional)
554
# * cdef _sub_
555
# * __deepcopy__
556
# * __invert__
557
# * Matrix windows -- only if you need strassen for that base
558
# * Other functions (list them here):
559
#
560
# compute_LU(self)
561
#
562
########################################################################
563
564
565
def condition(self, p='frob'):
566
r"""
567
Returns the condition number of a square nonsingular matrix.
568
569
Roughly speaking, this is a measure of how sensitive
570
the matrix is to round-off errors in numerical computations.
571
The minimum possible value is 1.0, and larger numbers indicate
572
greater sensitivity.
573
574
INPUT:
575
576
- ``p`` - default: 'frob' - controls which norm is used
577
to compute the condition number, allowable values are
578
'frob' (for the Frobenius norm), integers -2, -1, 1, 2,
579
positive and negative infinity. See output discussion
580
for specifics.
581
582
OUTPUT:
583
584
The condition number of a matrix is the product of a norm
585
of the matrix times the norm of the inverse of the matrix.
586
This requires that the matrix be square and invertible
587
(nonsingular, full rank).
588
589
Returned value is a double precision floating point value
590
in ``RDF``, or ``Infinity``. Row and column sums described below are
591
sums of the absolute values of the entries, where the
592
absolute value of the complex number `a+bi` is `\sqrt{a^2+b^2}`.
593
Singular values are the "diagonal" entries of the "S" matrix in
594
the singular value decomposition.
595
596
- ``p = 'frob'``: the default norm employed in computing
597
the condition number, the Frobenius norm, which for a
598
matrix `A=(a_{ij})` computes
599
600
.. math::
601
602
\left(\sum_{i,j}\left\lvert{a_{i,j}}\right\rvert^2\right)^{1/2}
603
604
- ``p = 'sv'``: the quotient of the maximal and minimal singular value.
605
- ``p = Infinity`` or ``p = oo``: the maximum row sum.
606
- ``p = -Infinity`` or ``p = -oo``: the minimum column sum.
607
- ``p = 1``: the maximum column sum.
608
- ``p = -1``: the minimum column sum.
609
- ``p = 2``: the 2-norm, equal to the maximum singular value.
610
- ``p = -2``: the minimum singular value.
611
612
ALGORITHM:
613
614
Computation is performed by the ``cond()`` function of
615
the SciPy/NumPy library.
616
617
EXAMPLES:
618
619
First over the reals. ::
620
621
sage: A = matrix(RDF, 4, [(1/4)*x^3 for x in range(16)]); A
622
[ 0.0 0.25 2.0 6.75]
623
[ 16.0 31.25 54.0 85.75]
624
[ 128.0 182.25 250.0 332.75]
625
[ 432.0 549.25 686.0 843.75]
626
sage: A.condition()
627
9923.88955...
628
sage: A.condition(p='frob')
629
9923.88955...
630
sage: A.condition(p=Infinity)
631
22738.5
632
sage: A.condition(p=-Infinity)
633
17.5
634
sage: A.condition(p=1)
635
12139.21...
636
sage: A.condition(p=-1)
637
550.0
638
sage: A.condition(p=2)
639
9897.8088...
640
sage: A.condition(p=-2)
641
0.000101032462...
642
643
And over the complex numbers. ::
644
645
sage: B = matrix(CDF, 3, [x + x^2*I for x in range(9)]); B
646
[ 0.0 1.0 + 1.0*I 2.0 + 4.0*I]
647
[ 3.0 + 9.0*I 4.0 + 16.0*I 5.0 + 25.0*I]
648
[6.0 + 36.0*I 7.0 + 49.0*I 8.0 + 64.0*I]
649
sage: B.condition()
650
203.851798...
651
sage: B.condition(p='frob')
652
203.851798...
653
sage: B.condition(p=Infinity)
654
369.55630...
655
sage: B.condition(p=-Infinity)
656
5.46112969...
657
sage: B.condition(p=1)
658
289.251481...
659
sage: B.condition(p=-1)
660
20.4566639...
661
sage: B.condition(p=2)
662
202.653543...
663
sage: B.condition(p=-2)
664
0.00493453005...
665
666
Hilbert matrices are famously ill-conditioned, while
667
an identity matrix can hit the minimum with the right norm. ::
668
669
sage: A = matrix(RDF, 10, [1/(i+j+1) for i in range(10) for j in range(10)])
670
sage: A.condition()
671
1.633...e+13
672
sage: id = identity_matrix(CDF, 10)
673
sage: id.condition(p=1)
674
1.0
675
676
Return values are in `RDF`. ::
677
678
sage: A = matrix(CDF, 2, range(1,5))
679
sage: A.condition() in RDF
680
True
681
682
Rectangular and singular matrices raise errors if p is not 'sv'. ::
683
684
sage: A = matrix(RDF, 2, 3, range(6))
685
sage: A.condition()
686
Traceback (most recent call last):
687
...
688
TypeError: matrix must be square if p is not 'sv', not 2 x 3
689
690
sage: A.condition('sv')
691
7.34...
692
693
sage: A = matrix(QQ, 5, range(25))
694
sage: A.is_singular()
695
True
696
sage: B = A.change_ring(CDF)
697
sage: B.condition()
698
Traceback (most recent call last):
699
...
700
LinAlgError: Singular matrix
701
702
Improper values of ``p`` are caught. ::
703
704
sage: A = matrix(CDF, 2, range(1,5))
705
sage: A.condition(p='bogus')
706
Traceback (most recent call last):
707
...
708
ValueError: condition number 'p' must be +/- infinity, 'frob', 'sv' or an integer, not bogus
709
sage: A.condition(p=632)
710
Traceback (most recent call last):
711
...
712
ValueError: condition number integer values of 'p' must be -2, -1, 1 or 2, not 632
713
714
TESTS:
715
716
Some condition numbers, first by the definition which also exercises
717
:meth:`norm`, then by this method. ::
718
719
sage: A = matrix(CDF, [[1,2,4],[5,3,9],[7,8,6]])
720
sage: c = A.norm(2)*A.inverse().norm(2)
721
sage: d = A.condition(2)
722
sage: abs(c-d) < 1.0e-12
723
True
724
sage: c = A.norm(1)*A.inverse().norm(1)
725
sage: d = A.condition(1)
726
sage: abs(c-d) < 1.0e-12
727
True
728
"""
729
if not self.is_square() and p != 'sv':
730
raise TypeError("matrix must be square if p is not 'sv', not %s x %s" % (self.nrows(), self.ncols()))
731
global numpy
732
if numpy is None:
733
import numpy
734
import sage.rings.infinity
735
import sage.rings.integer
736
import sage.rings.real_double
737
if p == sage.rings.infinity.Infinity:
738
p = numpy.inf
739
elif p == -sage.rings.infinity.Infinity:
740
p = -numpy.inf
741
elif p == 'frob':
742
p = 'fro'
743
elif p == 'sv' :
744
p = None
745
else:
746
try:
747
p = sage.rings.integer.Integer(p)
748
except:
749
raise ValueError("condition number 'p' must be +/- infinity, 'frob', 'sv' or an integer, not %s" % p)
750
if p not in [-2,-1,1,2]:
751
raise ValueError("condition number integer values of 'p' must be -2, -1, 1 or 2, not %s" % p)
752
# may raise a LinAlgError if matrix is singular
753
c = numpy.linalg.cond(self._matrix_numpy, p=p)
754
if c == numpy.inf:
755
return sage.rings.infinity.Infinity
756
else:
757
return sage.rings.real_double.RDF(c)
758
759
def norm(self, p='frob'):
760
r"""
761
Returns the norm of the matrix.
762
763
INPUT:
764
765
- ``p`` - default: 'frob' - controls which norm is computed,
766
allowable values are 'frob' (for the Frobenius norm),
767
integers -2, -1, 1, 2, positive and negative infinity.
768
See output discussion for specifics.
769
770
OUTPUT:
771
772
Returned value is a double precision floating point value
773
in ``RDF``. Row and column sums described below are
774
sums of the absolute values of the entries, where the
775
absolute value of the complex number `a+bi` is `\sqrt{a^2+b^2}`.
776
Singular values are the "diagonal" entries of the "S" matrix in
777
the singular value decomposition.
778
779
- ``p = 'frob'``: the default, the Frobenius norm, which for
780
a matrix `A=(a_{ij})` computes
781
782
.. math::
783
784
\left(\sum_{i,j}\left\lvert{a_{i,j}}\right\rvert^2\right)^{1/2}
785
786
- ``p = Infinity`` or ``p = oo``: the maximum row sum.
787
- ``p = -Infinity`` or ``p = -oo``: the minimum column sum.
788
- ``p = 1``: the maximum column sum.
789
- ``p = -1``: the minimum column sum.
790
- ``p = 2``: the 2-norm, equal to the maximum singular value.
791
- ``p = -2``: the minimum singular value.
792
793
ALGORITHM:
794
795
Computation is performed by the ``norm()`` function of
796
the SciPy/NumPy library.
797
798
EXAMPLES:
799
800
First over the reals. ::
801
802
sage: A = matrix(RDF, 3, range(-3, 6)); A
803
[-3.0 -2.0 -1.0]
804
[ 0.0 1.0 2.0]
805
[ 3.0 4.0 5.0]
806
sage: A.norm()
807
8.30662386...
808
sage: A.norm(p='frob')
809
8.30662386...
810
sage: A.norm(p=Infinity)
811
12.0
812
sage: A.norm(p=-Infinity)
813
3.0
814
sage: A.norm(p=1)
815
8.0
816
sage: A.norm(p=-1)
817
6.0
818
sage: A.norm(p=2)
819
7.99575670...
820
sage: A.norm(p=-2) < 10^-15
821
True
822
823
And over the complex numbers. ::
824
825
sage: B = matrix(CDF, 2, [[1+I, 2+3*I],[3+4*I,3*I]]); B
826
[1.0 + 1.0*I 2.0 + 3.0*I]
827
[3.0 + 4.0*I 3.0*I]
828
sage: B.norm()
829
7.0
830
sage: B.norm(p='frob')
831
7.0
832
sage: B.norm(p=Infinity)
833
8.0
834
sage: B.norm(p=-Infinity)
835
5.01976483...
836
sage: B.norm(p=1)
837
6.60555127...
838
sage: B.norm(p=-1)
839
6.41421356...
840
sage: B.norm(p=2)
841
6.66189877...
842
sage: B.norm(p=-2)
843
2.14921023...
844
845
Since it is invariant under unitary multiplication, the
846
Frobenius norm is equal to the square root of the sum of
847
squares of the singular values. ::
848
849
sage: A = matrix(RDF, 5, range(1,26))
850
sage: f = A.norm(p='frob')
851
sage: U, S, V = A.SVD()
852
sage: s = sqrt(sum([S[i,i]^2 for i in range(5)]))
853
sage: abs(f-s) < 1.0e-12
854
True
855
856
Return values are in `RDF`. ::
857
858
sage: A = matrix(CDF, 2, range(4))
859
sage: A.norm() in RDF
860
True
861
862
Improper values of ``p`` are caught. ::
863
864
sage: A.norm(p='bogus')
865
Traceback (most recent call last):
866
...
867
ValueError: matrix norm 'p' must be +/- infinity, 'frob' or an integer, not bogus
868
sage: A.norm(p=632)
869
Traceback (most recent call last):
870
...
871
ValueError: matrix norm integer values of 'p' must be -2, -1, 1 or 2, not 632
872
"""
873
global numpy
874
if numpy is None:
875
import numpy
876
import sage.rings.infinity
877
import sage.rings.integer
878
import sage.rings.real_double
879
if p == sage.rings.infinity.Infinity:
880
p = numpy.inf
881
elif p == -sage.rings.infinity.Infinity:
882
p = -numpy.inf
883
elif p == 'frob':
884
p = 'fro'
885
else:
886
try:
887
p = sage.rings.integer.Integer(p)
888
except:
889
raise ValueError("matrix norm 'p' must be +/- infinity, 'frob' or an integer, not %s" % p)
890
if not p in [-2,-1,1,2]:
891
raise ValueError("matrix norm integer values of 'p' must be -2, -1, 1 or 2, not %s" % p)
892
return sage.rings.real_double.RDF(numpy.linalg.norm(self._matrix_numpy, ord=p))
893
894
def singular_values(self, eps=None):
895
r"""
896
Returns a sorted list of the singular values of the matrix.
897
898
INPUT:
899
900
- ``eps`` - default: ``None`` - the largest number which
901
will be considered to be zero. May also be set to the
902
string 'auto'. See the discussion below.
903
904
OUTPUT:
905
906
A sorted list of the singular values of the matrix, which are the
907
diagonal entries of the "S" matrix in the SVD decomposition. As such,
908
the values are real and are returned as elements of ``RDF``. The
909
list is sorted with larger values first, and since theory predicts
910
these values are always positive, for a rank-deficient matrix the
911
list should end in zeros (but in practice may not). The length of
912
the list is the minimum of the row count and column count for the
913
matrix.
914
915
The number of non-zero singular values will be the rank of the
916
matrix. However, as a numerical matrix, it is impossible to
917
control the difference between zero entries and very small
918
non-zero entries. As an informed consumer it is up to you
919
to use the output responsibly. We will do our best, and give
920
you the tools to work with the output, but we cannot
921
give you a guarantee.
922
923
With ``eps`` set to ``None`` you will get the raw singular
924
values and can manage them as you see fit. You may also set
925
``eps`` to any positive floating point value you wish. If you
926
set ``eps`` to 'auto' this routine will compute a reasonable
927
cutoff value, based on the size of the matrix, the largest
928
singular value and the smallest nonzero value representable
929
by the 53-bit precision values used. See the discussion
930
at page 268 of [WATKINS]_.
931
932
See the examples for a way to use the "verbose" facility
933
to easily watch the zero cutoffs in action.
934
935
ALGORITHM:
936
937
The singular values come from the SVD decomposition
938
computed by SciPy/NumPy.
939
940
EXAMPLES:
941
942
Singular values close to zero have trailing digits that may vary
943
on different hardware. For exact matrices, the number of non-zero
944
singular values will equal the rank of the matrix. So for some of
945
the doctests we round the small singular values that ideally would
946
be zero, to control the variability across hardware.
947
948
This matrix has a determinant of one. A chain of two or
949
three theorems implies the product of the singular values
950
must also be one. ::
951
952
sage: A = matrix(QQ, [[ 1, 0, 0, 0, 0, 1, 3],
953
... [-2, 1, 1, -2, 0, -4, 0],
954
... [ 1, 0, 1, -4, -6, -3, 7],
955
... [-2, 2, 1, 1, 7, 1, -1],
956
... [-1, 0, -1, 5, 8, 4, -6],
957
... [ 4, -2, -2, 1, -3, 0, 8],
958
... [-2, 1, 0, 2, 7, 3, -4]])
959
sage: A.determinant()
960
1
961
sage: B = A.change_ring(RDF)
962
sage: sv = B.singular_values(); sv
963
[20.5239806589, 8.48683702854, 5.86168134845, 2.44291658993,
964
0.583197014472, 0.269332872866, 0.00255244880761]
965
sage: prod(sv)
966
1.0
967
968
An exact matrix that is obviously not of full rank, and then
969
a computation of the singular values after conversion
970
to an approximate matrix. ::
971
972
sage: A = matrix(QQ, [[1/3, 2/3, 11/3],
973
... [2/3, 1/3, 7/3],
974
... [2/3, 5/3, 27/3]])
975
sage: A.rank()
976
2
977
sage: B = A.change_ring(CDF)
978
sage: sv = B.singular_values()
979
sage: sv[0:2]
980
[10.1973039..., 0.487045871...]
981
sage: sv[2] < 1e-14
982
True
983
984
A matrix of rank 3 over the complex numbers. ::
985
986
sage: A = matrix(CDF, [[46*I - 28, -47*I - 50, 21*I + 51, -62*I - 782, 13*I + 22],
987
... [35*I - 20, -32*I - 46, 18*I + 43, -57*I - 670, 7*I + 3],
988
... [22*I - 13, -23*I - 23, 9*I + 24, -26*I - 347, 7*I + 13],
989
... [-44*I + 23, 41*I + 57, -19*I - 54, 60*I + 757, -11*I - 9],
990
... [30*I - 18, -30*I - 34, 14*I + 34, -42*I - 522, 8*I + 12]])
991
sage: sv = A.singular_values()
992
sage: sv[0:3]
993
[1440.733666, 18.4044034134, 6.83970779714]
994
sage: (10^-15 < sv[3]) and (sv[3] < 10^-13)
995
True
996
sage: (10^-16 < sv[4]) and (sv[4] < 10^-14)
997
True
998
999
A full-rank matrix that is ill-conditioned. We use this to
1000
illustrate ways of using the various possibilities for ``eps``,
1001
including one that is ill-advised. Notice that the automatically
1002
computed cutoff gets this (difficult) example slightly wrong.
1003
This illustrates the impossibility of any automated process always
1004
getting this right. Use with caution and judgement. ::
1005
1006
sage: entries = [1/(i+j+1) for i in range(12) for j in range(12)]
1007
sage: B = matrix(QQ, 12, 12, entries)
1008
sage: B.rank()
1009
12
1010
sage: A = B.change_ring(RDF)
1011
sage: A.condition() > 1.7 * 10^16
1012
True
1013
1014
sage: sv = A.singular_values(eps=None)
1015
sage: [round(sv[i],15) for i in range(12)]
1016
[1.79537205956, 0.380275245955, 0.0447385487522, 0.00372231223789,
1017
0.000233089089022, 1.1163357483e-05, 4.08237611e-07,
1018
1.1228611e-08, 2.25196e-10, 3.111e-12, 2.6e-14, 0.0]
1019
sage: (10^-17 < sv[11]) and (sv[11] < 10^-15)
1020
True
1021
1022
sage: sv = A.singular_values(eps='auto')
1023
sage: [round(sv[i],15) for i in range(12)]
1024
[1.79537205956, 0.380275245955, 0.0447385487522, 0.00372231223789,
1025
0.000233089089022, 1.1163357483e-05, 4.08237611e-07,
1026
1.1228611e-08, 2.25196e-10, 3.111e-12, 2.6e-14, 0.0]
1027
sage: sv[11] == 0.0
1028
True
1029
1030
sage: sv = A.singular_values(eps=1e-4)
1031
sage: [round(sv[i],15) for i in range(12)]
1032
[1.79537205956, 0.380275245955, 0.0447385487522, 0.00372231223789,
1033
0.000233089089022, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
1034
sage: all([sv[i] == 0.0 for i in range(5, 12)])
1035
True
1036
1037
With Sage's "verbose" facility, you can compactly see the cutoff
1038
at work. In any application of this routine, or those that build upon
1039
it, it would be a good idea to conduct this exercise on samples.
1040
We also test here that all the values are returned in `RDF` since
1041
singular values are always real. ::
1042
1043
sage: A = matrix(CDF, 4, range(16))
1044
sage: set_verbose(1)
1045
sage: sv = A.singular_values(eps='auto'); sv
1046
verbose 1 (<module>) singular values,
1047
smallest-non-zero:cutoff:largest-zero,
1048
2.2766...:6.2421...e-14:...
1049
[35.139963659, 2.27661020871, 0.0, 0.0]
1050
sage: set_verbose(0)
1051
1052
sage: all([s in RDF for s in sv])
1053
True
1054
1055
TESTS:
1056
1057
Bogus values of the ``eps`` keyword will be caught. ::
1058
1059
sage: A.singular_values(eps='junk')
1060
Traceback (most recent call last):
1061
...
1062
ValueError: could not convert string to float: junk
1063
1064
REFERENCES:
1065
1066
.. [WATKINS] Watkins, David S. Fundamentals of Matrix Computations,
1067
Third Edition. Wiley, Hoboken, New Jersey, 2010.
1068
1069
AUTHOR:
1070
1071
- Rob Beezer - (2011-02-18)
1072
"""
1073
from sage.misc.misc import verbose
1074
from sage.rings.real_double import RDF
1075
global scipy
1076
# get SVD decomposition, which is a cached quantity
1077
_, S, _ = self.SVD()
1078
diag = min(self._nrows, self._ncols)
1079
sv = [RDF(S[i,i]) for i in range(diag)]
1080
# no cutoff, send raw data back
1081
if eps is None:
1082
verbose("singular values, no zero cutoff specified", level=1)
1083
return sv
1084
# set cutoff as RDF element
1085
if eps == 'auto':
1086
if scipy is None: import scipy
1087
eps = 2*max(self._nrows, self._ncols)*scipy.finfo(float).eps*sv[0]
1088
eps = RDF(eps)
1089
# locate non-zero entries
1090
rank = 0
1091
while rank < diag and sv[rank] > eps:
1092
rank = rank + 1
1093
# capture info for watching zero cutoff behavior at verbose level 1
1094
if rank == 0:
1095
small_nonzero = None
1096
else:
1097
small_nonzero = sv[rank-1]
1098
if rank < diag:
1099
large_zero = sv[rank]
1100
else:
1101
large_zero = None
1102
# convert small values to zero, then done
1103
for i in range(rank, diag):
1104
sv[i] = RDF(0)
1105
verbose("singular values, smallest-non-zero:cutoff:largest-zero, %s:%s:%s" % (small_nonzero, eps, large_zero), level=1)
1106
return sv
1107
1108
def LU(self):
1109
r"""
1110
Returns a decomposition of the (row-permuted) matrix as a product of
1111
a lower-triangular matrix ("L") and an upper-triangular matrix ("U").
1112
1113
OUTPUT:
1114
1115
For an `m\times n` matrix ``A`` this method returns a triple of
1116
immutable matrices ``P, L, U`` such that
1117
1118
- ``P*A = L*U``
1119
- ``P`` is a square permutation matrix, of size `m\times m`,
1120
so is all zeroes, but with exactly a single one in each
1121
row and each column.
1122
- ``L`` is lower-triangular, square of size `m\times m`,
1123
with every diagonal entry equal to one.
1124
- ``U`` is upper-triangular with size `m\times n`, i.e.
1125
entries below the "diagonal" are all zero.
1126
1127
The computed decomposition is cached and returned on
1128
subsequent calls, thus requiring the results to be immutable.
1129
1130
Effectively, ``P`` permutes the rows of ``A``. Then ``L``
1131
can be viewed as a sequence of row operations on this matrix,
1132
where each operation is adding a multiple of a row to a
1133
subsequent row. There is no scaling (thus 1's on the diagonal
1134
of ``L``) and no row-swapping (``P`` does that). As a result
1135
``U`` is close to being the result of Gaussian-elimination.
1136
However, round-off errors can make it hard to determine
1137
the zero entries of ``U``.
1138
1139
.. NOTE::
1140
1141
Sometimes this decomposition is written as ``A=P*L*U``,
1142
where ``P`` represents the inverse permutation and is
1143
the matrix inverse of the ``P`` returned by this method.
1144
The computation of this matrix inverse can be accomplished
1145
quickly with just a transpose as the matrix is orthogonal/unitary.
1146
1147
EXAMPLES::
1148
1149
sage: m = matrix(RDF,4,range(16))
1150
sage: P,L,U = m.LU()
1151
sage: P*m
1152
[12.0 13.0 14.0 15.0]
1153
[ 0.0 1.0 2.0 3.0]
1154
[ 8.0 9.0 10.0 11.0]
1155
[ 4.0 5.0 6.0 7.0]
1156
sage: L*U
1157
[12.0 13.0 14.0 15.0]
1158
[ 0.0 1.0 2.0 3.0]
1159
[ 8.0 9.0 10.0 11.0]
1160
[ 4.0 5.0 6.0 7.0]
1161
1162
Trac 10839 made this routine available for rectangular matrices. ::
1163
1164
sage: A = matrix(RDF, 5, 6, range(30)); A
1165
[ 0.0 1.0 2.0 3.0 4.0 5.0]
1166
[ 6.0 7.0 8.0 9.0 10.0 11.0]
1167
[12.0 13.0 14.0 15.0 16.0 17.0]
1168
[18.0 19.0 20.0 21.0 22.0 23.0]
1169
[24.0 25.0 26.0 27.0 28.0 29.0]
1170
sage: P, L, U = A.LU()
1171
sage: P
1172
[0.0 0.0 0.0 0.0 1.0]
1173
[1.0 0.0 0.0 0.0 0.0]
1174
[0.0 0.0 1.0 0.0 0.0]
1175
[0.0 0.0 0.0 1.0 0.0]
1176
[0.0 1.0 0.0 0.0 0.0]
1177
sage: L.zero_at(0) # Use zero_at(0) to get rid of signed zeros
1178
[ 1.0 0.0 0.0 0.0 0.0]
1179
[ 0.0 1.0 0.0 0.0 0.0]
1180
[ 0.5 0.5 1.0 0.0 0.0]
1181
[0.75 0.25 0.0 1.0 0.0]
1182
[0.25 0.75 0.0 0.0 1.0]
1183
sage: U.zero_at(0) # Use zero_at(0) to get rid of signed zeros
1184
[24.0 25.0 26.0 27.0 28.0 29.0]
1185
[ 0.0 1.0 2.0 3.0 4.0 5.0]
1186
[ 0.0 0.0 0.0 0.0 0.0 0.0]
1187
[ 0.0 0.0 0.0 0.0 0.0 0.0]
1188
[ 0.0 0.0 0.0 0.0 0.0 0.0]
1189
sage: P*A-L*U
1190
[0.0 0.0 0.0 0.0 0.0 0.0]
1191
[0.0 0.0 0.0 0.0 0.0 0.0]
1192
[0.0 0.0 0.0 0.0 0.0 0.0]
1193
[0.0 0.0 0.0 0.0 0.0 0.0]
1194
[0.0 0.0 0.0 0.0 0.0 0.0]
1195
sage: P.transpose()*L*U
1196
[ 0.0 1.0 2.0 3.0 4.0 5.0]
1197
[ 6.0 7.0 8.0 9.0 10.0 11.0]
1198
[12.0 13.0 14.0 15.0 16.0 17.0]
1199
[18.0 19.0 20.0 21.0 22.0 23.0]
1200
[24.0 25.0 26.0 27.0 28.0 29.0]
1201
1202
Trivial cases return matrices of the right size and
1203
characteristics. ::
1204
1205
sage: A = matrix(RDF, 5, 0, entries=0)
1206
sage: P, L, U = A.LU()
1207
sage: P.parent()
1208
Full MatrixSpace of 5 by 5 dense matrices over Real Double Field
1209
sage: L.parent()
1210
Full MatrixSpace of 5 by 5 dense matrices over Real Double Field
1211
sage: U.parent()
1212
Full MatrixSpace of 5 by 0 dense matrices over Real Double Field
1213
sage: P*A-L*U
1214
[]
1215
1216
The results are immutable since they are cached. ::
1217
1218
sage: P, L, U = matrix(RDF, 2, 2, range(4)).LU()
1219
sage: L[0,0] = 0
1220
Traceback (most recent call last):
1221
...
1222
ValueError: matrix is immutable; please change a copy instead (i.e., use copy(M) to change a copy of M).
1223
sage: P[0,0] = 0
1224
Traceback (most recent call last):
1225
...
1226
ValueError: matrix is immutable; please change a copy instead (i.e., use copy(M) to change a copy of M).
1227
sage: U[0,0] = 0
1228
Traceback (most recent call last):
1229
...
1230
ValueError: matrix is immutable; please change a copy instead (i.e., use copy(M) to change a copy of M).
1231
"""
1232
global scipy, numpy
1233
cdef Matrix_double_dense P, L, U
1234
m = self._nrows
1235
n = self._ncols
1236
1237
# scipy fails on trivial cases
1238
if m == 0 or n == 0:
1239
P = self._new(m, m)
1240
for i in range(m):
1241
P[i,i]=1
1242
P.set_immutable()
1243
L = P
1244
U = self._new(m,n)
1245
U.set_immutable()
1246
return P, L, U
1247
1248
PLU = self.fetch('PLU_factors')
1249
if not PLU is None:
1250
return PLU
1251
if scipy is None:
1252
import scipy
1253
import scipy.linalg
1254
if numpy is None:
1255
import numpy
1256
PM, LM, UM = scipy.linalg.lu(self._matrix_numpy)
1257
# Numpy has a different convention than we had with GSL
1258
# So we invert (transpose) the P to match our prior behavior
1259
# TODO: It's an awful waste to store a huge matrix for P, which
1260
# is just a simple permutation, really.
1261
P = self._new(m, m)
1262
L = self._new(m, m)
1263
U = self._new(m, n)
1264
P._matrix_numpy = PM.T.copy()
1265
L._matrix_numpy = numpy.ascontiguousarray(LM)
1266
U._matrix_numpy = numpy.ascontiguousarray(UM)
1267
PLU = (P, L, U)
1268
for M in PLU:
1269
M.set_immutable()
1270
self.cache('PLU_factors', PLU)
1271
return PLU
1272
1273
def eigenspaces_left(self, var='a', algebraic_multiplicity=False):
1274
r"""
1275
Computes the left eigenspaces of a matrix of double precision
1276
real or complex numbers (i.e. RDF or CDF).
1277
1278
.. warning::
1279
1280
This method returns eigenspaces that are all of
1281
dimension one, since it is impossible to ascertain
1282
if the numerical results belong to the same eigenspace.
1283
So this is deprecated in favor of the eigenmatrix routines,
1284
such as :meth:`sage.matrix.matrix2.Matrix.eigenmatrix_right`.
1285
1286
INPUT:
1287
1288
- ``var`` - ignored for numerical matrices
1289
- ``algebraic_multiplicity`` - must be set to ``False``
1290
for numerical matrices, and will raise an error otherwise.
1291
1292
OUTPUT:
1293
1294
Return a list of pairs ``(e, V)`` where ``e`` is a (complex)
1295
eigenvalue and ``V`` is the associated left eigenspace as a
1296
vector space.
1297
1298
No attempt is made to determine if an eigenvalue has multiplicity
1299
greater than one, so all the eigenspaces returned have dimension one.
1300
1301
The SciPy routines used for these computations produce eigenvectors
1302
normalized to have length 1, but on different hardware they may vary
1303
by a sign. So for doctests we have normalized output by creating an
1304
eigenspace with a canonical basis.
1305
1306
EXAMPLES:
1307
1308
This first test simply raises the deprecation warning. ::
1309
1310
sage: A = identity_matrix(RDF, 2)
1311
sage: es = A.eigenspaces_left()
1312
doctest:...: DeprecationWarning: Eigenspaces of RDF/CDF matrices are
1313
deprecated as of Sage version 5.0,
1314
please use "eigenmatrix_left" instead
1315
1316
::
1317
1318
sage: m = matrix(RDF, [[-5, 3, 2, 8],[10, 2, 4, -2],[-1, -10, -10, -17],[-2, 7, 6, 13]])
1319
sage: spectrum = m.eigenspaces_left()
1320
sage: spectrum[0][0]
1321
2.0
1322
sage: (RDF^4).subspace(spectrum[0][1].basis())
1323
Vector space of degree 4 and dimension 1 over Real Double Field
1324
Basis matrix:
1325
[1.0 1.0 1.0 1.0]
1326
1327
sage: e, V = spectrum[2]
1328
sage: v = V.basis()[0]
1329
sage: diff = (v*m).change_ring(CDF) - e*v
1330
sage: abs(abs(diff)) < 1e-14
1331
True
1332
1333
TESTS::
1334
1335
sage: m.eigenspaces_left(algebraic_multiplicity=True)
1336
Traceback (most recent call last):
1337
...
1338
ValueError: algebraic_multiplicity must be set to False for double precision matrices
1339
"""
1340
from sage.misc.misc import deprecation
1341
msg = ('Eigenspaces of RDF/CDF matrices are deprecated as of ',
1342
'Sage version 5.0',
1343
', please use "eigenmatrix_left" instead')
1344
deprecation(''.join(msg))
1345
# For numerical values we leave decisions about
1346
# multiplicity to the calling routine
1347
if algebraic_multiplicity:
1348
raise ValueError("algebraic_multiplicity must be set to False for double precision matrices")
1349
spectrum = self.left_eigenvectors()
1350
pairs = []
1351
for evalue,evectors,_ in spectrum:
1352
evector = evectors[0]
1353
espace = evector.parent().span_of_basis([evector],check=False)
1354
pairs.append((evalue, espace))
1355
return pairs
1356
1357
left_eigenspaces = eigenspaces_left
1358
1359
def eigenspaces_right(self, var='a', algebraic_multiplicity=False):
1360
r"""
1361
Computes the right eigenspaces of a matrix of double precision
1362
real or complex numbers (i.e. RDF or CDF).
1363
1364
.. warning::
1365
1366
This method returns eigenspaces that are all of
1367
dimension one, since it is impossible to ascertain
1368
if the numerical results belong to the same eigenspace.
1369
So this is deprecated in favor of the eigenmatrix routines,
1370
such as :meth:`sage.matrix.matrix2.Matrix.eigenmatrix_right`.
1371
1372
INPUT:
1373
1374
- ``var`` - ignored for numerical matrices
1375
- ``algebraic_multiplicity`` - must be set to ``False``
1376
for numerical matrices, and will raise an error otherwise.
1377
1378
OUTPUT:
1379
1380
Return a list of pairs ``(e, V)`` where ``e`` is a (complex)
1381
eigenvalue and ``V`` is the associated right eigenspace as a
1382
vector space.
1383
1384
No attempt is made to determine if an eigenvalue has multiplicity
1385
greater than one, so all the eigenspaces returned have dimension one.
1386
1387
The SciPy routines used for these computations produce eigenvectors
1388
normalized to have length 1, but on different hardware they may vary
1389
by a sign. So for doctests we have normalized output by creating an
1390
eigenspace with a canonical basis.
1391
1392
1393
EXAMPLES:
1394
1395
This first test simply raises the deprecation warning. ::
1396
1397
sage: A = identity_matrix(RDF, 2)
1398
sage: es = A.eigenspaces_right()
1399
doctest:...: DeprecationWarning: Eigenspaces of RDF/CDF matrices are
1400
deprecated as of Sage version 5.0,
1401
please use "eigenmatrix_right" instead
1402
1403
::
1404
1405
sage: m = matrix(RDF, [[-9, -14, 19, -74],[-1, 2, 4, -11],[-4, -12, 6, -32],[0, -2, -1, 1]])
1406
sage: m
1407
[ -9.0 -14.0 19.0 -74.0]
1408
[ -1.0 2.0 4.0 -11.0]
1409
[ -4.0 -12.0 6.0 -32.0]
1410
[ 0.0 -2.0 -1.0 1.0]
1411
sage: spectrum = m.eigenspaces_right()
1412
sage: spectrum[0][0]
1413
2.0
1414
sage: (RDF^4).subspace(spectrum[0][1].basis())
1415
Vector space of degree 4 and dimension 1 over Real Double Field
1416
Basis matrix:
1417
[ 1.0 -2.0 3.0 1.0]
1418
1419
sage: e, V = spectrum[2]
1420
sage: v = V.basis()[0]
1421
sage: diff = (m*v).change_ring(CDF) - e*v
1422
sage: abs(abs(diff)) < 3e-14
1423
True
1424
1425
TESTS::
1426
1427
sage: m.eigenspaces_right(algebraic_multiplicity=True)
1428
Traceback (most recent call last):
1429
...
1430
ValueError: algebraic_multiplicity must be set to False for double precision matrices
1431
"""
1432
from sage.misc.misc import deprecation
1433
msg = ('Eigenspaces of RDF/CDF matrices are deprecated as of ',
1434
'Sage version 5.0',
1435
', please use "eigenmatrix_right" instead')
1436
deprecation(''.join(msg))
1437
# For numerical values we leave decisions about
1438
# multiplicity to the calling routine
1439
if algebraic_multiplicity:
1440
raise ValueError("algebraic_multiplicity must be set to False for double precision matrices")
1441
spectrum = self.right_eigenvectors()
1442
pairs = []
1443
for evalue,evectors,_ in spectrum:
1444
evector = evectors[0]
1445
espace = evector.parent().span_of_basis([evector],check=False)
1446
pairs.append((evalue, espace))
1447
return pairs
1448
1449
right_eigenspaces = eigenspaces_right
1450
1451
def eigenvalues(self, algorithm='default', tol=None):
1452
r"""
1453
Returns a list of eigenvalues.
1454
1455
1456
INPUT:
1457
1458
- ``self`` - a square matrix
1459
1460
- ``algorithm`` - default: ``'default'``
1461
1462
- ``'default'`` - applicable to any matrix
1463
with double-precision floating point entries.
1464
Uses the :meth:`~scipy.linalg.eigvals` method from SciPy.
1465
1466
- ``'symmetric'`` - converts the matrix into a real matrix
1467
(i.e. with entries from :class:`~sage.rings.real_double.RDF`),
1468
then applies the algorithm for Hermitian matrices. This
1469
algorithm can be significantly faster than the
1470
``'default'`` algorithm.
1471
1472
- ``'hermitian'`` - uses the :meth:`~scipy.linalg.eigh` method
1473
from SciPy, which applies only to real symmetric or complex
1474
Hermitian matrices. Since Hermitian is defined as a matrix
1475
equaling its conjugate-transpose, for a matrix with real
1476
entries this property is equivalent to being symmetric.
1477
This algorithm can be significantly faster than the
1478
``'default'`` algorithm.
1479
1480
- ``'tol'`` - default: ``None`` - if set to a value other than
1481
``None`` this is interpreted as a small real number used to aid in
1482
grouping eigenvalues that are numerically similar. See the output
1483
description for more information.
1484
1485
.. WARNING::
1486
1487
When using the ``'symmetric'`` or ``'hermitian'`` algorithms,
1488
no check is made on the input matrix, and only the entries below,
1489
and on, the main diagonal are employed in the computation.
1490
1491
Methods such as :meth:`is_symmetric` and :meth:`is_hermitian`
1492
could be used to verify this beforehand.
1493
1494
OUTPUT:
1495
1496
Default output for a square matrix of size $n$ is a list of $n$
1497
eigenvalues from the complex double field,
1498
:class:`~sage.rings.complex_double.CDF`. If the ``'symmetric'``
1499
or ``'hermitian'`` algorithms are chosen, the returned eigenvalues
1500
are from the real double field,
1501
:class:`~sage.rings.real_double.RDF`.
1502
1503
If a tolerance is specified, an attempt is made to group eigenvalues
1504
that are numerically similar. The return is then a list of pairs,
1505
where each pair is an eigenvalue followed by its multiplicity.
1506
The eigenvalue reported is the mean of the eigenvalues computed,
1507
and these eigenvalues are contained in an interval (or disk) whose
1508
radius is less than ``5*tol`` for $n < 10,000$ in the worst case.
1509
1510
More precisely, for an $n\times n$ matrix, the diameter of the
1511
interval containing similar eigenvalues could be as large as sum
1512
of the reciprocals of the first $n$ integers times ``tol``.
1513
1514
.. WARNING::
1515
1516
Use caution when using the ``tol`` parameter to group
1517
eigenvalues. See the examples below to see how this can go wrong.
1518
1519
EXAMPLES::
1520
1521
sage: m = matrix(RDF, 2, 2, [1,2,3,4])
1522
sage: ev = m.eigenvalues(); ev
1523
[-0.372281323..., 5.37228132...]
1524
sage: ev[0].parent()
1525
Complex Double Field
1526
1527
sage: m = matrix(RDF, 2, 2, [0,1,-1,0])
1528
sage: m.eigenvalues(algorithm='default')
1529
[1.0*I, -1.0*I]
1530
1531
sage: m = matrix(CDF, 2, 2, [I,1,-I,0])
1532
sage: m.eigenvalues()
1533
[-0.624810533... + 1.30024259...*I, 0.624810533... - 0.30024259...*I]
1534
1535
The adjacency matrix of a graph will be symmetric, and the
1536
eigenvalues will be real. ::
1537
1538
sage: A = graphs.PetersenGraph().adjacency_matrix()
1539
sage: A = A.change_ring(RDF)
1540
sage: ev = A.eigenvalues(algorithm='symmetric'); ev
1541
[-2.0, -2.0, -2.0, -2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 3.0]
1542
sage: ev[0].parent()
1543
Real Double Field
1544
1545
The matrix ``A`` is "random", but the construction of ``B``
1546
provides a positive-definite Hermitian matrix. Note that
1547
the eigenvalues of a Hermitian matrix are real, and the
1548
eigenvalues of a positive-definite matrix will be positive. ::
1549
1550
sage: A = matrix([[ 4*I + 5, 8*I + 1, 7*I + 5, 3*I + 5],
1551
... [ 7*I - 2, -4*I + 7, -2*I + 4, 8*I + 8],
1552
... [-2*I + 1, 6*I + 6, 5*I + 5, -I - 4],
1553
... [ 5*I + 1, 6*I + 2, I - 4, -I + 3]])
1554
sage: B = (A*A.conjugate_transpose()).change_ring(CDF)
1555
sage: ev = B.eigenvalues(algorithm='hermitian'); ev
1556
[2.68144025..., 49.5167998..., 274.086188..., 390.71557...]
1557
sage: ev[0].parent()
1558
Real Double Field
1559
1560
A tolerance can be given to aid in grouping eigenvalues that
1561
are similar numerically. However, if the parameter is too small
1562
it might split too finely. Too large, and it can go wrong very
1563
badly. Use with care. ::
1564
1565
sage: G = graphs.PetersenGraph()
1566
sage: G.spectrum()
1567
[3, 1, 1, 1, 1, 1, -2, -2, -2, -2]
1568
1569
sage: A = G.adjacency_matrix().change_ring(RDF)
1570
sage: A.eigenvalues(algorithm='symmetric', tol=1.0e-5)
1571
[(-2.0, 4), (1.0, 5), (3.0, 1)]
1572
1573
sage: A.eigenvalues(algorithm='symmetric', tol=2.5)
1574
[(-2.0, 4), (1.33333333333, 6)]
1575
1576
An (extreme) example of properly grouping similar eigenvalues. ::
1577
1578
sage: G = graphs.HigmanSimsGraph()
1579
sage: A = G.adjacency_matrix().change_ring(RDF)
1580
sage: A.eigenvalues(algorithm='symmetric', tol=1.0e-5)
1581
[(-8.0, 22), (2.0, 77), (22.0, 1)]
1582
1583
TESTS:
1584
1585
Testing bad input. ::
1586
1587
sage: A = matrix(CDF, 2, range(4))
1588
sage: A.eigenvalues(algorithm='junk')
1589
Traceback (most recent call last):
1590
...
1591
ValueError: algorithm must be 'default', 'symmetric', or 'hermitian', not junk
1592
1593
sage: A = matrix(CDF, 2, 3, range(6))
1594
sage: A.eigenvalues()
1595
Traceback (most recent call last):
1596
...
1597
ValueError: matrix must be square, not 2 x 3
1598
1599
sage: A = matrix(CDF, 2, [1, 2, 3, 4*I])
1600
sage: A.eigenvalues(algorithm='symmetric')
1601
Traceback (most recent call last):
1602
...
1603
TypeError: cannot apply symmetric algorithm to matrix with complex entries
1604
1605
sage: A = matrix(CDF, 2, 2, range(4))
1606
sage: A.eigenvalues(tol='junk')
1607
Traceback (most recent call last):
1608
...
1609
TypeError: tolerance parameter must be a real number, not junk
1610
1611
sage: A = matrix(CDF, 2, 2, range(4))
1612
sage: A.eigenvalues(tol=-0.01)
1613
Traceback (most recent call last):
1614
...
1615
ValueError: tolerance parameter must be positive, not -0.01
1616
1617
A very small matrix. ::
1618
1619
sage: matrix(CDF,0,0).eigenvalues()
1620
[]
1621
"""
1622
import sage.rings.real_double
1623
import sage.rings.complex_double
1624
import numpy
1625
if not algorithm in ['default', 'symmetric', 'hermitian']:
1626
msg = "algorithm must be 'default', 'symmetric', or 'hermitian', not {0}"
1627
raise ValueError(msg.format(algorithm))
1628
if not self.is_square():
1629
msg = 'matrix must be square, not {0} x {1}'
1630
raise ValueError(msg.format(self.nrows(), self.ncols()))
1631
if algorithm == 'symmetric' and self.base_ring() == sage.rings.complex_double.CDF:
1632
try:
1633
self = self.change_ring(sage.rings.real_double.RDF) # check side effect
1634
except TypeError:
1635
raise TypeError('cannot apply symmetric algorithm to matrix with complex entries')
1636
if algorithm == 'symmetric':
1637
algorithm = 'hermitian'
1638
multiplicity = not tol is None
1639
if multiplicity:
1640
try:
1641
tol = float(tol)
1642
except (ValueError, TypeError):
1643
msg = 'tolerance parameter must be a real number, not {0}'
1644
raise TypeError(msg.format(tol))
1645
if tol < 0:
1646
msg = 'tolerance parameter must be positive, not {0}'
1647
raise ValueError(msg.format(tol))
1648
1649
if self._nrows == 0:
1650
return []
1651
global scipy
1652
if scipy is None:
1653
import scipy
1654
import scipy.linalg
1655
if self._nrows == 0:
1656
return []
1657
global scipy
1658
if scipy is None:
1659
import scipy
1660
import scipy.linalg
1661
global numpy
1662
if numpy is None:
1663
import numpy
1664
# generic eigenvalues, or real eigenvalues for Hermitian
1665
if algorithm == 'default':
1666
return_class = sage.rings.complex_double.CDF
1667
evalues = scipy.linalg.eigvals(self._matrix_numpy)
1668
elif algorithm=='hermitian':
1669
return_class = sage.rings.real_double.RDF
1670
evalues = scipy.linalg.eigh(self._matrix_numpy, eigvals_only=True)
1671
if not multiplicity:
1672
return [return_class(e) for e in evalues]
1673
else:
1674
# pairs in ev_group are
1675
# slot 0: the sum of "equal" eigenvalues, "s"
1676
# slot 1: number of eigenvalues in this sum, "m"
1677
# slot 2: average of these eigenvalues, "avg"
1678
# we test if "new" eigenvalues are close to the group average
1679
ev_group = []
1680
for e in evalues:
1681
location = None
1682
best_fit = tol
1683
for i in range(len(ev_group)):
1684
s, m, avg = ev_group[i]
1685
d = numpy.abs(avg - e)
1686
if d < best_fit:
1687
best_fit = d
1688
location = i
1689
if location is None:
1690
ev_group.append([e, 1, e])
1691
else:
1692
ev_group[location][0] += e
1693
ev_group[location][1] += 1
1694
ev_group[location][2] = ev_group[location][0]/ev_group[location][1]
1695
return [(return_class(avg), m) for _, m, avg in ev_group]
1696
1697
def left_eigenvectors(self):
1698
r"""
1699
Compute the left eigenvectors of a matrix of double precision
1700
real or complex numbers (i.e. RDF or CDF).
1701
1702
OUTPUT:
1703
Returns a list of triples, each of the form ``(e,[v],1)``,
1704
where ``e`` is the eigenvalue, and ``v`` is an associated
1705
left eigenvector. If the matrix is of size `n`, then there are
1706
`n` triples. Values are computed with the SciPy library.
1707
1708
The format of this output is designed to match the format
1709
for exact results. However, since matrices here have numerical
1710
entries, the resulting eigenvalues will also be numerical. No
1711
attempt is made to determine if two eigenvalues are equal, or if
1712
eigenvalues might actually be zero. So the algebraic multiplicity
1713
of each eigenvalue is reported as 1. Decisions about equal
1714
eigenvalues or zero eigenvalues should be addressed in the
1715
calling routine.
1716
1717
The SciPy routines used for these computations produce eigenvectors
1718
normalized to have length 1, but on different hardware they may vary
1719
by a sign. So for doctests we have normalized output by forcing their
1720
eigenvectors to have their first non-zero entry equal to one.
1721
1722
EXAMPLES::
1723
1724
sage: m = matrix(RDF, [[-5, 3, 2, 8],[10, 2, 4, -2],[-1, -10, -10, -17],[-2, 7, 6, 13]])
1725
sage: m
1726
[ -5.0 3.0 2.0 8.0]
1727
[ 10.0 2.0 4.0 -2.0]
1728
[ -1.0 -10.0 -10.0 -17.0]
1729
[ -2.0 7.0 6.0 13.0]
1730
sage: spectrum = m.left_eigenvectors()
1731
sage: for i in range(len(spectrum)):
1732
... spectrum[i][1][0]=matrix(RDF, spectrum[i][1]).echelon_form()[0]
1733
sage: spectrum[0]
1734
(2.0, [(1.0, 1.0, 1.0, 1.0)], 1)
1735
sage: spectrum[1]
1736
(1.0, [(1.0, 0.8, 0.8, 0.6)], 1)
1737
sage: spectrum[2]
1738
(-2.0, [(1.0, 0.4, 0.6, 0.2)], 1)
1739
sage: spectrum[3]
1740
(-1.0, [(1.0, 1.0, 2.0, 2.0)], 1)
1741
"""
1742
if not self.is_square():
1743
raise ArithmeticError("self must be a square matrix")
1744
if self._nrows == 0:
1745
return [], self.__copy__()
1746
global scipy
1747
if scipy is None:
1748
import scipy
1749
import scipy.linalg
1750
v,eig = scipy.linalg.eig(self._matrix_numpy, right=False, left=True)
1751
# scipy puts eigenvectors in columns, we will extract from rows
1752
eig = matrix(eig.T)
1753
return [(sage.rings.complex_double.CDF(v[i]), [eig[i]], 1) for i in range(len(v))]
1754
1755
eigenvectors_left = left_eigenvectors
1756
1757
def right_eigenvectors(self):
1758
r"""
1759
Compute the right eigenvectors of a matrix of double precision
1760
real or complex numbers (i.e. RDF or CDF).
1761
1762
OUTPUT:
1763
1764
Returns a list of triples, each of the form ``(e,[v],1)``,
1765
where ``e`` is the eigenvalue, and ``v`` is an associated
1766
right eigenvector. If the matrix is of size `n`, then there
1767
are `n` triples. Values are computed with the SciPy library.
1768
1769
The format of this output is designed to match the format
1770
for exact results. However, since matrices here have numerical
1771
entries, the resulting eigenvalues will also be numerical. No
1772
attempt is made to determine if two eigenvalues are equal, or if
1773
eigenvalues might actually be zero. So the algebraic multiplicity
1774
of each eigenvalue is reported as 1. Decisions about equal
1775
eigenvalues or zero eigenvalues should be addressed in the
1776
calling routine.
1777
1778
The SciPy routines used for these computations produce eigenvectors
1779
normalized to have length 1, but on different hardware they may vary
1780
by a sign. So for doctests we have normalized output by forcing their
1781
eigenvectors to have their first non-zero entry equal to one.
1782
1783
EXAMPLES::
1784
1785
sage: m = matrix(RDF, [[-9, -14, 19, -74],[-1, 2, 4, -11],[-4, -12, 6, -32],[0, -2, -1, 1]])
1786
sage: m
1787
[ -9.0 -14.0 19.0 -74.0]
1788
[ -1.0 2.0 4.0 -11.0]
1789
[ -4.0 -12.0 6.0 -32.0]
1790
[ 0.0 -2.0 -1.0 1.0]
1791
sage: spectrum = m.right_eigenvectors()
1792
sage: for i in range(len(spectrum)):
1793
... spectrum[i][1][0]=matrix(RDF, spectrum[i][1]).echelon_form()[0]
1794
sage: spectrum[0]
1795
(2.0, [(1.0, -2.0, 3.0, 1.0)], 1)
1796
sage: spectrum[1]
1797
(1.0, [(1.0, -0.666666666667, 1.33333333333, 0.333333333333)], 1)
1798
sage: spectrum[2]
1799
(-2.0, [(1.0, -0.2, 1.0, 0.2)], 1)
1800
sage: spectrum[3]
1801
(-1.0, [(1.0, -0.5, 2.0, 0.5)], 1)
1802
"""
1803
if not self.is_square():
1804
raise ArithmeticError("self must be a square matrix")
1805
if self._nrows == 0:
1806
return [], self.__copy__()
1807
global scipy
1808
if scipy is None:
1809
import scipy
1810
import scipy.linalg
1811
v,eig = scipy.linalg.eig(self._matrix_numpy, right=True, left=False)
1812
# scipy puts eigenvectors in columns, we will extract from rows
1813
eig = matrix(eig.T)
1814
return [(sage.rings.complex_double.CDF(v[i]), [eig[i]], 1) for i in range(len(v))]
1815
1816
eigenvectors_right = right_eigenvectors
1817
1818
def solve_left_LU(self, b):
1819
"""
1820
Solve the equation `A x = b` using LU decomposition.
1821
1822
.. WARNING::
1823
1824
This function is broken. See trac 4932.
1825
1826
INPUT:
1827
1828
- self -- an invertible matrix
1829
- b -- a vector
1830
1831
.. NOTE::
1832
1833
This method precomputes and stores the LU decomposition
1834
before solving. If many equations of the form Ax=b need to be
1835
solved for a singe matrix A, then this method should be used
1836
instead of solve. The first time this method is called it will
1837
compute the LU decomposition. If the matrix has not changed
1838
then subsequent calls will be very fast as the precomputed LU
1839
decomposition will be reused.
1840
1841
EXAMPLES::
1842
1843
sage: A = matrix(RDF, 3,3, [1,2,5,7.6,2.3,1,1,2,-1]); A
1844
[ 1.0 2.0 5.0]
1845
[ 7.6 2.3 1.0]
1846
[ 1.0 2.0 -1.0]
1847
sage: b = vector(RDF,[1,2,3])
1848
sage: x = A.solve_left_LU(b); x
1849
Traceback (most recent call last):
1850
...
1851
NotImplementedError: this function is not finished (see trac 4932)
1852
1853
1854
TESTS:
1855
1856
We test two degenerate cases::
1857
1858
sage: A = matrix(RDF, 0, 3, [])
1859
sage: A.solve_left_LU(vector(RDF,[]))
1860
(0.0, 0.0, 0.0)
1861
sage: A = matrix(RDF, 3, 0, [])
1862
sage: A.solve_left_LU(vector(RDF,3, [1,2,3]))
1863
()
1864
1865
"""
1866
if self._nrows != b.degree():
1867
raise ValueError("number of rows of self must equal degree of b")
1868
if self._nrows == 0 or self._ncols == 0:
1869
return self._row_ambient_module().zero_vector()
1870
1871
raise NotImplementedError("this function is not finished (see trac 4932)")
1872
self._c_compute_LU() # so self._L_M and self._U_M are defined below.
1873
cdef Matrix_double_dense M = self._new()
1874
lu = self._L_M*self._U_M
1875
global scipy
1876
if scipy is None:
1877
import scipy
1878
import scipy.linalg
1879
M._matrix_numpy = scipy.linalg.lu_solve((lu, self._P_M), b)
1880
return M
1881
1882
def solve_right(self, b):
1883
r"""
1884
Solve the vector equation ``A*x = b`` for a nonsingular ``A``.
1885
1886
INPUT:
1887
1888
- ``self`` - a square matrix that is nonsigular (of full rank).
1889
- ``b`` - a vector of the correct size. Elements of the vector
1890
must coerce into the base ring of the coefficient matrix. In
1891
particular, if ``b`` has entries from ``CDF`` then ``self``
1892
must have ``CDF`` as its base ring.
1893
1894
OUTPUT:
1895
1896
The unique solution ``x`` to the matrix equation ``A*x = b``,
1897
as a vector over the same base ring as ``self``.
1898
1899
ALGORITHM:
1900
1901
Uses the ``solve()`` routine from the SciPy ``scipy.linalg`` module.
1902
1903
EXAMPLES:
1904
1905
Over the reals. ::
1906
1907
sage: A = matrix(RDF, 3,3, [1,2,5,7.6,2.3,1,1,2,-1]); A
1908
[ 1.0 2.0 5.0]
1909
[ 7.6 2.3 1.0]
1910
[ 1.0 2.0 -1.0]
1911
sage: b = vector(RDF,[1,2,3])
1912
sage: x = A.solve_right(b); x
1913
(-0.113695090439, 1.39018087855, -0.333333333333)
1914
sage: x.parent()
1915
Vector space of dimension 3 over Real Double Field
1916
sage: A*x
1917
(1.0, 2.0, 3.0)
1918
1919
Over the complex numbers. ::
1920
1921
sage: A = matrix(CDF, [[ 0, -1 + 2*I, 1 - 3*I, I],
1922
... [2 + 4*I, -2 + 3*I, -1 + 2*I, -1 - I],
1923
... [ 2 + I, 1 - I, -1, 5],
1924
... [ 3*I, -1 - I, -1 + I, -3 + I]])
1925
sage: b = vector(CDF, [2 -3*I, 3, -2 + 3*I, 8])
1926
sage: x = A.solve_right(b); x
1927
(1.96841637... - 1.07606761...*I, -0.614323843... + 1.68416370...*I, 0.0733985765... + 1.73487544...*I, -1.6018683... + 0.524021352...*I)
1928
sage: x.parent()
1929
Vector space of dimension 4 over Complex Double Field
1930
sage: abs(A*x - b) < 1e-14
1931
True
1932
1933
The vector of constants, ``b``, can be given in a
1934
variety of forms, so long as it coerces to a vector
1935
over the same base ring as the coefficient matrix. ::
1936
1937
sage: A=matrix(CDF, 5, [1/(i+j+1) for i in range(5) for j in range(5)])
1938
sage: A.solve_right([1]*5)
1939
(5.0..., -120.0..., 630.0..., -1120.0..., 630.0...)
1940
1941
TESTS:
1942
1943
A degenerate case. ::
1944
1945
sage: A = matrix(RDF, 0, 0, [])
1946
sage: A.solve_right(vector(RDF,[]))
1947
()
1948
1949
The coefficent matrix must be square. ::
1950
1951
sage: A = matrix(RDF, 2, 3, range(6))
1952
sage: b = vector(RDF, [1,2,3])
1953
sage: A.solve_right(b)
1954
Traceback (most recent call last):
1955
...
1956
ValueError: coefficient matrix of a system over RDF/CDF must be square, not 2 x 3
1957
1958
The coefficient matrix must be nonsingular. ::
1959
1960
sage: A = matrix(RDF, 5, range(25))
1961
sage: b = vector(RDF, [1,2,3,4,5])
1962
sage: A.solve_right(b)
1963
Traceback (most recent call last):
1964
...
1965
LinAlgError: singular matrix
1966
1967
The vector of constants needs the correct degree. ::
1968
1969
sage: A = matrix(RDF, 5, range(25))
1970
sage: b = vector(RDF, [1,2,3,4])
1971
sage: A.solve_right(b)
1972
Traceback (most recent call last):
1973
...
1974
TypeError: vector of constants over Real Double Field incompatible with matrix over Real Double Field
1975
1976
The vector of constants needs to be compatible with
1977
the base ring of the coefficient matrix. ::
1978
1979
sage: F.<a> = FiniteField(27)
1980
sage: b = vector(F, [a,a,a,a,a])
1981
sage: A.solve_right(b)
1982
Traceback (most recent call last):
1983
...
1984
TypeError: vector of constants over Finite Field in a of size 3^3 incompatible with matrix over Real Double Field
1985
1986
With a coefficient matrix over ``RDF``, a vector of constants
1987
over ``CDF`` can be accomodated by converting the base ring
1988
of the coefficient matrix. ::
1989
1990
sage: A = matrix(RDF, 2, range(4))
1991
sage: b = vector(CDF, [1+I,2])
1992
sage: A.solve_right(b)
1993
Traceback (most recent call last):
1994
...
1995
TypeError: vector of constants over Complex Double Field incompatible with matrix over Real Double Field
1996
1997
sage: B = A.change_ring(CDF)
1998
sage: B.solve_right(b)
1999
(-0.5 - 1.5*I, 1.0 + 1.0*I)
2000
"""
2001
if not self.is_square():
2002
raise ValueError("coefficient matrix of a system over RDF/CDF must be square, not %s x %s " % (self.nrows(), self.ncols()))
2003
M = self._column_ambient_module()
2004
try:
2005
vec = M(b)
2006
except TypeError:
2007
raise TypeError("vector of constants over %s incompatible with matrix over %s" % (b.base_ring(), self.base_ring()))
2008
if vec.degree() != self.ncols():
2009
raise ValueError("vector of constants in linear system over RDF/CDF must have degree equal to the number of columns for the coefficient matrix, not %s" % vec.degree() )
2010
2011
if self._ncols == 0:
2012
return M.zero_vector()
2013
2014
global scipy
2015
if scipy is None:
2016
import scipy
2017
import scipy.linalg
2018
# may raise a LinAlgError for a singular matrix
2019
return M(scipy.linalg.solve(self._matrix_numpy, vec.numpy()))
2020
2021
def solve_left(self, b):
2022
r"""
2023
Solve the vector equation ``x*A = b`` for a nonsingular ``A``.
2024
2025
INPUT:
2026
2027
- ``self`` - a square matrix that is nonsigular (of full rank).
2028
- ``b`` - a vector of the correct size. Elements of the vector
2029
must coerce into the base ring of the coefficient matrix. In
2030
particular, if ``b`` has entries from ``CDF`` then ``self``
2031
must have ``CDF`` as its base ring.
2032
2033
OUTPUT:
2034
2035
The unique solution ``x`` to the matrix equation ``x*A = b``,
2036
as a vector over the same base ring as ``self``.
2037
2038
ALGORITHM:
2039
2040
Uses the ``solve()`` routine from the SciPy ``scipy.linalg`` module,
2041
after taking the tranpose of the coefficient matrix.
2042
2043
EXAMPLES:
2044
2045
Over the reals. ::
2046
2047
sage: A = matrix(RDF, 3,3, [1,2,5,7.6,2.3,1,1,2,-1]); A
2048
[ 1.0 2.0 5.0]
2049
[ 7.6 2.3 1.0]
2050
[ 1.0 2.0 -1.0]
2051
sage: b = vector(RDF,[1,2,3])
2052
sage: x = A.solve_left(b); x.zero_at(1e-18) # fix noisy zeroes
2053
(0.666666666..., 0.0, 0.333333333...)
2054
sage: x.parent()
2055
Vector space of dimension 3 over Real Double Field
2056
sage: x*A
2057
(1.0, 2.0, 3.0)
2058
2059
Over the complex numbers. ::
2060
2061
sage: A = matrix(CDF, [[ 0, -1 + 2*I, 1 - 3*I, I],
2062
... [2 + 4*I, -2 + 3*I, -1 + 2*I, -1 - I],
2063
... [ 2 + I, 1 - I, -1, 5],
2064
... [ 3*I, -1 - I, -1 + I, -3 + I]])
2065
sage: b = vector(CDF, [2 -3*I, 3, -2 + 3*I, 8])
2066
sage: x = A.solve_left(b); x
2067
(-1.55765124... - 0.644483985...*I, 0.183274021... + 0.286476868...*I, 0.270818505... + 0.246619217...*I, -1.69003558... - 0.828113879...*I)
2068
sage: x.parent()
2069
Vector space of dimension 4 over Complex Double Field
2070
sage: abs(x*A - b) < 1e-14
2071
True
2072
2073
The vector of constants, ``b``, can be given in a
2074
variety of forms, so long as it coerces to a vector
2075
over the same base ring as the coefficient matrix. ::
2076
2077
sage: A=matrix(CDF, 5, [1/(i+j+1) for i in range(5) for j in range(5)])
2078
sage: A.solve_left([1]*5)
2079
(5.0..., -120.0..., 630.0..., -1120.0..., 630.0...)
2080
2081
TESTS:
2082
2083
A degenerate case. ::
2084
2085
sage: A = matrix(RDF, 0, 0, [])
2086
sage: A.solve_left(vector(RDF,[]))
2087
()
2088
2089
The coefficent matrix must be square. ::
2090
2091
sage: A = matrix(RDF, 2, 3, range(6))
2092
sage: b = vector(RDF, [1,2,3])
2093
sage: A.solve_left(b)
2094
Traceback (most recent call last):
2095
...
2096
ValueError: coefficient matrix of a system over RDF/CDF must be square, not 2 x 3
2097
2098
The coefficient matrix must be nonsingular. ::
2099
2100
sage: A = matrix(RDF, 5, range(25))
2101
sage: b = vector(RDF, [1,2,3,4,5])
2102
sage: A.solve_left(b)
2103
Traceback (most recent call last):
2104
...
2105
LinAlgError: singular matrix
2106
2107
The vector of constants needs the correct degree. ::
2108
2109
sage: A = matrix(RDF, 5, range(25))
2110
sage: b = vector(RDF, [1,2,3,4])
2111
sage: A.solve_left(b)
2112
Traceback (most recent call last):
2113
...
2114
TypeError: vector of constants over Real Double Field incompatible with matrix over Real Double Field
2115
2116
The vector of constants needs to be compatible with
2117
the base ring of the coefficient matrix. ::
2118
2119
sage: F.<a> = FiniteField(27)
2120
sage: b = vector(F, [a,a,a,a,a])
2121
sage: A.solve_left(b)
2122
Traceback (most recent call last):
2123
...
2124
TypeError: vector of constants over Finite Field in a of size 3^3 incompatible with matrix over Real Double Field
2125
2126
With a coefficient matrix over ``RDF``, a vector of constants
2127
over ``CDF`` can be accomodated by converting the base ring
2128
of the coefficient matrix. ::
2129
2130
sage: A = matrix(RDF, 2, range(4))
2131
sage: b = vector(CDF, [1+I,2])
2132
sage: A.solve_left(b)
2133
Traceback (most recent call last):
2134
...
2135
TypeError: vector of constants over Complex Double Field incompatible with matrix over Real Double Field
2136
2137
sage: B = A.change_ring(CDF)
2138
sage: B.solve_left(b)
2139
(0.5 - 1.5*I, 0.5 + 0.5*I)
2140
"""
2141
if not self.is_square():
2142
raise ValueError("coefficient matrix of a system over RDF/CDF must be square, not %s x %s " % (self.nrows(), self.ncols()))
2143
M = self._row_ambient_module()
2144
try:
2145
vec = M(b)
2146
except TypeError:
2147
raise TypeError("vector of constants over %s incompatible with matrix over %s" % (b.base_ring(), self.base_ring()))
2148
if vec.degree() != self.nrows():
2149
raise ValueError("vector of constants in linear system over RDF/CDF must have degree equal to the number of rows for the coefficient matrix, not %s" % vec.degree() )
2150
2151
if self._nrows == 0:
2152
return M.zero_vector()
2153
2154
global scipy
2155
if scipy is None:
2156
import scipy
2157
import scipy.linalg
2158
# may raise a LinAlgError for a singular matrix
2159
# call "right solve" routine with the transpose
2160
return M(scipy.linalg.solve(self._matrix_numpy.T, vec.numpy()))
2161
2162
def determinant(self):
2163
"""
2164
Return the determinant of self.
2165
2166
ALGORITHM:
2167
2168
Use numpy
2169
2170
EXAMPLES::
2171
2172
sage: m = matrix(RDF,2,range(4)); m.det()
2173
-2.0
2174
sage: m = matrix(RDF,0,[]); m.det()
2175
1.0
2176
sage: m = matrix(RDF, 2, range(6)); m.det()
2177
Traceback (most recent call last):
2178
...
2179
ValueError: self must be a square matrix
2180
"""
2181
if not self.is_square():
2182
raise ValueError("self must be a square matrix")
2183
if self._nrows == 0 or self._ncols == 0:
2184
return self._sage_dtype(1)
2185
global scipy
2186
if scipy is None:
2187
import scipy
2188
import scipy.linalg
2189
2190
return self._sage_dtype(scipy.linalg.det(self._matrix_numpy))
2191
2192
2193
def log_determinant(self):
2194
"""
2195
Compute the log of the absolute value of the determinant
2196
using LU decomposition.
2197
2198
.. NOTE::
2199
2200
This is useful if the usual determinant overflows.
2201
2202
EXAMPLES::
2203
2204
sage: m = matrix(RDF,2,2,range(4)); m
2205
[0.0 1.0]
2206
[2.0 3.0]
2207
sage: RDF(log(abs(m.determinant())))
2208
0.69314718056
2209
sage: m.log_determinant()
2210
0.69314718056
2211
sage: m = matrix(RDF,0,0,[]); m
2212
[]
2213
sage: m.log_determinant()
2214
0.0
2215
sage: m = matrix(CDF,2,2,range(4)); m
2216
[0.0 1.0]
2217
[2.0 3.0]
2218
sage: RDF(log(abs(m.determinant())))
2219
0.69314718056
2220
sage: m.log_determinant()
2221
0.69314718056
2222
sage: m = matrix(CDF,0,0,[]); m
2223
[]
2224
sage: m.log_determinant()
2225
0.0
2226
2227
"""
2228
global numpy
2229
cdef Matrix_double_dense U
2230
2231
if self._nrows == 0 or self._ncols == 0:
2232
return sage.rings.real_double.RDF(0)
2233
2234
if not self.is_square():
2235
raise ArithmeticError("self must be a square matrix")
2236
2237
P, L, U = self.LU()
2238
if numpy is None:
2239
import numpy
2240
2241
return sage.rings.real_double.RDF(sum(numpy.log(abs(numpy.diag(U._matrix_numpy)))))
2242
2243
def transpose(self):
2244
"""
2245
Return the transpose of this matrix, without changing self.
2246
2247
EXAMPLES::
2248
2249
sage: m = matrix(RDF,2,3,range(6)); m
2250
[0.0 1.0 2.0]
2251
[3.0 4.0 5.0]
2252
sage: m2 = m.transpose()
2253
sage: m[0,0] = 2
2254
sage: m2 #note that m2 hasn't changed
2255
[0.0 3.0]
2256
[1.0 4.0]
2257
[2.0 5.0]
2258
2259
``.T`` is a convenient shortcut for the transpose::
2260
2261
sage: m.T
2262
[2.0 3.0]
2263
[1.0 4.0]
2264
[2.0 5.0]
2265
2266
sage: m = matrix(RDF,0,3); m
2267
[]
2268
sage: m.transpose()
2269
[]
2270
sage: m.transpose().parent()
2271
Full MatrixSpace of 3 by 0 dense matrices over Real Double Field
2272
2273
"""
2274
if self._nrows == 0 or self._ncols == 0:
2275
return self.new_matrix(self._ncols, self._nrows)
2276
2277
cdef Matrix_double_dense trans
2278
trans = self._new(self._ncols, self._nrows)
2279
trans._matrix_numpy = self._matrix_numpy.transpose().copy()
2280
if self._subdivisions is not None:
2281
row_divs, col_divs = self.subdivisions()
2282
trans.subdivide(col_divs, row_divs)
2283
return trans
2284
2285
def SVD(self, *args, **kwds):
2286
r"""
2287
Return the singular value decomposition of this matrix.
2288
2289
The U and V matrices are not unique and may be returned with different
2290
values in the future or on different systems. The S matrix is unique
2291
and contains the singular values in descending order.
2292
2293
The computed decomposition is cached and returned on subsequent calls.
2294
2295
INPUT:
2296
2297
- A -- a matrix
2298
2299
OUTPUT:
2300
2301
- U, S, V -- immutable matrices such that $A = U*S*V.conj().transpose()$
2302
where U and V are orthogonal and S is zero off of the diagonal.
2303
2304
Note that if self is m-by-n, then the dimensions of the
2305
matrices that this returns are (m,m), (m,n), and (n, n).
2306
2307
.. NOTE::
2308
2309
If all you need is the singular values of the matrix, see
2310
the more convenient :meth:`singular_values`.
2311
2312
EXAMPLES::
2313
2314
sage: m = matrix(RDF,4,range(1,17))
2315
sage: U,S,V = m.SVD()
2316
sage: U*S*V.transpose()
2317
[ 1.0 2.0 3.0 4.0]
2318
[ 5.0 6.0 7.0 8.0]
2319
[ 9.0 10.0 11.0 12.0]
2320
[13.0 14.0 15.0 16.0]
2321
2322
A non-square example::
2323
2324
sage: m = matrix(RDF, 2, range(1,7)); m
2325
[1.0 2.0 3.0]
2326
[4.0 5.0 6.0]
2327
sage: U, S, V = m.SVD()
2328
sage: U*S*V.transpose()
2329
[1.0 2.0 3.0]
2330
[4.0 5.0 6.0]
2331
2332
S contains the singular values::
2333
2334
sage: S.round(4)
2335
[ 9.508 0.0 0.0]
2336
[ 0.0 0.7729 0.0]
2337
sage: [round(sqrt(abs(x)),4) for x in (S*S.transpose()).eigenvalues()]
2338
[9.508, 0.7729]
2339
2340
U and V are orthogonal matrices::
2341
2342
sage: U # random, SVD is not unique
2343
[-0.386317703119 -0.922365780077]
2344
[-0.922365780077 0.386317703119]
2345
[-0.274721127897 -0.961523947641]
2346
[-0.961523947641 0.274721127897]
2347
sage: (U*U.transpose()).zero_at(1e-15)
2348
[1.0 0.0]
2349
[0.0 1.0]
2350
sage: V # random, SVD is not unique
2351
[-0.428667133549 0.805963908589 0.408248290464]
2352
[-0.566306918848 0.112382414097 -0.816496580928]
2353
[-0.703946704147 -0.581199080396 0.408248290464]
2354
sage: (V*V.transpose()).zero_at(1e-15)
2355
[1.0 0.0 0.0]
2356
[0.0 1.0 0.0]
2357
[0.0 0.0 1.0]
2358
2359
TESTS::
2360
2361
sage: m = matrix(RDF,3,2,range(1, 7)); m
2362
[1.0 2.0]
2363
[3.0 4.0]
2364
[5.0 6.0]
2365
sage: U,S,V = m.SVD()
2366
sage: U*S*V.transpose()
2367
[1.0 2.0]
2368
[3.0 4.0]
2369
[5.0 6.0]
2370
2371
sage: m = matrix(RDF, 3, 0, []); m
2372
[]
2373
sage: m.SVD()
2374
([], [], [])
2375
sage: m = matrix(RDF, 0, 3, []); m
2376
[]
2377
sage: m.SVD()
2378
([], [], [])
2379
sage: def shape(x): return (x.nrows(), x.ncols())
2380
sage: m = matrix(RDF, 2, 3, range(6))
2381
sage: map(shape, m.SVD())
2382
[(2, 2), (2, 3), (3, 3)]
2383
sage: for x in m.SVD(): x.is_immutable()
2384
True
2385
True
2386
True
2387
"""
2388
global scipy, numpy
2389
cdef Py_ssize_t i
2390
cdef Matrix_double_dense U, S, V
2391
2392
if len(args)>0 or len(kwds)>0:
2393
from sage.misc.misc import deprecation
2394
deprecation("Arguments passed to SVD, but SVD no longer supports different methods (it only uses numpy now).")
2395
2396
if self._nrows == 0 or self._ncols == 0:
2397
U_t = self.new_matrix(self._nrows, self._ncols)
2398
S_t = self.new_matrix(self._nrows, self._ncols)
2399
V_t = self.new_matrix(self._ncols, self._nrows)
2400
return U_t, S_t, V_t
2401
2402
USV = self.fetch('SVD_factors')
2403
if USV is None:
2404
# TODO: More efficient representation of non-square diagonal matrix S
2405
if scipy is None:
2406
import scipy
2407
import scipy.linalg
2408
if numpy is None:
2409
import numpy
2410
U_mat, S_diagonal, V_mat = scipy.linalg.svd(self._matrix_numpy)
2411
2412
U = self._new(self._nrows, self._nrows)
2413
S = self._new(self._nrows, self._ncols)
2414
V = self._new(self._ncols, self._ncols)
2415
2416
S_mat = numpy.zeros((self._nrows, self._ncols), dtype=self._numpy_dtype)
2417
for i in range(S_diagonal.shape[0]):
2418
S_mat[i,i] = S_diagonal[i]
2419
2420
U._matrix_numpy = numpy.ascontiguousarray(U_mat)
2421
S._matrix_numpy = S_mat
2422
V._matrix_numpy = numpy.ascontiguousarray(V_mat.conj().T)
2423
USV = U, S, V
2424
for M in USV: M.set_immutable()
2425
self.cache('SVD_factors', USV)
2426
2427
return USV
2428
2429
def QR(self):
2430
"""
2431
Return the Q,R factorization of a real matrix A.
2432
2433
The computed decomposition is cached and returned on subsequent calls.
2434
2435
INPUT:
2436
2437
- self -- a real matrix A
2438
2439
OUTPUT:
2440
2441
- Q, R -- immutable matrices such that A = Q*R such that the columns of Q are
2442
orthogonal (i.e., $Q^t Q = I$), and R is upper triangular.
2443
2444
EXAMPLES::
2445
2446
sage: m = matrix(RDF,3,range(0, 12)); m
2447
[ 0.0 1.0 2.0 3.0]
2448
[ 4.0 5.0 6.0 7.0]
2449
[ 8.0 9.0 10.0 11.0]
2450
sage: Q,R = m.QR()
2451
sage: Q*R
2452
[ 0.0 1.0 2.0 3.0]
2453
[ 4.0 5.0 6.0 7.0]
2454
[ 8.0 9.0 10.0 11.0]
2455
2456
Note that Q is an orthogonal matrix::
2457
2458
sage: (Q*Q.transpose()).zero_at(1e-10)
2459
[1.0 0.0 0.0]
2460
[0.0 1.0 0.0]
2461
[0.0 0.0 1.0]
2462
2463
The result is immutable::
2464
2465
sage: Q[0,0] = 0
2466
Traceback (most recent call last):
2467
...
2468
ValueError: matrix is immutable; please change a copy instead (i.e., use copy(M) to change a copy of M).
2469
sage: R.is_immutable()
2470
True
2471
2472
"""
2473
global scipy
2474
cdef Matrix_double_dense Q,R
2475
2476
if self._nrows == 0 or self._ncols == 0:
2477
return self.new_matrix(self._nrows, self._nrows), self.new_matrix()
2478
2479
QR = self.fetch('QR_factors')
2480
if QR is None:
2481
Q = self._new(self._nrows, self._nrows)
2482
R = self._new(self._nrows, self._ncols)
2483
if scipy is None:
2484
import scipy
2485
import scipy.linalg
2486
Q._matrix_numpy, R._matrix_numpy = scipy.linalg.qr(self._matrix_numpy)
2487
Q.set_immutable()
2488
R.set_immutable()
2489
QR = (Q, R)
2490
self.cache('QR_factors', QR)
2491
return QR
2492
2493
def is_symmetric(self, tol = 1e-12):
2494
"""
2495
Return whether this matrix is symmetric, to the given tolerance.
2496
2497
EXAMPLES::
2498
2499
sage: m = matrix(RDF,2,2,range(4)); m
2500
[0.0 1.0]
2501
[2.0 3.0]
2502
sage: m.is_symmetric()
2503
False
2504
sage: m[1,0] = 1.1; m
2505
[0.0 1.0]
2506
[1.1 3.0]
2507
sage: m.is_symmetric()
2508
False
2509
2510
The tolerance inequality is strict:
2511
sage: m.is_symmetric(tol=0.1)
2512
False
2513
sage: m.is_symmetric(tol=0.11)
2514
True
2515
"""
2516
cdef Py_ssize_t i, j
2517
tol = float(tol)
2518
key = 'symmetric_%s'%tol
2519
b = self.fetch(key)
2520
if not b is None:
2521
return b
2522
if self._nrows != self._ncols:
2523
self.cache(key, False)
2524
return False
2525
b = True
2526
for i from 0 < i < self._nrows:
2527
for j from 0 <= j < i:
2528
if math.fabs(self.get_unsafe(i,j) - self.get_unsafe(j,i)) > tol:
2529
b = False
2530
break
2531
self.cache(key, b)
2532
return b
2533
2534
def is_unitary(self, tol=1e-12, algorithm='orthonormal'):
2535
r"""
2536
Returns ``True`` if the columns of the matrix are an orthonormal basis.
2537
2538
For a matrix with real entries this determines if a matrix is
2539
"orthogonal" and for a matrix with complex entries this determines
2540
if the matrix is "unitary."
2541
2542
INPUT:
2543
2544
- ``tol`` - default: ``1e-12`` - the largest value of the
2545
absolute value of the difference between two matrix entries
2546
for which they will still be considered equal.
2547
2548
- ``algorithm`` - default: 'orthonormal' - set to 'orthonormal'
2549
for a stable procedure and set to 'naive' for a fast
2550
procedure.
2551
2552
OUTPUT:
2553
2554
``True`` if the matrix is square and its conjugate-transpose is
2555
its inverse, and ``False`` otherwise. In other words, a matrix
2556
is orthogonal or unitary if the product of its conjugate-transpose
2557
times the matrix is the identity matrix.
2558
2559
The tolerance parameter is used to allow for numerical values
2560
to be equal if there is a slight difference due to round-off
2561
and other imprecisions.
2562
2563
The result is cached, on a per-tolerance and per-algorithm basis.
2564
2565
ALGORITHMS:
2566
2567
The naive algorithm simply computes the product of the
2568
conjugate-transpose with the matrix and compares the entries
2569
to the identity matrix, with equality controlled by the
2570
tolerance parameter.
2571
2572
The orthonormal algorithm first computes a Schur decomposition
2573
(via the :meth:`schur` method) and checks that the result is a
2574
diagonal matrix with entries of modulus 1, which is equivalent to
2575
being unitary.
2576
2577
So the naive algorithm might finish fairly quickly for a matrix
2578
that is not unitary, once the product has been computed.
2579
However, the orthonormal algorithm will compute a Schur
2580
decomposition before going through a similar check of a
2581
matrix entry-by-entry.
2582
2583
EXAMPLES:
2584
2585
A matrix that is far from unitary. ::
2586
2587
sage: A = matrix(RDF, 4, range(16))
2588
sage: A.conjugate().transpose()*A
2589
[224.0 248.0 272.0 296.0]
2590
[248.0 276.0 304.0 332.0]
2591
[272.0 304.0 336.0 368.0]
2592
[296.0 332.0 368.0 404.0]
2593
sage: A.is_unitary()
2594
False
2595
sage: A.is_unitary(algorithm='naive')
2596
False
2597
sage: A.is_unitary(algorithm='orthonormal')
2598
False
2599
2600
The QR decoposition will produce a unitary matrix as Q and the
2601
SVD decomposition will create two unitary matrices, U and V. ::
2602
2603
sage: A = matrix(CDF, [[ 1 - I, -3*I, -2 + I, 1, -2 + 3*I],
2604
... [ 1 - I, -2 + I, 1 + 4*I, 0, 2 + I],
2605
... [ -1, -5 + I, -2 + I, 1 + I, -5 - 4*I],
2606
... [-2 + 4*I, 2 - I, 8 - 4*I, 1 - 8*I, 3 - 2*I]])
2607
sage: Q, R = A.QR()
2608
sage: Q.is_unitary()
2609
True
2610
sage: U, S, V = A.SVD()
2611
sage: U.is_unitary(algorithm='naive')
2612
True
2613
sage: U.is_unitary(algorithm='orthonormal')
2614
True
2615
sage: V.is_unitary(algorithm='naive') # not tested - known bug (trac #11248)
2616
True
2617
2618
If we make the tolerance too strict we can get misleading results. ::
2619
2620
sage: A = matrix(RDF, 10, 10, [1/(i+j+1) for i in range(10) for j in range(10)])
2621
sage: Q, R = A.QR()
2622
sage: Q.is_unitary(algorithm='naive', tol=1e-16)
2623
False
2624
sage: Q.is_unitary(algorithm='orthonormal', tol=1e-17)
2625
False
2626
2627
Rectangular matrices are not unitary/orthogonal, even if their
2628
columns form an orthonormal set. ::
2629
2630
sage: A = matrix(CDF, [[1,0], [0,0], [0,1]])
2631
sage: A.is_unitary()
2632
False
2633
2634
The smallest cases. The Schur decomposition used by the
2635
orthonormal algorithm will fail on a matrix of size zero. ::
2636
2637
sage: P = matrix(CDF, 0, 0)
2638
sage: P.is_unitary(algorithm='naive')
2639
True
2640
2641
sage: P = matrix(CDF, 1, 1, [1])
2642
sage: P.is_unitary(algorithm='orthonormal')
2643
True
2644
2645
sage: P = matrix(CDF, 0, 0,)
2646
sage: P.is_unitary(algorithm='orthonormal')
2647
Traceback (most recent call last):
2648
...
2649
ValueError: failed to create intent(cache|hide)|optional array-- must have defined dimensions but got (0,)
2650
2651
TESTS::
2652
2653
sage: P = matrix(CDF, 2, 2)
2654
sage: P.is_unitary(tol='junk')
2655
Traceback (most recent call last):
2656
...
2657
TypeError: tolerance must be a real number, not junk
2658
2659
sage: P.is_unitary(tol=-0.3)
2660
Traceback (most recent call last):
2661
...
2662
ValueError: tolerance must be positive, not -0.3
2663
2664
sage: P.is_unitary(algorithm='junk')
2665
Traceback (most recent call last):
2666
...
2667
ValueError: algorithm must be 'naive' or 'orthonormal', not junk
2668
2669
2670
AUTHOR:
2671
2672
- Rob Beezer (2011-05-04)
2673
"""
2674
global numpy
2675
try:
2676
tol = float(tol)
2677
except:
2678
raise TypeError('tolerance must be a real number, not {0}'.format(tol))
2679
if tol <= 0:
2680
raise ValueError('tolerance must be positive, not {0}'.format(tol))
2681
if not algorithm in ['naive', 'orthonormal']:
2682
raise ValueError("algorithm must be 'naive' or 'orthonormal', not {0}".format(algorithm))
2683
key = 'unitary_{0}_{1}'.format(algorithm, tol)
2684
b = self.fetch(key)
2685
if not b is None:
2686
return b
2687
if not self.is_square():
2688
self.cache(key, False)
2689
return False
2690
if numpy is None:
2691
import numpy
2692
cdef Py_ssize_t i, j
2693
cdef Matrix_double_dense T, P
2694
if algorithm == 'orthonormal':
2695
# Schur decomposition over CDF will be unitary
2696
# iff diagonal with unit modulus entries
2697
_, T = self.schur(base_ring=sage.rings.complex_double.CDF)
2698
unitary = T._is_lower_triangular(tol)
2699
if unitary:
2700
for 0 <= i < self._nrows:
2701
if numpy.absolute(numpy.absolute(T.get_unsafe(i,i)) - 1) > tol:
2702
unitary = False
2703
break
2704
elif algorithm == 'naive':
2705
P = self.conjugate().transpose()*self
2706
unitary = True
2707
for i from 0 <= i < self._nrows:
2708
# off-diagonal, since P is Hermitian
2709
for j from 0 <= j < i:
2710
if numpy.absolute(P.get_unsafe(i,j)) > tol:
2711
unitary = False
2712
break
2713
# at diagonal
2714
if numpy.absolute(P.get_unsafe(i,i)-1) > tol:
2715
unitary = False
2716
if not unitary:
2717
break
2718
self.cache(key, unitary)
2719
return unitary
2720
2721
def _is_lower_triangular(self, tol):
2722
r"""
2723
Returns ``True`` if the entries above the diagonal are all zero.
2724
2725
INPUT:
2726
2727
- ``tol`` - the largest value of the absolute value of the
2728
difference between two matrix entries for which they will
2729
still be considered equal.
2730
2731
OUTPUT:
2732
2733
Returns ``True`` if each entry above the diagonal (entries
2734
with a row index less than the column index) is zero.
2735
2736
EXAMPLES::
2737
2738
sage: A = matrix(RDF, [[ 2.0, 0.0, 0.0],
2739
... [ 1.0, 3.0, 0.0],
2740
... [-4.0, 2.0, -1.0]])
2741
sage: A._is_lower_triangular(1.0e-17)
2742
True
2743
sage: A[1,2] = 10^-13
2744
sage: A._is_lower_triangular(1.0e-14)
2745
False
2746
"""
2747
global numpy
2748
if numpy is None:
2749
import numpy
2750
cdef Py_ssize_t i, j
2751
for i in range(self._nrows):
2752
for j in range(i+1, self._ncols):
2753
if numpy.absolute(self.get_unsafe(i,j)) > tol:
2754
return False
2755
return True
2756
2757
def is_hermitian(self, tol = 1e-12, algorithm='orthonormal'):
2758
r"""
2759
Returns ``True`` if the matrix is equal to its conjugate-transpose.
2760
2761
INPUT:
2762
2763
- ``tol`` - default: ``1e-12`` - the largest value of the
2764
absolute value of the difference between two matrix entries
2765
for which they will still be considered equal.
2766
2767
- ``algorithm`` - default: 'orthonormal' - set to 'orthonormal'
2768
for a stable procedure and set to 'naive' for a fast
2769
procedure.
2770
2771
OUTPUT:
2772
2773
``True`` if the matrix is square and equal to the transpose
2774
with every entry conjugated, and ``False`` otherwise.
2775
2776
Note that if conjugation has no effect on elements of the base
2777
ring (such as for integers), then the :meth:`is_symmetric`
2778
method is equivalent and faster.
2779
2780
The tolerance parameter is used to allow for numerical values
2781
to be equal if there is a slight difference due to round-off
2782
and other imprecisions.
2783
2784
The result is cached, on a per-tolerance and per-algorithm basis.
2785
2786
ALGORITHMS:
2787
2788
The naive algorithm simply compares corresponing entries on either
2789
side of the diagonal (and on the diagonal itself) to see if they are
2790
conjugates, with equality controlled by the tolerance parameter.
2791
2792
The orthonormal algorithm first computes a Schur decomposition
2793
(via the :meth:`schur` method) and checks that the result is a
2794
diagonal matrix with real entries.
2795
2796
So the naive algorithm can finish quickly for a matrix that is not
2797
Hermitian, while the orthonormal algorithm will always compute a
2798
Schur decomposition before going through a similar check of the matrix
2799
entry-by-entry.
2800
2801
EXAMPLES::
2802
2803
sage: A = matrix(CDF, [[ 1 + I, 1 - 6*I, -1 - I],
2804
... [-3 - I, -4*I, -2],
2805
... [-1 + I, -2 - 8*I, 2 + I]])
2806
sage: A.is_hermitian(algorithm='orthonormal')
2807
False
2808
sage: A.is_hermitian(algorithm='naive')
2809
False
2810
sage: B = A*A.conjugate_transpose()
2811
sage: B.is_hermitian(algorithm='orthonormal')
2812
True
2813
sage: B.is_hermitian(algorithm='naive')
2814
True
2815
2816
A matrix that is nearly Hermitian, but for one non-real
2817
diagonal entry. ::
2818
2819
sage: A = matrix(CDF, [[ 2, 2-I, 1+4*I],
2820
... [ 2+I, 3+I, 2-6*I],
2821
... [1-4*I, 2+6*I, 5]])
2822
sage: A.is_hermitian(algorithm='orthonormal')
2823
False
2824
sage: A[1,1] = 132
2825
sage: A.is_hermitian(algorithm='orthonormal')
2826
True
2827
2828
We get a unitary matrix from the SVD routine and use this
2829
numerical matrix to create a matrix that should be Hermitian
2830
(indeed it should be the identity matrix), but with some
2831
imprecision. We use this to illustrate that if the tolerance
2832
is set too small, then we can be too strict about the equality
2833
of entries and may achieve the wrong result (depending on
2834
the system)::
2835
2836
sage: A = matrix(CDF, [[ 1 + I, 1 - 6*I, -1 - I],
2837
... [-3 - I, -4*I, -2],
2838
... [-1 + I, -2 - 8*I, 2 + I]])
2839
sage: U, _, _ = A.SVD()
2840
sage: B=U*U.conjugate_transpose()
2841
sage: B.is_hermitian(algorithm='naive')
2842
True
2843
sage: B.is_hermitian(algorithm='naive', tol=1.0e-17) # random
2844
False
2845
sage: B.is_hermitian(algorithm='naive', tol=1.0e-15)
2846
True
2847
2848
A square, empty matrix is trivially Hermitian. ::
2849
2850
sage: A = matrix(RDF, 0, 0)
2851
sage: A.is_hermitian()
2852
True
2853
2854
Rectangular matrices are never Hermitian, no matter which
2855
algorithm is requested. ::
2856
2857
sage: A = matrix(CDF, 3, 4)
2858
sage: A.is_hermitian()
2859
False
2860
2861
TESTS:
2862
2863
The tolerance must be strictly positive. ::
2864
2865
sage: A = matrix(RDF, 2, range(4))
2866
sage: A.is_hermitian(tol = -3.1)
2867
Traceback (most recent call last):
2868
...
2869
ValueError: tolerance must be positive, not -3.1
2870
2871
The ``algorithm`` keyword gets checked. ::
2872
2873
sage: A = matrix(RDF, 2, range(4))
2874
sage: A.is_hermitian(algorithm='junk')
2875
Traceback (most recent call last):
2876
...
2877
ValueError: algorithm must be 'naive' or 'orthonormal', not junk
2878
2879
AUTHOR:
2880
2881
- Rob Beezer (2011-03-30)
2882
"""
2883
import sage.rings.complex_double
2884
global numpy
2885
tol = float(tol)
2886
if tol <= 0:
2887
raise ValueError('tolerance must be positive, not {0}'.format(tol))
2888
if not algorithm in ['naive', 'orthonormal']:
2889
raise ValueError("algorithm must be 'naive' or 'orthonormal', not {0}".format(algorithm))
2890
2891
key = 'hermitian_{0}_{1}'.format(algorithm, tol)
2892
h = self.fetch(key)
2893
if not h is None:
2894
return h
2895
if not self.is_square():
2896
self.cache(key, False)
2897
return False
2898
if self._nrows == 0:
2899
self.cache(key, True)
2900
return True
2901
if numpy is None:
2902
import numpy
2903
cdef Py_ssize_t i, j
2904
cdef Matrix_double_dense T
2905
if algorithm == 'orthonormal':
2906
# Schur decomposition over CDF will be diagonal and real iff Hermitian
2907
_, T = self.schur(base_ring=sage.rings.complex_double.CDF)
2908
hermitian = T._is_lower_triangular(tol)
2909
if hermitian:
2910
for i in range(T._nrows):
2911
if numpy.absolute(numpy.imag(T.get_unsafe(i,i))) > tol:
2912
hermitian = False
2913
break
2914
elif algorithm == 'naive':
2915
hermitian = True
2916
for i in range(self._nrows):
2917
for j in range(i+1):
2918
if numpy.absolute(self.get_unsafe(i,j) - self.get_unsafe(j,i).conjugate()) > tol:
2919
hermitian = False
2920
break
2921
if not hermitian:
2922
break
2923
self.cache(key, hermitian)
2924
return hermitian
2925
2926
def is_normal(self, tol=1e-12, algorithm='orthonormal'):
2927
r"""
2928
Returns ``True`` if the matrix commutes with its conjugate-transpose.
2929
2930
INPUT:
2931
2932
- ``tol`` - default: ``1e-12`` - the largest value of the
2933
absolute value of the difference between two matrix entries
2934
for which they will still be considered equal.
2935
2936
- ``algorithm`` - default: 'orthonormal' - set to 'orthonormal'
2937
for a stable procedure and set to 'naive' for a fast
2938
procedure.
2939
2940
OUTPUT:
2941
2942
``True`` if the matrix is square and commutes with its
2943
conjugate-transpose, and ``False`` otherwise.
2944
2945
Normal matrices are precisely those that can be diagonalized
2946
by a unitary matrix.
2947
2948
The tolerance parameter is used to allow for numerical values
2949
to be equal if there is a slight difference due to round-off
2950
and other imprecisions.
2951
2952
The result is cached, on a per-tolerance and per-algorithm basis.
2953
2954
ALGORITHMS:
2955
2956
The naive algorithm simply compares entries of the two possible
2957
products of the matrix with its conjugate-transpose, with equality
2958
controlled by the tolerance parameter.
2959
2960
The orthonormal algorithm first computes a Schur decomposition
2961
(via the :meth:`schur` method) and checks that the result is a
2962
diagonal matrix. An orthonormal diagonalization
2963
is equivalent to being normal.
2964
2965
So the naive algorithm can finish fairly quickly for a matrix
2966
that is not normal, once the products have been computed.
2967
However, the orthonormal algorithm will compute a Schur
2968
decomposition before going through a similar check of a
2969
matrix entry-by-entry.
2970
2971
EXAMPLES:
2972
2973
First over the complexes. ``B`` is Hermitian, hence normal. ::
2974
2975
sage: A = matrix(CDF, [[ 1 + I, 1 - 6*I, -1 - I],
2976
... [-3 - I, -4*I, -2],
2977
... [-1 + I, -2 - 8*I, 2 + I]])
2978
sage: B = A*A.conjugate_transpose()
2979
sage: B.is_hermitian()
2980
True
2981
sage: B.is_normal(algorithm='orthonormal')
2982
True
2983
sage: B.is_normal(algorithm='naive')
2984
True
2985
sage: B[0,0] = I
2986
sage: B.is_normal(algorithm='orthonormal')
2987
False
2988
sage: B.is_normal(algorithm='naive')
2989
False
2990
2991
Now over the reals. Circulant matrices are normal. ::
2992
2993
sage: G = graphs.CirculantGraph(20, [3, 7])
2994
sage: D = digraphs.Circuit(20)
2995
sage: A = 3*D.adjacency_matrix() - 5*G.adjacency_matrix()
2996
sage: A = A.change_ring(RDF)
2997
sage: A.is_normal()
2998
True
2999
sage: A.is_normal(algorithm = 'naive')
3000
True
3001
sage: A[19,0] = 4.0
3002
sage: A.is_normal()
3003
False
3004
sage: A.is_normal(algorithm = 'naive')
3005
False
3006
3007
Skew-Hermitian matrices are normal. ::
3008
3009
sage: A = matrix(CDF, [[ 1 + I, 1 - 6*I, -1 - I],
3010
... [-3 - I, -4*I, -2],
3011
... [-1 + I, -2 - 8*I, 2 + I]])
3012
sage: B = A - A.conjugate_transpose()
3013
sage: B.is_hermitian()
3014
False
3015
sage: B.is_normal()
3016
True
3017
sage: B.is_normal(algorithm='naive')
3018
True
3019
3020
A small matrix that does not fit into any of the usual categories
3021
of normal matrices. ::
3022
3023
sage: A = matrix(RDF, [[1, -1],
3024
... [1, 1]])
3025
sage: A.is_normal()
3026
True
3027
sage: not A.is_hermitian() and not A.is_skew_symmetric()
3028
True
3029
3030
Sage has several fields besides the entire complex numbers
3031
where conjugation is non-trivial. ::
3032
3033
sage: F.<b> = QuadraticField(-7)
3034
sage: C = matrix(F, [[-2*b - 3, 7*b - 6, -b + 3],
3035
... [-2*b - 3, -3*b + 2, -2*b],
3036
... [ b + 1, 0, -2]])
3037
sage: C = C*C.conjugate_transpose()
3038
sage: C.is_normal()
3039
True
3040
3041
A square, empty matrix is trivially normal. ::
3042
3043
sage: A = matrix(CDF, 0, 0)
3044
sage: A.is_normal()
3045
True
3046
3047
Rectangular matrices are never normal, no matter which
3048
algorithm is requested. ::
3049
3050
sage: A = matrix(CDF, 3, 4)
3051
sage: A.is_normal()
3052
False
3053
3054
TESTS:
3055
3056
The tolerance must be strictly positive. ::
3057
3058
sage: A = matrix(RDF, 2, range(4))
3059
sage: A.is_normal(tol = -3.1)
3060
Traceback (most recent call last):
3061
...
3062
ValueError: tolerance must be positive, not -3.1
3063
3064
The ``algorithm`` keyword gets checked. ::
3065
3066
sage: A = matrix(RDF, 2, range(4))
3067
sage: A.is_normal(algorithm='junk')
3068
Traceback (most recent call last):
3069
...
3070
ValueError: algorithm must be 'naive' or 'orthonormal', not junk
3071
3072
AUTHOR:
3073
3074
- Rob Beezer (2011-03-31)
3075
"""
3076
import sage.rings.complex_double
3077
global numpy
3078
tol = float(tol)
3079
if tol <= 0:
3080
raise ValueError('tolerance must be positive, not {0}'.format(tol))
3081
if not algorithm in ['naive', 'orthonormal']:
3082
raise ValueError("algorithm must be 'naive' or 'orthonormal', not {0}".format(algorithm))
3083
3084
key = 'normal_{0}_{1}'.format(algorithm, tol)
3085
b = self.fetch(key)
3086
if not b is None:
3087
return b
3088
if not self.is_square():
3089
self.cache(key, False)
3090
return False
3091
if self._nrows == 0:
3092
self.cache(key, True)
3093
return True
3094
cdef Py_ssize_t i, j
3095
cdef Matrix_double_dense T, left, right
3096
if algorithm == 'orthonormal':
3097
# Schur decomposition over CDF will be diagonal iff normal
3098
_, T = self.schur(base_ring=sage.rings.complex_double.CDF)
3099
normal = T._is_lower_triangular(tol)
3100
elif algorithm == 'naive':
3101
if numpy is None:
3102
import numpy
3103
CT = self.conjugate_transpose()
3104
left = self*CT
3105
right = CT*self
3106
normal = True
3107
# two products are Hermitian, need only check lower triangle
3108
for i in range(self._nrows):
3109
for j in range(i+1):
3110
if numpy.absolute(left.get_unsafe(i,j) - right.get_unsafe(i,j)) > tol:
3111
normal = False
3112
break
3113
if not normal:
3114
break
3115
self.cache(key, normal)
3116
return normal
3117
3118
def schur(self, base_ring=None):
3119
r"""
3120
Returns the Schur decomposition of the matrix.
3121
3122
INPUT:
3123
3124
- ``base_ring`` - optional, defaults to the base ring of ``self``.
3125
Use this to request the base ring of the returned matrices, which
3126
will affect the format of the results.
3127
3128
OUTPUT:
3129
3130
A pair of immutable matrices. The first is a unitary matrix `Q`.
3131
The second, `T`, is upper-triangular when returned over the complex
3132
numbers, while it is almost upper-triangular over the reals. In the
3133
latter case, there can be some `2\times 2` blocks on the diagonal
3134
which represent a pair of conjugate complex eigenvalues of ``self``.
3135
3136
If ``self`` is the matrix `A`, then
3137
3138
.. math::
3139
3140
A = QT({\overline Q})^t
3141
3142
where the latter matrix is the conjugate-transpose of ``Q``, which
3143
is also the inverse of ``Q``, since ``Q`` is unitary.
3144
3145
Note that in the case of a normal matrix (Hermitian, symmetric, and
3146
others), the upper-triangular matrix is a diagonal matrix with
3147
eigenvalues of ``self`` on the diagonal, and the unitary matrix
3148
has columns that form an orthonormal basis composed of eigenvectors
3149
of ``self``. This is known as "orthonormal diagonalization".
3150
3151
.. WARNING::
3152
3153
The Schur decomposition is not unique, as there may be numerous
3154
choices for the vectors of the orthonormal basis, and consequently
3155
different possibilities for the upper-triangular matrix. However,
3156
the diagonal of the upper-triangular matrix will always contain the
3157
eigenvalues of the matrix (in the complex version), or `2\times 2`
3158
block matrices in the real version representing pairs of conjugate
3159
complex eigenvalues.
3160
3161
In particular, results may vary across systems and processors.
3162
3163
EXAMPLES:
3164
3165
First over the complexes. The similar matrix is always
3166
upper-triangular in this case. ::
3167
3168
sage: A = matrix(CDF, 4, 4, range(16)) + matrix(CDF, 4, 4, [x^3*I for x in range(0, 16)])
3169
sage: Q, T = A.schur()
3170
sage: (Q*Q.conjugate().transpose()).zero_at(1.0e-12)
3171
[1.0 0.0 0.0 0.0]
3172
[0.0 1.0 0.0 0.0]
3173
[0.0 0.0 1.0 0.0]
3174
[0.0 0.0 0.0 1.0]
3175
sage: all([T.zero_at(1.0e-12)[i,j] == 0 for i in range(4) for j in range(i)])
3176
True
3177
sage: (Q*T*Q.conjugate().transpose()-A).zero_at(1.0e-11)
3178
[0.0 0.0 0.0 0.0]
3179
[0.0 0.0 0.0 0.0]
3180
[0.0 0.0 0.0 0.0]
3181
[0.0 0.0 0.0 0.0]
3182
sage: eigenvalues = [T[i,i] for i in range(4)]; eigenvalues
3183
[30.733... + 4648.541...*I, -0.184... - 159.057...*I, -0.523... + 11.158...*I, -0.025... - 0.642...*I]
3184
sage: A.eigenvalues()
3185
[30.733... + 4648.541...*I, -0.184... - 159.057...*I, -0.523... + 11.158...*I, -0.025... - 0.642...*I]
3186
sage: abs(A.norm()-T.norm()) < 1e-10
3187
True
3188
3189
We begin with a real matrix but ask for a decomposition over the
3190
complexes. The result will yield an upper-triangular matrix over
3191
the complex numbers for ``T``. ::
3192
3193
sage: A = matrix(RDF, 4, 4, [x^3 for x in range(16)])
3194
sage: Q, T = A.schur(base_ring=CDF)
3195
sage: (Q*Q.conjugate().transpose()).zero_at(1.0e-12)
3196
[1.0 0.0 0.0 0.0]
3197
[0.0 1.0 0.0 0.0]
3198
[0.0 0.0 1.0 0.0]
3199
[0.0 0.0 0.0 1.0]
3200
sage: T.parent()
3201
Full MatrixSpace of 4 by 4 dense matrices over Complex Double Field
3202
sage: all([T.zero_at(1.0e-12)[i,j] == 0 for i in range(4) for j in range(i)])
3203
True
3204
sage: (Q*T*Q.conjugate().transpose()-A).zero_at(1.0e-11)
3205
[0.0 0.0 0.0 0.0]
3206
[0.0 0.0 0.0 0.0]
3207
[0.0 0.0 0.0 0.0]
3208
[0.0 0.0 0.0 0.0]
3209
3210
Now totally over the reals. But with complex eigenvalues, the
3211
similar matrix may not be upper-triangular. But "at worst" there
3212
may be some `2\times 2` blocks on the diagonal which represent
3213
a pair of conjugate complex eigenvalues. These blocks will then
3214
just interrupt the zeros below the main diagonal. This example
3215
has a pair of these of the blocks. ::
3216
3217
sage: A = matrix(RDF, 4, 4, [[1, 0, -3, -1],
3218
... [4, -16, -7, 0],
3219
... [1, 21, 1, -2],
3220
... [26, -1, -2, 1]])
3221
sage: Q, T = A.schur()
3222
sage: (Q*Q.conjugate().transpose()).zero_at(1.0e-12)
3223
[1.0 0.0 0.0 0.0]
3224
[0.0 1.0 0.0 0.0]
3225
[0.0 0.0 1.0 0.0]
3226
[0.0 0.0 0.0 1.0]
3227
sage: all([T.zero_at(1.0e-12)[i,j] == 0 for i in range(4) for j in range(i)])
3228
False
3229
sage: all([T.zero_at(1.0e-12)[i,j] == 0 for i in range(4) for j in range(i-1)])
3230
True
3231
sage: (Q*T*Q.conjugate().transpose()-A).zero_at(1.0e-11)
3232
[0.0 0.0 0.0 0.0]
3233
[0.0 0.0 0.0 0.0]
3234
[0.0 0.0 0.0 0.0]
3235
[0.0 0.0 0.0 0.0]
3236
sage: sorted(T[0:2,0:2].eigenvalues() + T[2:4,2:4].eigenvalues())
3237
[-5.710... - 8.382...*I, -5.710... + 8.382...*I, -0.789... - 2.336...*I, -0.789... + 2.336...*I]
3238
sage: sorted(A.eigenvalues())
3239
[-5.710... - 8.382...*I, -5.710... + 8.382...*I, -0.789... - 2.336...*I, -0.789... + 2.336...*I]
3240
sage: abs(A.norm()-T.norm()) < 1e-12
3241
True
3242
3243
Starting with complex numbers and requesting a result over the reals
3244
will never happen. ::
3245
3246
sage: A = matrix(CDF, 2, 2, [[2+I, -1+3*I], [5-4*I, 2-7*I]])
3247
sage: A.schur(base_ring=RDF)
3248
Traceback (most recent call last):
3249
...
3250
TypeError: unable to convert input matrix over CDF to a matrix over RDF
3251
3252
If theory predicts your matrix is real, but it contains some
3253
very small imaginary parts, you can specify the cutoff for "small"
3254
imaginary parts, then request the output as real matrices, and let
3255
the routine do the rest. ::
3256
3257
sage: A = matrix(RDF, 2, 2, [1, 1, -1, 0]) + matrix(CDF, 2, 2, [1.0e-14*I]*4)
3258
sage: B = A.zero_at(1.0e-12)
3259
sage: B.parent()
3260
Full MatrixSpace of 2 by 2 dense matrices over Complex Double Field
3261
sage: Q, T = B.schur(RDF)
3262
sage: Q.parent()
3263
Full MatrixSpace of 2 by 2 dense matrices over Real Double Field
3264
sage: T.parent()
3265
Full MatrixSpace of 2 by 2 dense matrices over Real Double Field
3266
sage: Q.round(6)
3267
[ 0.707107 0.707107]
3268
[-0.707107 0.707107]
3269
sage: T.round(6)
3270
[ 0.5 1.5]
3271
[-0.5 0.5]
3272
sage: (Q*T*Q.conjugate().transpose()-B).zero_at(1.0e-11)
3273
[0.0 0.0]
3274
[0.0 0.0]
3275
3276
A Hermitian matrix has real eigenvalues, so the similar matrix
3277
will be upper-triangular. Furthermore, a Hermitian matrix is
3278
diagonalizable with respect to an orthonormal basis, composed
3279
of eigenvectors of the matrix. Here that basis is the set of
3280
columns of the unitary matrix. ::
3281
3282
sage: A = matrix(CDF, [[ 52, -9*I - 8, 6*I - 187, -188*I + 2],
3283
... [ 9*I - 8, 12, -58*I + 59, 30*I + 42],
3284
... [-6*I - 187, 58*I + 59, 2677, 2264*I + 65],
3285
... [ 188*I + 2, -30*I + 42, -2264*I + 65, 2080]])
3286
sage: Q, T = A.schur()
3287
sage: T = T.zero_at(1.0e-12).change_ring(RDF)
3288
sage: T.round(6)
3289
[4680.13301 0.0 0.0 0.0]
3290
[ 0.0 102.715967 0.0 0.0]
3291
[ 0.0 0.0 35.039344 0.0]
3292
[ 0.0 0.0 0.0 3.11168]
3293
sage: (Q*Q.conjugate().transpose()).zero_at(1.0e-12)
3294
[1.0 0.0 0.0 0.0]
3295
[0.0 1.0 0.0 0.0]
3296
[0.0 0.0 1.0 0.0]
3297
[0.0 0.0 0.0 1.0]
3298
sage: (Q*T*Q.conjugate().transpose()-A).zero_at(1.0e-11)
3299
[0.0 0.0 0.0 0.0]
3300
[0.0 0.0 0.0 0.0]
3301
[0.0 0.0 0.0 0.0]
3302
[0.0 0.0 0.0 0.0]
3303
3304
Similarly, a real symmetric matrix has only real eigenvalues,
3305
and there is an orthonormal basis composed of eigenvectors of
3306
the matrix. ::
3307
3308
sage: A = matrix(RDF, [[ 1, -2, 5, -3],
3309
... [-2, 9, 1, 5],
3310
... [ 5, 1, 3 , 7],
3311
... [-3, 5, 7, -8]])
3312
sage: Q, T = A.schur()
3313
sage: Q.round(4)
3314
[-0.3027 -0.751 0.576 -0.1121]
3315
[ 0.139 -0.3892 -0.2648 0.8713]
3316
[ 0.4361 0.359 0.7599 0.3217]
3317
[ -0.836 0.3945 0.1438 0.3533]
3318
sage: T = T.zero_at(10^-12)
3319
sage: all(abs(e) < 10^-4 for e in (T - diagonal_matrix(RDF, [-13.5698, -0.8508, 7.7664, 11.6542])).list())
3320
True
3321
sage: (Q*Q.transpose()).zero_at(1.0e-12)
3322
[1.0 0.0 0.0 0.0]
3323
[0.0 1.0 0.0 0.0]
3324
[0.0 0.0 1.0 0.0]
3325
[0.0 0.0 0.0 1.0]
3326
sage: (Q*T*Q.transpose()-A).zero_at(1.0e-11)
3327
[0.0 0.0 0.0 0.0]
3328
[0.0 0.0 0.0 0.0]
3329
[0.0 0.0 0.0 0.0]
3330
[0.0 0.0 0.0 0.0]
3331
3332
The results are cached, both as a real factorization and also as a
3333
complex factorization. This means the returned matrices are
3334
immutable. ::
3335
3336
sage: A = matrix(RDF, 2, 2, [[0, -1], [1, 0]])
3337
sage: Qr, Tr = A.schur(base_ring=RDF)
3338
sage: Qc, Tc = A.schur(base_ring=CDF)
3339
sage: all([M.is_immutable() for M in [Qr, Tr, Qc, Tc]])
3340
True
3341
sage: Tr.round(6) != Tc.round(6)
3342
True
3343
3344
TESTS:
3345
3346
The Schur factorization is only defined for square matrices. ::
3347
3348
sage: A = matrix(RDF, 4, 5, range(20))
3349
sage: A.schur()
3350
Traceback (most recent call last):
3351
...
3352
ValueError: Schur decomposition requires a square matrix, not a 4 x 5 matrix
3353
3354
A base ring request is checked. ::
3355
3356
sage: A = matrix(RDF, 3, range(9))
3357
sage: A.schur(base_ring=QQ)
3358
Traceback (most recent call last):
3359
...
3360
ValueError: base ring of Schur decomposition matrices must be RDF or CDF, not Rational Field
3361
3362
AUTHOR:
3363
3364
- Rob Beezer (2011-03-31)
3365
"""
3366
global scipy
3367
from sage.rings.real_double import RDF
3368
from sage.rings.complex_double import CDF
3369
3370
cdef Matrix_double_dense Q, T
3371
3372
if not self.is_square():
3373
raise ValueError('Schur decomposition requires a square matrix, not a {0} x {1} matrix'.format(self.nrows(), self.ncols()))
3374
if base_ring == None:
3375
base_ring = self.base_ring()
3376
if not base_ring in [RDF, CDF]:
3377
raise ValueError('base ring of Schur decomposition matrices must be RDF or CDF, not {0}'.format(base_ring))
3378
3379
if self.base_ring() != base_ring:
3380
try:
3381
self = self.change_ring(base_ring)
3382
except TypeError:
3383
raise TypeError('unable to convert input matrix over CDF to a matrix over RDF')
3384
if base_ring == CDF:
3385
format = 'complex'
3386
else:
3387
format = 'real'
3388
3389
schur = self.fetch('schur_factors_' + format)
3390
if not schur is None:
3391
return schur
3392
if scipy is None:
3393
import scipy
3394
import scipy.linalg
3395
Q = self._new(self._nrows, self._nrows)
3396
T = self._new(self._nrows, self._nrows)
3397
T._matrix_numpy, Q._matrix_numpy = scipy.linalg.schur(self._matrix_numpy, output=format)
3398
Q.set_immutable()
3399
T.set_immutable()
3400
# Our return order is the reverse of NumPy's
3401
schur = (Q, T)
3402
self.cache('schur_factors_' + format, schur)
3403
return schur
3404
3405
def cholesky(self):
3406
r"""
3407
Returns the Cholesky factorization of a matrix that
3408
is real symmetric, or complex Hermitian.
3409
3410
INPUT:
3411
3412
Any square matrix with entries from ``RDF`` that is symmetric, or
3413
with entries from ``CDF`` that is Hermitian. The matrix must
3414
be positive definite for the Cholesky decomposition to exist.
3415
3416
OUTPUT:
3417
3418
For a matrix `A` the routine returns a lower triangular
3419
matrix `L` such that,
3420
3421
.. math::
3422
3423
A = LL^\ast
3424
3425
where `L^\ast` is the conjugate-transpose in the complex case,
3426
and just the transpose in the real case. If the matrix fails
3427
to be positive definite (perhaps because it is not symmetric
3428
or Hermitian), then this function raises a ``ValueError``.
3429
3430
EXAMPLES:
3431
3432
A real matrix that is symmetric and positive definite. ::
3433
3434
sage: M = matrix(RDF,[[ 1, 1, 1, 1, 1],
3435
... [ 1, 5, 31, 121, 341],
3436
... [ 1, 31, 341, 1555, 4681],
3437
... [ 1,121, 1555, 7381, 22621],
3438
... [ 1,341, 4681, 22621, 69905]])
3439
sage: M.is_symmetric()
3440
True
3441
sage: L = M.cholesky()
3442
sage: L.round(6).zero_at(10^-10)
3443
[ 1.0 0.0 0.0 0.0 0.0]
3444
[ 1.0 2.0 0.0 0.0 0.0]
3445
[ 1.0 15.0 10.723805 0.0 0.0]
3446
[ 1.0 60.0 60.985814 7.792973 0.0]
3447
[ 1.0 170.0 198.623524 39.366567 1.7231]
3448
sage: (L*L.transpose()).round(6).zero_at(10^-10)
3449
[ 1.0 1.0 1.0 1.0 1.0]
3450
[ 1.0 5.0 31.0 121.0 341.0]
3451
[ 1.0 31.0 341.0 1555.0 4681.0]
3452
[ 1.0 121.0 1555.0 7381.0 22621.0]
3453
[ 1.0 341.0 4681.0 22621.0 69905.0]
3454
3455
A complex matrix that is Hermitian and positive definite. ::
3456
3457
sage: A = matrix(CDF, [[ 23, 17*I + 3, 24*I + 25, 21*I],
3458
... [ -17*I + 3, 38, -69*I + 89, 7*I + 15],
3459
... [-24*I + 25, 69*I + 89, 976, 24*I + 6],
3460
... [ -21*I, -7*I + 15, -24*I + 6, 28]])
3461
sage: A.is_hermitian()
3462
True
3463
sage: L = A.cholesky()
3464
sage: L.round(6).zero_at(10^-10)
3465
[ 4.795832 0.0 0.0 0.0]
3466
[ 0.625543 - 3.544745*I 5.004346 0.0 0.0]
3467
[ 5.21286 - 5.004346*I 13.588189 + 10.721116*I 24.984023 0.0]
3468
[ -4.378803*I -0.104257 - 0.851434*I -0.21486 + 0.371348*I 2.811799]
3469
sage: (L*L.conjugate_transpose()).round(6).zero_at(10^-10)
3470
[ 23.0 3.0 + 17.0*I 25.0 + 24.0*I 21.0*I]
3471
[ 3.0 - 17.0*I 38.0 89.0 - 69.0*I 15.0 + 7.0*I]
3472
[25.0 - 24.0*I 89.0 + 69.0*I 976.0 6.0 + 24.0*I]
3473
[ -21.0*I 15.0 - 7.0*I 6.0 - 24.0*I 28.0]
3474
3475
This routine will recognize when the input matrix is not
3476
positive definite. The negative eigenvalues are an
3477
equivalent indicator. (Eigenvalues of a Hermitian matrix
3478
must be real, so there is no loss in ignoring the imprecise
3479
imaginary parts). ::
3480
3481
sage: A = matrix(RDF, [[ 3, -6, 9, 6, -9],
3482
... [-6, 11, -16, -11, 17],
3483
... [ 9, -16, 28, 16, -40],
3484
... [ 6, -11, 16, 9, -19],
3485
... [-9, 17, -40, -19, 68]])
3486
sage: A.is_symmetric()
3487
True
3488
sage: A.eigenvalues()
3489
[108.07..., 13.02..., -0.02..., -0.70..., -1.37...]
3490
sage: A.cholesky()
3491
Traceback (most recent call last):
3492
...
3493
ValueError: matrix is not positive definite
3494
3495
sage: B = matrix(CDF, [[ 2, 4 - 2*I, 2 + 2*I],
3496
... [4 + 2*I, 8, 10*I],
3497
... [2 - 2*I, -10*I, -3]])
3498
sage: B.is_hermitian()
3499
True
3500
sage: [ev.real() for ev in B.eigenvalues()]
3501
[15.88..., 0.08..., -8.97...]
3502
sage: B.cholesky()
3503
Traceback (most recent call last):
3504
...
3505
ValueError: matrix is not positive definite
3506
3507
TESTS:
3508
3509
A trivial case. ::
3510
3511
sage: A = matrix(RDF, 0, [])
3512
sage: A.cholesky()
3513
[]
3514
3515
The Cholesky factorization is only defined for square matrices. ::
3516
3517
sage: A = matrix(RDF, 4, 5, range(20))
3518
sage: A.cholesky()
3519
Traceback (most recent call last):
3520
...
3521
ValueError: Cholesky decomposition requires a square matrix, not a 4 x 5 matrix
3522
"""
3523
from sage.rings.real_double import RDF
3524
from sage.rings.complex_double import CDF
3525
3526
cdef Matrix_double_dense L
3527
3528
if not self.is_square():
3529
msg = "Cholesky decomposition requires a square matrix, not a {0} x {1} matrix"
3530
raise ValueError(msg.format(self.nrows(), self.ncols()))
3531
if self._nrows == 0: # special case
3532
return self.__copy__()
3533
3534
L = self.fetch('cholesky')
3535
if L is None:
3536
L = self._new()
3537
global scipy
3538
if scipy is None:
3539
import scipy
3540
import scipy.linalg
3541
from numpy.linalg import LinAlgError
3542
try:
3543
L._matrix_numpy = scipy.linalg.cholesky(self._matrix_numpy, lower=1)
3544
except LinAlgError:
3545
raise ValueError("matrix is not positive definite")
3546
L.set_immutable()
3547
self.cache('cholesky', L)
3548
return L
3549
3550
cdef Vector _vector_times_matrix_(self,Vector v):
3551
if self._nrows == 0 or self._ncols == 0:
3552
return self._row_ambient_module().zero_vector()
3553
global numpy
3554
if numpy is None:
3555
import numpy
3556
3557
v_numpy = numpy.array([self._python_dtype(i) for i in v])
3558
3559
M = self._row_ambient_module()
3560
ans = numpy.dot(v_numpy,self._matrix_numpy)
3561
return M(ans)
3562
3563
cdef Vector _matrix_times_vector_(self,Vector v):
3564
if self._nrows == 0 or self._ncols == 0:
3565
return self._column_ambient_module().zero_vector()
3566
3567
global numpy
3568
if numpy is None:
3569
import numpy
3570
3571
v_numpy = numpy.array([self._python_dtype(i) for i in v], dtype=self._numpy_dtype)
3572
3573
M = self._column_ambient_module()
3574
ans = numpy.dot(self._matrix_numpy, v_numpy)
3575
return M(ans)
3576
3577
def numpy(self, dtype=None):
3578
"""
3579
This method returns a copy of the matrix as a numpy array. It
3580
uses the numpy C/api so is very fast.
3581
3582
INPUT:
3583
3584
- ``dtype`` - The desired data-type for the array. If not given,
3585
then the type will be determined as the minimum type required
3586
to hold the objects in the sequence.
3587
3588
EXAMPLES::
3589
3590
sage: m = matrix(RDF,[[1,2],[3,4]])
3591
sage: n = m.numpy()
3592
sage: import numpy
3593
sage: numpy.linalg.eig(n)
3594
(array([-0.37228132, 5.37228132]), array([[-0.82456484, -0.41597356],
3595
[ 0.56576746, -0.90937671]]))
3596
sage: m = matrix(RDF, 2, range(6)); m
3597
[0.0 1.0 2.0]
3598
[3.0 4.0 5.0]
3599
sage: m.numpy()
3600
array([[ 0., 1., 2.],
3601
[ 3., 4., 5.]])
3602
3603
Alternatively, numpy automatically calls this function (via
3604
the magic :meth:`__array__` method) to convert Sage matrices
3605
to numpy arrays::
3606
3607
sage: import numpy
3608
sage: m = matrix(RDF, 2, range(6)); m
3609
[0.0 1.0 2.0]
3610
[3.0 4.0 5.0]
3611
sage: numpy.array(m)
3612
array([[ 0., 1., 2.],
3613
[ 3., 4., 5.]])
3614
sage: numpy.array(m).dtype
3615
dtype('float64')
3616
sage: m = matrix(CDF, 2, range(6)); m
3617
[0.0 1.0 2.0]
3618
[3.0 4.0 5.0]
3619
sage: numpy.array(m)
3620
array([[ 0.+0.j, 1.+0.j, 2.+0.j],
3621
[ 3.+0.j, 4.+0.j, 5.+0.j]])
3622
sage: numpy.array(m).dtype
3623
dtype('complex128')
3624
3625
TESTS::
3626
3627
sage: m = matrix(RDF,0,5,[]); m
3628
[]
3629
sage: m.numpy()
3630
array([], shape=(0, 5), dtype=float64)
3631
sage: m = matrix(RDF,5,0,[]); m
3632
[]
3633
sage: m.numpy()
3634
array([], shape=(5, 0), dtype=float64)
3635
"""
3636
import numpy as np
3637
if dtype is None or self._numpy_dtype == np.dtype(dtype):
3638
return self._matrix_numpy.copy()
3639
else:
3640
return matrix_dense.Matrix_dense.numpy(self, dtype=dtype)
3641
3642
def _replace_self_with_numpy(self,numpy_matrix):
3643
"""
3644
3645
EXAMPLES::
3646
3647
sage: import numpy
3648
sage: a = numpy.array([[1,2],[3,4]], 'float64')
3649
sage: m = matrix(RDF,2,2,0)
3650
sage: m._replace_self_with_numpy(a)
3651
sage: m
3652
[1.0 2.0]
3653
[3.0 4.0]
3654
"""
3655
if (<object>self._matrix_numpy).shape != (<object>numpy_matrix).shape:
3656
raise ValueError("matrix shapes are not the same")
3657
self._matrix_numpy = numpy_matrix.astype(self._numpy_dtype)
3658
3659
3660
def _replace_self_with_numpy32(self,numpy_matrix):
3661
"""
3662
3663
EXAMPLES::
3664
3665
sage: import numpy
3666
sage: a = numpy.array([[1,2],[3,4]], 'float32')
3667
sage: m = matrix(RDF,2,2,0)
3668
sage: m._replace_self_with_numpy32(a)
3669
sage: m
3670
[1.0 2.0]
3671
[3.0 4.0]
3672
"""
3673
#TODO find where this is used and change it
3674
self._replace_self_with_numpy(numpy_matrix)
3675
3676
3677
def _hadamard_row_bound(self):
3678
r"""
3679
Return an integer n such that the absolute value of the
3680
determinant of this matrix is at most $10^n$.
3681
3682
EXAMPLES::
3683
3684
sage: a = matrix(RDF, 3, [1,2,5,7,-3,4,2,1,123])
3685
sage: a._hadamard_row_bound()
3686
4
3687
sage: a.det()
3688
-2014.0
3689
sage: 10^4
3690
10000
3691
"""
3692
cdef double d = 0, s
3693
cdef Py_ssize_t i, j
3694
for i from 0 <= i < self._nrows:
3695
s = 0
3696
for j from 0 <= j < self._ncols:
3697
s += self.get_unsafe(i,j)**2
3698
d += math.log(s)
3699
d /= 2
3700
return int(math.ceil(d / math.log(10)))
3701
3702
@rename_keyword(deprecated='Sage version 4.6', method="algorithm")
3703
def exp(self, algorithm='pade', order=None):
3704
r"""
3705
Calculate the exponential of this matrix X, which is the matrix
3706
3707
.. math::
3708
3709
e^X = \sum_{k=0}^{\infty} \frac{X^k}{k!}.
3710
3711
INPUT:
3712
3713
- algorithm -- 'pade', 'eig', or 'taylor'; the algorithm used to
3714
compute the exponential.
3715
3716
- order -- for Pade or Taylor series algorithms, order is the
3717
order of the Pade approximation or the order of the Taylor
3718
series used. The current defaults (from scipy) are 7 for
3719
'pade' and 20 for 'taylor'.
3720
3721
EXAMPLES::
3722
3723
sage: A=matrix(RDF, 2, [1,2,3,4]); A
3724
[1.0 2.0]
3725
[3.0 4.0]
3726
sage: A.exp()
3727
[51.9689561987 74.736564567]
3728
[112.104846851 164.073803049]
3729
sage: A.exp(algorithm='eig')
3730
[51.9689561987 74.736564567]
3731
[112.104846851 164.073803049]
3732
sage: A.exp(order=2)
3733
[51.8888631634 74.6198348038]
3734
[111.929752206 163.818615369]
3735
sage: A.exp(algorithm='taylor', order=5)
3736
[19.9583333333 28.0833333333]
3737
[ 42.125 62.0833333333]
3738
sage: A.exp(algorithm='taylor')
3739
[51.9689035511 74.7364878369]
3740
[112.104731755 164.073635306]
3741
3742
sage: A=matrix(CDF, 2, [1,2+I,3*I,4]); A
3743
[ 1.0 2.0 + 1.0*I]
3744
[ 3.0*I 4.0]
3745
sage: A.exp()
3746
[-19.6146029538 + 12.5177438468*I 3.79496364496 + 28.8837993066*I]
3747
[-32.3835809809 + 21.8842359579*I 2.26963300409 + 44.9013248277*I]
3748
sage: A.exp(algorithm='eig')
3749
[-19.6146029538 + 12.5177438468*I 3.79496364496 + 28.8837993066*I]
3750
[-32.3835809809 + 21.8842359579*I 2.26963300409 + 44.9013248277*I]
3751
sage: A.exp(order=2)
3752
[-19.6130852955 + 12.5327938535*I 3.81156364812 + 28.891438232*I]
3753
[-32.3827876895 + 21.9087393169*I 2.29565402142 + 44.915581543*I]
3754
sage: A.exp(algorithm='taylor', order=5)
3755
[ -6.29166666667 + 14.25*I 14.0833333333 + 15.7916666667*I]
3756
[ -10.5 + 26.375*I 20.0833333333 + 24.75*I]
3757
sage: A.exp(algorithm='taylor')
3758
[-19.6146006163 + 12.5177432169*I 3.79496442472 + 28.8837964828*I]
3759
[-32.3835771246 + 21.8842351994*I 2.26963458304 + 44.9013203415*I]
3760
"""
3761
if algorithm not in ('pade', 'eig', 'taylor'):
3762
raise ValueError("algorithm must be 'pade', 'eig', or 'taylor'")
3763
3764
global scipy
3765
if scipy is None:
3766
import scipy
3767
import scipy.linalg
3768
3769
cdef Matrix_double_dense M
3770
M = self._new()
3771
3772
if algorithm=='pade':
3773
if order is None:
3774
M._matrix_numpy = scipy.linalg.expm(self._matrix_numpy)
3775
else:
3776
M._matrix_numpy = scipy.linalg.expm(self._matrix_numpy, q=order)
3777
elif algorithm=='eig':
3778
M._matrix_numpy = scipy.linalg.expm2(self._matrix_numpy)
3779
elif algorithm=='taylor':
3780
if order is None:
3781
M._matrix_numpy = scipy.linalg.expm3(self._matrix_numpy)
3782
else:
3783
M._matrix_numpy = scipy.linalg.expm3(self._matrix_numpy, q=order)
3784
3785
return M
3786
3787
def zero_at(self, eps):
3788
"""
3789
Returns a copy of the matrix where elements smaller than or
3790
equal to ``eps`` are replaced with zeroes. For complex matrices,
3791
the real and imaginary parts are considered individually.
3792
3793
This is useful for modifying output from algorithms which have large
3794
relative errors when producing zero elements, e.g. to create reliable
3795
doctests.
3796
3797
INPUT:
3798
3799
- ``eps`` - Cutoff value
3800
3801
OUTPUT:
3802
3803
A modified copy of the matrix.
3804
3805
EXAMPLES::
3806
3807
sage: a=matrix([[1, 1e-4r, 1+1e-100jr], [1e-8+3j, 0, 1e-58r]])
3808
sage: a
3809
[ 1.0 0.0001 1.0 + 1e-100*I]
3810
[ 1e-08 + 3.0*I 0.0 1e-58]
3811
sage: a.zero_at(1e-50)
3812
[ 1.0 0.0001 1.0]
3813
[1e-08 + 3.0*I 0.0 0.0]
3814
sage: a.zero_at(1e-4)
3815
[ 1.0 0.0 1.0]
3816
[3.0*I 0.0 0.0]
3817
3818
3819
3820
"""
3821
global numpy
3822
cdef Matrix_double_dense M
3823
if numpy is None:
3824
import numpy
3825
eps = float(eps)
3826
out = self._matrix_numpy.copy()
3827
if self._sage_dtype is sage.rings.complex_double.CDF:
3828
out.real[numpy.abs(out.real) <= eps] = 0
3829
out.imag[numpy.abs(out.imag) <= eps] = 0
3830
else:
3831
out[numpy.abs(out) <= eps] = 0
3832
M = self._new()
3833
M._matrix_numpy = out
3834
return M
3835
3836
def round(self, ndigits=0):
3837
"""
3838
Returns a copy of the matrix where all entries have been rounded
3839
to a given precision in decimal digits (default 0 digits).
3840
3841
INPUT:
3842
3843
- ``ndigits`` - The precision in number of decimal digits
3844
3845
OUTPUT:
3846
3847
A modified copy of the matrix
3848
3849
EXAMPLES::
3850
3851
sage: M=matrix(CDF, [[10.234r + 34.2343jr, 34e10r]])
3852
sage: M
3853
[10.234 + 34.2343*I 3.4e+11]
3854
sage: M.round(2)
3855
[10.23 + 34.23*I 3.4e+11]
3856
sage: M.round()
3857
[10.0 + 34.0*I 3.4e+11]
3858
"""
3859
global numpy
3860
cdef Matrix_double_dense M
3861
if numpy is None:
3862
import numpy
3863
ndigits = int(ndigits)
3864
M = self._new()
3865
M._matrix_numpy = numpy.round(self._matrix_numpy, ndigits)
3866
return M
3867
3868