"""
Base class for matrices, part 0
.. note::
For design documentation see matrix/docs.py.
EXAMPLES::
sage: matrix(2,[1,2,3,4])
[1 2]
[3 4]
"""
include "../ext/stdsage.pxi"
include "../ext/cdefs.pxi"
include "../ext/python.pxi"
include "../ext/python_list.pxi"
include "../ext/python_object.pxi"
include "../ext/python_slice.pxi"
include "../ext/python_tuple.pxi"
import sage.modules.free_module
import sage.misc.latex
import sage.rings.integer
from sage.misc.misc import verbose, get_verbose
from sage.structure.sequence import Sequence
cimport sage.structure.element
from sage.structure.element cimport ModuleElement, Element, RingElement, Vector
from sage.structure.mutability cimport Mutability
from sage.misc.misc_c cimport normalize_index
from sage.rings.ring cimport CommutativeRing
from sage.rings.ring import is_Ring
from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing
import sage.modules.free_module
import matrix_misc
cdef extern from "Python.h":
bint PySlice_Check(PyObject* ob)
cdef class Matrix(sage.structure.element.Matrix):
r"""
A generic matrix.
The ``Matrix`` class is the base class for all matrix
classes. To create a ``Matrix``, first create a
``MatrixSpace``, then coerce a list of elements into
the ``MatrixSpace``. See the documentation of
``MatrixSpace`` for more details.
EXAMPLES:
We illustrate matrices and matrix spaces. Note that no actual
matrix that you make should have class Matrix; the class should
always be derived from Matrix.
::
sage: M = MatrixSpace(CDF,2,3); M
Full MatrixSpace of 2 by 3 dense matrices over Complex Double Field
sage: a = M([1,2,3, 4,5,6]); a
[1.0 2.0 3.0]
[4.0 5.0 6.0]
sage: type(a)
<type 'sage.matrix.matrix_complex_double_dense.Matrix_complex_double_dense'>
sage: parent(a)
Full MatrixSpace of 2 by 3 dense matrices over Complex Double Field
::
sage: matrix(CDF, 2,3, [1,2,3, 4,5,6])
[1.0 2.0 3.0]
[4.0 5.0 6.0]
sage: Mat(CDF,2,3)(range(1,7))
[1.0 2.0 3.0]
[4.0 5.0 6.0]
::
sage: Q.<i,j,k> = QuaternionAlgebra(QQ, -1,-1)
sage: matrix(Q,2,1,[1,2])
[1]
[2]
"""
def __init__(self, parent):
"""
EXAMPLES::
sage: import sage.matrix.matrix0
sage: A = sage.matrix.matrix0.Matrix(MatrixSpace(QQ,2))
sage: type(A)
<type 'sage.matrix.matrix0.Matrix'>
"""
self._parent = parent
self._base_ring = parent.base_ring()
self._nrows = parent.nrows()
self._ncols = parent.ncols()
self._mutability = Mutability(False)
self._cache = {}
def copy(self):
"""
Make a copy of self. If self is immutable, the copy will be
mutable.
.. warning::
This method is deprecated and will be removed from a future
version of Sage. Please use the ``copy()`` function
instead. In other words, instead of doing ``m.copy()``, do ``copy(m)``.
.. warning::
The individual elements aren't themselves copied (though
the list is copied). This shouldn't matter, since ring
elements are (almost!) always immutable in Sage.
EXAMPLES:
The :meth:`.copy` method is deprecated. Instead, use the
:func:`copy` function::
sage: a = matrix([[1,2],[3,4]])
sage: b = a.copy()
doctest:...: DeprecationWarning: the .copy() method is deprecated; please use the copy() function instead, for example, copy(M)
sage: b = copy(a)
::
sage: R.<x> = QQ['x']
sage: a = matrix(R,2,[x+1,2/3, x^2/2, 1+x^3]); a
[ x + 1 2/3]
[1/2*x^2 x^3 + 1]
sage: b = copy(a)
sage: b[0,0] = 5
sage: b
[ 5 2/3]
[1/2*x^2 x^3 + 1]
sage: a
[ x + 1 2/3]
[1/2*x^2 x^3 + 1]
::
sage: b = copy(a)
sage: f = b[0,0]; f[0] = 10
Traceback (most recent call last):
...
IndexError: polynomials are immutable
"""
import sage.misc.misc
sage.misc.misc.deprecation("the .copy() method is deprecated; please use the copy() function instead, for example, copy(M)")
return self.__copy__()
def list(self):
"""
List of the elements of self ordered by elements in each
row. It is safe to change the returned list.
.. warning::
This function returns a list of the entries in the matrix
self. It does not return a list of the rows of self, so it
is different than the output of list(self), which returns
``[self[0],self[1],...]``.
EXAMPLES::
sage: R.<x,y> = QQ[]
sage: a = matrix(R,2,[x,y,x*y, y,x,2*x+y]); a
[ x y x*y]
[ y x 2*x + y]
sage: v = a.list(); v
[x, y, x*y, y, x, 2*x + y]
Note that list(a) is different than a.list()::
sage: a.list()
[x, y, x*y, y, x, 2*x + y]
sage: list(a)
[(x, y, x*y), (y, x, 2*x + y)]
Notice that changing the returned list does not change a (the list
is a copy)::
sage: v[0] = 25
sage: a
[ x y x*y]
[ y x 2*x + y]
"""
return list(self._list())
def _list(self):
"""
Unsafe version of the list method, mainly for internal use. This
may return the list of elements, but as an *unsafe* reference to
the underlying list of the object. It is might be dangerous if you
change entries of the returned list.
EXAMPLES: Using _list is potentially fast and memory efficient,
but very dangerous (at least for generic dense matrices).
::
sage: a = matrix(QQ['x,y'],2,range(6)); a
[0 1 2]
[3 4 5]
sage: v = a._list(); v
[0, 1, 2, 3, 4, 5]
If you change an entry of the list, the corresponding entry of the
matrix will be changed (but without clearing any caches of
computing information about the matrix)::
sage: v[0] = -2/3; v
[-2/3, 1, 2, 3, 4, 5]
sage: a._list()
[-2/3, 1, 2, 3, 4, 5]
Now the 0,0 entry of the matrix is `-2/3`, which is weird.
::
sage: a[0,0]
-2/3
See::
sage: a
[-2/3 1 2]
[ 3 4 5]
"""
cdef Py_ssize_t i, j
x = self.fetch('list')
if not x is None:
return x
x = []
for i from 0 <= i < self._nrows:
for j from 0 <= j < self._ncols:
x.append(self.get_unsafe(i, j))
return x
def dict(self):
"""
Dictionary of the elements of self with keys pairs (i,j) and values
the nonzero entries of self.
It is safe to change the returned dictionary.
EXAMPLES::
sage: R.<x,y> = QQ[]
sage: a = matrix(R,2,[x,y,0, 0,0,2*x+y]); a
[ x y 0]
[ 0 0 2*x + y]
sage: d = a.dict(); d
{(0, 1): y, (1, 2): 2*x + y, (0, 0): x}
Notice that changing the returned list does not change a (the list
is a copy)::
sage: d[0,0] = 25
sage: a
[ x y 0]
[ 0 0 2*x + y]
"""
return dict(self._dict())
def _dict(self):
"""
Unsafe version of the dict method, mainly for internal use.
This may return the dict of elements, but as an *unsafe*
reference to the underlying dict of the object. It might
dangerous if you change entries of the returned dict.
EXAMPLES: Using _dict is potentially fast and memory efficient,
but very dangerous (at least for generic sparse matrices).
::
sage: a = matrix(QQ['x,y'],2,range(6), sparse=True); a
[0 1 2]
[3 4 5]
sage: v = a._dict(); v
{(0, 1): 1, (1, 2): 5, (1, 0): 3, (0, 2): 2, (1, 1): 4}
If you change a key of the dictionary, the corresponding entry of
the matrix will be changed (but without clearing any caches of
computing information about the matrix)::
sage: v[0,1] = -2/3; v
{(0, 1): -2/3, (1, 2): 5, (1, 0): 3, (0, 2): 2, (1, 1): 4}
sage: a._dict()
{(0, 1): -2/3, (1, 2): 5, (1, 0): 3, (0, 2): 2, (1, 1): 4}
sage: a[0,1]
-2/3
But the matrix doesn't know the entry changed, so it returns the
cached version of its print representation::
sage: a
[0 1 2]
[3 4 5]
If we change an entry, the cache is cleared, and the correct print
representation appears::
sage: a[1,2]=10
sage: a
[ 0 -2/3 2]
[ 3 4 10]
"""
d = self.fetch('dict')
if not d is None:
return d
cdef Py_ssize_t i, j
d = {}
for i from 0 <= i < self._nrows:
for j from 0 <= j < self._ncols:
x = self.get_unsafe(i, j)
if x != 0:
d[(int(i),int(j))] = x
self.cache('dict', d)
return d
def _clear_cache(self):
"""
Clear anything cached about this matrix.
EXAMPLES::
sage: m=Matrix(QQ,2,range(0,4))
sage: m._clear_cache()
"""
self.clear_cache()
cdef clear_cache(self):
"""
Clear the properties cache.
"""
self._cache = None
cdef fetch(self, key):
"""
Try to get an element from the cache; if there isn't anything
there, return None.
"""
if self._cache is None:
return None
try:
return self._cache[key]
except KeyError:
return None
cdef cache(self, key, x):
"""
Record x in the cache with given key.
"""
if self._cache is None:
self._cache = {}
self._cache[key] = x
def _get_cache(self):
"""
Return the cache.
EXAMPLES::
sage: m=Matrix(QQ,2,range(0,4))
sage: m._get_cache()
{}
"""
return self._cache
cdef check_bounds(self, Py_ssize_t i, Py_ssize_t j):
"""
This function gets called when you're about to access the i,j entry
of this matrix. If i, j are out of range, an IndexError is
raised.
"""
if i<0 or i >= self._nrows or j<0 or j >= self._ncols:
raise IndexError("matrix index out of range")
cdef check_mutability(self):
"""
This function gets called when you're about to change this matrix.
If self is immutable, a ValueError is raised, since you should
never change a mutable matrix.
If self is mutable, the cache of results about self is deleted.
"""
if self._mutability._is_immutable:
raise ValueError("matrix is immutable; please change a copy instead (i.e., use copy(M) to change a copy of M).")
else:
self._cache = {}
cdef check_bounds_and_mutability(self, Py_ssize_t i, Py_ssize_t j):
"""
This function gets called when you're about to set the i,j entry of
this matrix. If i or j is out of range, an IndexError exception is
raised.
If self is immutable, a ValueError is raised, since you should
never change a mutable matrix.
If self is mutable, the cache of results about self is deleted.
"""
if self._mutability._is_immutable:
raise ValueError("matrix is immutable; please change a copy instead (i.e., use copy(M) to change a copy of M).")
else:
self._cache = {}
if i<0 or i >= self._nrows or j<0 or j >= self._ncols:
raise IndexError("matrix index out of range")
def set_immutable(self):
r"""
Call this function to set the matrix as immutable.
Matrices are always mutable by default, i.e., you can change their
entries using ``A[i,j] = x``. However, mutable matrices
aren't hashable, so can't be used as keys in dictionaries, etc.
Also, often when implementing a class, you might compute a matrix
associated to it, e.g., the matrix of a Hecke operator. If you
return this matrix to the user you're really returning a reference
and the user could then change an entry; this could be confusing.
Thus you should set such a matrix immutable.
EXAMPLES::
sage: A = Matrix(QQ, 2, 2, range(4))
sage: A.is_mutable()
True
sage: A[0,0] = 10
sage: A
[10 1]
[ 2 3]
Mutable matrices are not hashable, so can't be used as keys for
dictionaries::
sage: hash(A)
Traceback (most recent call last):
...
TypeError: mutable matrices are unhashable
sage: v = {A:1}
Traceback (most recent call last):
...
TypeError: mutable matrices are unhashable
If we make A immutable it suddenly is hashable.
::
sage: A.set_immutable()
sage: A.is_mutable()
False
sage: A[0,0] = 10
Traceback (most recent call last):
...
ValueError: matrix is immutable; please change a copy instead (i.e., use copy(M) to change a copy of M).
sage: hash(A) #random
12
sage: v = {A:1}; v
{[10 1]
[ 2 3]: 1}
"""
self._mutability.set_immutable()
def is_immutable(self):
"""
Return True if this matrix is immutable.
See the documentation for self.set_immutable for more details
about mutability.
EXAMPLES::
sage: A = Matrix(QQ['t','s'], 2, 2, range(4))
sage: A.is_immutable()
False
sage: A.set_immutable()
sage: A.is_immutable()
True
"""
return self._mutability._is_immutable
def is_mutable(self):
"""
Return True if this matrix is mutable.
See the documentation for self.set_immutable for more details
about mutability.
EXAMPLES::
sage: A = Matrix(QQ['t','s'], 2, 2, range(4))
sage: A.is_mutable()
True
sage: A.set_immutable()
sage: A.is_mutable()
False
"""
return self._mutability.is_mutable()
cdef set_unsafe(self, Py_ssize_t i, Py_ssize_t j, object x):
"""
Set entry quickly without doing any bounds checking. Calling this
with invalid arguments is allowed to produce a segmentation fault.
This is fast since it is a cdef function and there is no bounds
checking.
"""
raise NotImplementedError("this must be defined in the derived class (type=%s)"%type(self))
cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j):
"""
Entry access, but fast since it might be without bounds checking.
This is fast since it is a cdef function and there is no bounds
checking.
"""
raise NotImplementedError("this must be defined in the derived type.")
def __iter__(self):
"""
Return an iterator for the rows of self
EXAMPLES::
sage: m=matrix(2,[1,2,3,4])
sage: m.__iter__().next()
(1, 2)
"""
return matrix_misc.row_iterator(self)
def __getitem__(self, key):
"""
Return element, row, or slice of self.
INPUT:
- ``key``- tuple (i,j) where i, j can be integers, slices or lists
USAGE:
- ``A[i, j]`` - the i,j element (or elements, if i or j are
slices or lists) of A, or
- ``A[i:j]`` - rows of A, according to slice notation
EXAMPLES::
sage: A = Matrix(Integers(2006),2,2,[-1,2,3,4])
sage: A[0,0]
2005
sage: A[0]
(2005, 2)
The returned row is immutable (mainly to avoid confusion)::
sage: A[0][0] = 123
Traceback (most recent call last):
...
ValueError: vector is immutable; please change a copy instead (use copy())
sage: A[0].is_immutable()
True
sage: a = matrix(ZZ,3,range(9)); a
[0 1 2]
[3 4 5]
[6 7 8]
sage: a[1,2]
5
sage: a[0]
(0, 1, 2)
sage: a[4,7]
Traceback (most recent call last):
...
IndexError: matrix index out of range
sage: a[-1,0]
6
::
sage: a[2.7]
Traceback (most recent call last):
...
TypeError: index must be an integer
sage: a[1, 2.7]
Traceback (most recent call last):
...
TypeError: index must be an integer
sage: a[2.7, 1]
Traceback (most recent call last):
...
TypeError: index must be an integer
sage: m=[(1, -2, -1, -1,9), (1, 8, 6, 2,2), (1, 1, -1, 1,4), (-1, 2, -2, -1,4)];M= matrix(m)
sage: M
[ 1 -2 -1 -1 9]
[ 1 8 6 2 2]
[ 1 1 -1 1 4]
[-1 2 -2 -1 4]
Get the 2 x 2 submatrix of M, starting at row index and column
index 1
::
sage: M[1:3,1:3]
[ 8 6]
[ 1 -1]
Get the 2 x 3 submatrix of M starting at row index and column index
1::
sage: M[1:3,[1..3]]
[ 8 6 2]
[ 1 -1 1]
Get the second column of M::
sage: M[:,1]
[-2]
[ 8]
[ 1]
[ 2]
Get the first row of M::
sage: M[0,:]
[ 1 -2 -1 -1 9]
More examples::
sage: M[range(2),:]
[ 1 -2 -1 -1 9]
[ 1 8 6 2 2]
sage: M[range(2),4]
[9]
[2]
sage: M[range(3),range(5)]
[ 1 -2 -1 -1 9]
[ 1 8 6 2 2]
[ 1 1 -1 1 4]
::
sage: M[3,range(5)]
[-1 2 -2 -1 4]
sage: M[3,:]
[-1 2 -2 -1 4]
sage: M[3,4]
4
sage: M[-1,:]
[-1 2 -2 -1 4]
sage: A = matrix(ZZ,3,4, [3, 2, -5, 0, 1, -1, 1, -4, 1, 0, 1, -3]); A
[ 3 2 -5 0]
[ 1 -1 1 -4]
[ 1 0 1 -3]
::
sage: A[:,0:4:2]
[ 3 -5]
[ 1 1]
[ 1 1]
::
sage: A[1:,0:4:2]
[1 1]
[1 1]
sage: A[2::-1,:]
[ 1 0 1 -3]
[ 1 -1 1 -4]
[ 3 2 -5 0]
sage: A[1:,3::-1]
[-4 1 -1 1]
[-3 1 0 1]
sage: A[1:,3::-2]
[-4 -1]
[-3 0]
sage: A[2::-1,3:1:-1]
[-3 1]
[-4 1]
[ 0 -5]
::
sage: A= matrix(3,4,[1, 0, -3, -1, 3, 0, -2, 1, -3, -5, -1, -5])
sage: A[range(2,-1,-1),:]
[-3 -5 -1 -5]
[ 3 0 -2 1]
[ 1 0 -3 -1]
::
sage: A[range(2,-1,-1),range(3,-1,-1)]
[-5 -1 -5 -3]
[ 1 -2 0 3]
[-1 -3 0 1]
::
sage: A = matrix(2, [1, 2, 3, 4])
sage: A[[0,0],[0,0]]
[1 1]
[1 1]
::
sage: M = matrix(3, 4, range(12))
sage: M[0:0, 0:0]
[]
sage: M[0:0, 1:4]
[]
sage: M[2:3, 3:3]
[]
sage: M[range(2,2), :3]
[]
sage: M[(1,2), 3]
[ 7]
[11]
sage: M[(1,2),(0,1,1)]
[4 5 5]
[8 9 9]
sage: m=[(1, -2, -1, -1), (1, 8, 6, 2), (1, 1, -1, 1), (-1, 2, -2, -1)]
sage: M= matrix(m);M
[ 1 -2 -1 -1]
[ 1 8 6 2]
[ 1 1 -1 1]
[-1 2 -2 -1]
sage: M[:2]
[ 1 -2 -1 -1]
[ 1 8 6 2]
sage: M[:]
[ 1 -2 -1 -1]
[ 1 8 6 2]
[ 1 1 -1 1]
[-1 2 -2 -1]
sage: M[1:3]
[ 1 8 6 2]
[ 1 1 -1 1]
sage: A=matrix(QQ,10,range(100))
sage: A[0:3]
[ 0 1 2 3 4 5 6 7 8 9]
[10 11 12 13 14 15 16 17 18 19]
[20 21 22 23 24 25 26 27 28 29]
sage: A[:2]
[ 0 1 2 3 4 5 6 7 8 9]
[10 11 12 13 14 15 16 17 18 19]
sage: A[8:]
[80 81 82 83 84 85 86 87 88 89]
[90 91 92 93 94 95 96 97 98 99]
sage: A[1:10:3]
[10 11 12 13 14 15 16 17 18 19]
[40 41 42 43 44 45 46 47 48 49]
[70 71 72 73 74 75 76 77 78 79]
sage: A[-1]
(90, 91, 92, 93, 94, 95, 96, 97, 98, 99)
sage: A[-1:-6:-2]
[90 91 92 93 94 95 96 97 98 99]
[70 71 72 73 74 75 76 77 78 79]
[50 51 52 53 54 55 56 57 58 59]
sage: A[3].is_immutable()
True
sage: A[1:3].is_immutable()
True
TESTS:
If we're given lists as arguments, we should throw an
appropriate error when those lists do not contain valid
indices (trac #6569)::
sage: A = matrix(4, range(1,17))
sage: A[[1.5], [1]]
Traceback (most recent call last):
...
IndexError: row indices must be integers
sage: A[[1], [1.5]]
Traceback (most recent call last):
...
IndexError: column indices must be integers
sage: A[[1.5]]
Traceback (most recent call last):
...
IndexError: row indices must be integers
Before trac #6569 was fixed, sparse/dense matrices behaved
differently due to implementation details. Given invalid
indices, they should fail in the same manner. These tests
just repeat the previous set with a sparse matrix::
sage: A = matrix(4, range(1,17), sparse=True)
sage: A[[1.5], [1]]
Traceback (most recent call last):
...
IndexError: row indices must be integers
sage: A[[1], [1.5]]
Traceback (most recent call last):
...
IndexError: column indices must be integers
sage: A[[1.5]]
Traceback (most recent call last):
...
IndexError: row indices must be integers
"""
cdef list row_list
cdef list col_list
cdef Py_ssize_t i
cdef int row, col
cdef int nrows = self._nrows
cdef int ncols = self._ncols
cdef tuple key_tuple
cdef object row_index, col_index
cdef int ind
cdef int single_row = 0, single_col = 0
if PyTuple_CheckExact(key):
key_tuple = <tuple>key
if len(key_tuple) != 2:
raise IndexError("index must be an integer or pair of integers")
row_index = <object>PyTuple_GET_ITEM(key_tuple, 0)
col_index = <object>PyTuple_GET_ITEM(key_tuple, 1)
if PyList_CheckExact(row_index) or PyTuple_CheckExact(row_index):
if PyTuple_CheckExact(row_index):
row_list = list(row_index)
else:
row_list = row_index
for i from 0 <= i < len(row_list):
if not PyIndex_Check(row_list[i]):
raise IndexError('row indices must be integers')
ind = row_list[i]
if ind < 0:
ind += nrows
row_list[i] = ind
if ind < 0 or ind >= nrows:
raise IndexError("matrix index out of range")
elif PySlice_Check(<PyObject *>row_index):
row_list = range(*row_index.indices(nrows))
else:
if not PyIndex_Check(row_index):
raise TypeError("index must be an integer")
row = row_index
if row < 0:
row += nrows
if row < 0 or row >= nrows:
raise IndexError("matrix index out of range")
single_row = 1
if PyList_CheckExact(col_index) or PyTuple_CheckExact(col_index):
if PyTuple_CheckExact(col_index):
col_list = list(col_index)
else:
col_list = col_index
for i from 0 <= i < len(col_list):
if not PyIndex_Check(col_list[i]):
raise IndexError('column indices must be integers')
ind = col_list[i]
if ind < 0:
ind += ncols
col_list[i] = ind
if ind < 0 or ind >= ncols:
raise IndexError("matrix index out of range")
elif PySlice_Check(<PyObject *>col_index):
col_list = range(*col_index.indices(ncols))
else:
if not PyIndex_Check(col_index):
raise TypeError("index must be an integer")
col = col_index
if col < 0:
col += ncols
if col < 0 or col >= ncols:
raise IndexError("matrix index out of range")
single_col = 1
if single_row and single_col:
return self.get_unsafe(row, col)
if single_row:
row_list = [row]
if single_col:
col_list = [col]
if len(row_list) == 0 or len(col_list) == 0:
return self.new_matrix(nrows=0,ncols=0)
return self.matrix_from_rows_and_columns(row_list,col_list)
row_index = key
if PyList_CheckExact(row_index) or PyTuple_CheckExact(row_index):
if PyTuple_CheckExact(row_index):
row_list = list(row_index)
else:
row_list = row_index
for i from 0 <= i < len(row_list):
if not PyIndex_Check(row_list[i]):
raise IndexError('row indices must be integers')
ind = row_list[i]
if ind < 0:
ind += nrows
row_list[i] = ind
if ind < 0 or ind >= nrows:
raise IndexError("matrix index out of range")
r = self.matrix_from_rows(row_list)
elif PySlice_Check(<PyObject *>row_index):
row_list = range(*row_index.indices(nrows))
r = self.matrix_from_rows(row_list)
else:
if not PyIndex_Check(row_index):
raise TypeError("index must be an integer")
row = row_index
if row < 0:
row += nrows
if row < 0 or row >= nrows:
raise IndexError("matrix index out of range")
r = self.row(row)
r.set_immutable()
return r
def __setitem__(self, key, value):
"""
Set elements of this matrix to values given in value.
INPUT:
- ``key`` - any legal indexing (i.e., such that self[key] works)
- ``value`` - values that are used to set the elements indicated by key.
EXAMPLES::
sage: A = Matrix(Integers(2006),2,2,[-1,2,3,4])
sage: A[0,0]=43; A
[43 2]
[ 3 4]
sage: A[0]=[10,20]; A
[10 20]
[ 3 4]
sage: M=matrix([(1, -2, -1, -1,9), (1, 8, 6, 2,2), (1, 1, -1, 1,4), (-1, 2, -2, -1,4)]); M
[ 1 -2 -1 -1 9]
[ 1 8 6 2 2]
[ 1 1 -1 1 4]
[-1 2 -2 -1 4]
Set the 2 x 2 submatrix of M, starting at row index and column
index 1::
sage: M[1:3,1:3] = [[1,0],[0,1]]; M
[ 1 -2 -1 -1 9]
[ 1 1 0 2 2]
[ 1 0 1 1 4]
[-1 2 -2 -1 4]
Set the 2 x 3 submatrix of M starting at row index and column
index 1::
sage: M[1:3,[1..3]] = M[2:4,0:3]; M
[ 1 -2 -1 -1 9]
[ 1 1 0 1 2]
[ 1 -1 2 -2 4]
[-1 2 -2 -1 4]
Set part of the first column of M::
sage: M[1:,0]=[[2],[3],[4]]; M
[ 1 -2 -1 -1 9]
[ 2 1 0 1 2]
[ 3 -1 2 -2 4]
[ 4 2 -2 -1 4]
Or do a similar thing with a vector::
sage: M[1:,0]=vector([-2,-3,-4]); M
[ 1 -2 -1 -1 9]
[-2 1 0 1 2]
[-3 -1 2 -2 4]
[-4 2 -2 -1 4]
Or a constant::
sage: M[1:,0]=30; M
[ 1 -2 -1 -1 9]
[30 1 0 1 2]
[30 -1 2 -2 4]
[30 2 -2 -1 4]
Set the first row of M::
sage: M[0,:]=[[20,21,22,23,24]]; M
[20 21 22 23 24]
[30 1 0 1 2]
[30 -1 2 -2 4]
[30 2 -2 -1 4]
sage: M[0,:]=vector([0,1,2,3,4]); M
[ 0 1 2 3 4]
[30 1 0 1 2]
[30 -1 2 -2 4]
[30 2 -2 -1 4]
sage: M[0,:]=-3; M
[-3 -3 -3 -3 -3]
[30 1 0 1 2]
[30 -1 2 -2 4]
[30 2 -2 -1 4]
sage: A = matrix(ZZ,3,4, [3, 2, -5, 0, 1, -1, 1, -4, 1, 0, 1, -3]); A
[ 3 2 -5 0]
[ 1 -1 1 -4]
[ 1 0 1 -3]
We can use the step feature of slices to set every other column::
sage: A[:,0:3:2] = 5; A
[ 5 2 5 0]
[ 5 -1 5 -4]
[ 5 0 5 -3]
sage: A[1:,0:4:2] = [[100,200],[300,400]]; A
[ 5 2 5 0]
[100 -1 200 -4]
[300 0 400 -3]
We can also count backwards to flip the matrix upside down.
::
sage: A[::-1,:]=A; A
[300 0 400 -3]
[100 -1 200 -4]
[ 5 2 5 0]
sage: A[1:,3::-1]=[[2,3,0,1],[9,8,7,6]]; A
[300 0 400 -3]
[ 1 0 3 2]
[ 6 7 8 9]
sage: A[1:,::-2] = A[1:,::2]; A
[300 0 400 -3]
[ 1 3 3 1]
[ 6 8 8 6]
sage: A[::-1,3:1:-1] = [[4,3],[1,2],[-1,-2]]; A
[300 0 -2 -1]
[ 1 3 2 1]
[ 6 8 3 4]
TESTS::
sage: A = MatrixSpace(ZZ,3)(range(9)); A
[0 1 2]
[3 4 5]
[6 7 8]
sage: A[1,2]=100; A
[ 0 1 2]
[ 3 4 100]
[ 6 7 8]
sage: A[0]=(10,20,30); A
[ 10 20 30]
[ 3 4 100]
[ 6 7 8]
sage: A[4,7]=45
Traceback (most recent call last):
...
IndexError: index out of range
sage: A[-1,0]=63; A[-1,0]
63
sage: A[2.7]=3
Traceback (most recent call last):
...
TypeError: index must be an integer or slice or a tuple/list of integers and slices
sage: A[1, 2.7]=3
Traceback (most recent call last):
...
TypeError: index must be an integer or slice or a tuple/list of integers and slices
sage: A[2.7, 1]=3
Traceback (most recent call last):
...
TypeError: index must be an integer or slice or a tuple/list of integers and slices
sage: A.set_immutable()
sage: A[0,0] = 7
Traceback (most recent call last):
...
ValueError: matrix is immutable; please change a copy instead (i.e., use copy(M) to change a copy of M).
sage: A=matrix([[1,2],[3,4]]); B=matrix([[1,3],[5,7]])
sage: A[1:2,1:2]=B[1:2,1:2]
sage: A
[1 2]
[3 7]
sage: A=matrix([[1,2],[3,4]]); B=matrix([[1,3],[5,7]])
sage: A[1,0:1]=B[1,1:2]
sage: A
[1 2]
[7 4]
More examples::
sage: M[range(2),:]=[[1..5], [6..10]]; M
[ 1 2 3 4 5]
[ 6 7 8 9 10]
[30 -1 2 -2 4]
[30 2 -2 -1 4]
sage: M[range(2),4]=0; M
[ 1 2 3 4 0]
[ 6 7 8 9 0]
[30 -1 2 -2 4]
[30 2 -2 -1 4]
sage: M[range(3),range(5)]=M[range(1,4), :]; M
[ 6 7 8 9 0]
[30 -1 2 -2 4]
[30 2 -2 -1 4]
[30 2 -2 -1 4]
sage: M[3,range(5)]=vector([-2,3,4,-5,4]); M
[ 6 7 8 9 0]
[30 -1 2 -2 4]
[30 2 -2 -1 4]
[-2 3 4 -5 4]
sage: M[3,:]=2*M[2,:]; M
[ 6 7 8 9 0]
[30 -1 2 -2 4]
[30 2 -2 -1 4]
[60 4 -4 -2 8]
sage: M[3,4]=M[3,2]; M
[ 6 7 8 9 0]
[30 -1 2 -2 4]
[30 2 -2 -1 4]
[60 4 -4 -2 -4]
sage: M[-1,:]=M[-3,:]; M
[ 6 7 8 9 0]
[30 -1 2 -2 4]
[30 2 -2 -1 4]
[30 -1 2 -2 4]
sage: A= matrix(3,4,[1, 0, -3, -1, 3, 0, -2, 1, -3, -5, -1, -5]); A
[ 1 0 -3 -1]
[ 3 0 -2 1]
[-3 -5 -1 -5]
sage: A[range(2,-1,-1),:]=A; A
[-3 -5 -1 -5]
[ 3 0 -2 1]
[ 1 0 -3 -1]
sage: A[range(2,-1,-1),range(3,-1,-1)]=A; A
[-1 -3 0 1]
[ 1 -2 0 3]
[-5 -1 -5 -3]
sage: A = matrix(2, [1, 2, 3, 4])
sage: A[[0,0],[0,0]]=10; A
[10 2]
[ 3 4]
sage: M = matrix(3, 4, range(12))
sage: M[0:0, 0:0]=20; M
[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
sage: M[0:0, 1:4]=20; M
[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
sage: M[2:3, 3:3]=20; M
[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
sage: M[range(2,2), :3]=20; M
[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
sage: M[(1,2), 3]=vector([-1,-2]); M
[ 0 1 2 3]
[ 4 5 6 -1]
[ 8 9 10 -2]
sage: M[(1,2),(0,1,1)]=[[-1,-2,-3],[-4,-5,-6]]; M
[ 0 1 2 3]
[-1 -3 6 -1]
[-4 -6 10 -2]
sage: M=matrix([(1, -2, -1, -1), (1, 8, 6, 2), (1, 1, -1, 1), (-1, 2, -2, -1)]); M
[ 1 -2 -1 -1]
[ 1 8 6 2]
[ 1 1 -1 1]
[-1 2 -2 -1]
sage: M[:2]=M[2:]; M
[ 1 1 -1 1]
[-1 2 -2 -1]
[ 1 1 -1 1]
[-1 2 -2 -1]
sage: M[:] = M.transpose(); M
[ 1 -1 1 -1]
[ 1 2 1 2]
[-1 -2 -1 -2]
[ 1 -1 1 -1]
sage: M = matrix(ZZ,4,range(16)); M
[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]
sage: M[::2]=M[::-2]; M
[12 13 14 15]
[ 4 5 6 7]
[ 4 5 6 7]
[12 13 14 15]
sage: M[::2]=2; M
[ 2 2 2 2]
[ 4 5 6 7]
[ 2 2 2 2]
[12 13 14 15]
sage: M[2:]=10; M
[ 2 2 2 2]
[ 4 5 6 7]
[10 10 10 10]
[10 10 10 10]
sage: M=matrix(3,1,[1,2,3]); M
[1]
[2]
[3]
sage: M[1] = vector([20]); M
[ 1]
[20]
[ 3]
sage: M = matrix(3, 2, srange(6)); M[1] = 15; M
[ 0 1]
[15 15]
[ 4 5]
sage: M = matrix(3, 1, srange(3)); M[1] = 15; M
[ 0]
[15]
[ 2]
sage: M = matrix(3, 1, srange(3)); M[1] = [15]; M
[ 0]
[15]
[ 2]
"""
cdef list row_list
cdef list col_list
cdef object index
cdef Py_ssize_t row_list_len, col_list_len
cdef list value_list
cdef bint value_list_one_dimensional = 0
cdef Py_ssize_t i
cdef Py_ssize_t row, col
cdef Py_ssize_t nrows = self._nrows
cdef Py_ssize_t ncols = self._ncols
cdef tuple key_tuple
cdef object row_index, col_index
cdef object value_row
cdef bint single_row = 0, single_col = 0
cdef bint no_col_index = 0
self.check_mutability()
if PyTuple_CheckExact(key):
key_tuple = <tuple>key
if len(key_tuple) != 2:
raise IndexError("index can't have more than two components")
row_index = <object>PyTuple_GET_ITEM(key_tuple, 0)
col_index = <object>PyTuple_GET_ITEM(key_tuple, 1)
if PyIndex_Check(col_index):
col = col_index
if col < 0:
col += ncols
if col < 0 or col >= ncols:
raise IndexError("index out of range")
single_col = 1
col_list_len = 1
else:
col_list = normalize_index(col_index, ncols)
col_list_len = len(col_list)
if col_list_len==0:
return
else:
no_col_index = 1
row_index = key
col_list_len = ncols
if col_list_len==0:
return
if PyIndex_Check(row_index):
row = row_index
if row < 0:
row += nrows
if row < 0 or row >= nrows:
raise IndexError("index out of range")
single_row = 1
row_list_len = 1
else:
row_list = normalize_index(row_index, nrows)
row_list_len = len(row_list)
if row_list_len==0:
return
if single_row and single_col and not no_col_index:
self.set_unsafe(row, col, self._coerce_element(value))
return
if PyList_CheckExact(value):
if single_row and no_col_index:
value_list_one_dimensional = 1
value_list = value
elif PyTuple_CheckExact(value):
if single_row and no_col_index:
value_list_one_dimensional = 1
value_list = list(value)
elif IS_INSTANCE(value, Matrix):
value_list = list(value)
elif IS_INSTANCE(value, Vector):
if single_row or single_col:
value_list_one_dimensional = 1
value_list = list(value)
else:
raise IndexError("value does not have the right dimensions")
else:
value_element = self._coerce_element(value)
if single_row:
if no_col_index:
for col in range(col_list_len):
self.set_unsafe(row, col, value_element)
else:
for col in col_list:
self.set_unsafe(row, col, value_element)
elif single_col:
for row in row_list:
self.set_unsafe(row, col, value_element)
else:
if no_col_index:
for row in row_list:
for col in range(col_list_len):
self.set_unsafe(row, col, value_element)
else:
for row in row_list:
for col in col_list:
self.set_unsafe(row, col, value_element)
return
if value_list_one_dimensional:
if single_row and col_list_len != len(value_list):
raise IndexError("value does not have the right number of columns")
elif single_col and row_list_len != len(value_list):
raise IndexError("value does not have the right number of rows")
else:
if row_list_len != len(value_list):
raise IndexError("value does not have the right number of rows")
for value_row in value_list:
if col_list_len != len(value_row):
raise IndexError("value does not have the right number of columns")
if single_row:
if value_list_one_dimensional:
value_row = value_list
else:
value_row = value_list[0]
if no_col_index:
for col in range(col_list_len):
self.set_unsafe(row, col, self._coerce_element(value_row[col]))
else:
for col in range(col_list_len):
self.set_unsafe(row, col_list[col], self._coerce_element(value_row[col]))
elif single_col:
if value_list_one_dimensional:
for row in range(row_list_len):
self.set_unsafe(row_list[row], col, self._coerce_element(value_list[row]))
else:
for row in range(row_list_len):
self.set_unsafe(row_list[row], col, self._coerce_element(value_list[row][0]))
else:
if no_col_index:
for i in range(row_list_len):
row = row_list[i]
value_row = value_list[i]
for col in range(col_list_len):
self.set_unsafe(row, col, self._coerce_element(value_row[col]))
else:
for i in range(row_list_len):
row = row_list[i]
value_row = value_list[i]
for col in range(col_list_len):
self.set_unsafe(row, col_list[col], self._coerce_element(value_row[col]))
return
cdef _coerce_element(self, x):
"""
Return coercion of x into the base ring of self.
"""
if PY_TYPE_CHECK(x, Element) and (<Element> x)._parent is self._base_ring:
return x
return self._base_ring(x)
def __reduce__(self):
"""
EXAMPLES::
sage: a = matrix(Integers(8),3,range(9))
sage: a == loads(dumps(a))
True
"""
data, version = self._pickle()
return unpickle, (self.__class__, self._parent, self._mutability,
self._cache, data, version)
def _pickle(self):
"""
Not yet implemented!
EXAMPLES::
sage: m=matrix(QQ,2,range(0,4))
sage: m._pickle() # todo: not implemented
"""
raise NotImplementedError
def _test_reduce(self, **options):
"""
Checks that the pickling function works.
EXAMPLES::
sage: a=matrix([[1,2],[3,4]])
sage: a._test_reduce()
"""
tester = self._tester(**options)
a, b = self.__reduce__()
tester.assertEqual(a(*b),self)
def base_ring(self):
"""
Returns the base ring of the matrix.
EXAMPLES::
sage: m=matrix(QQ,2,[1,2,3,4])
sage: m.base_ring()
Rational Field
"""
return self._base_ring
def change_ring(self, ring):
"""
Return the matrix obtained by coercing the entries of this matrix
into the given ring.
Always returns a copy (unless self is immutable, in which case
returns self).
EXAMPLES::
sage: A = Matrix(QQ, 2, 2, [1/2, 1/3, 1/3, 1/4])
sage: A.parent()
Full MatrixSpace of 2 by 2 dense matrices over Rational Field
sage: A.change_ring(GF(25,'a'))
[3 2]
[2 4]
sage: A.change_ring(GF(25,'a')).parent()
Full MatrixSpace of 2 by 2 dense matrices over Finite Field in a of size 5^2
sage: A.change_ring(ZZ)
Traceback (most recent call last):
...
TypeError: matrix has denominators so can't change to ZZ.
Changing rings preserves subdivisions::
sage: A.subdivide([1], []); A
[1/2 1/3]
[-------]
[1/3 1/4]
sage: A.change_ring(GF(25,'a'))
[3 2]
[---]
[2 4]
"""
if not is_Ring(ring):
raise TypeError("ring must be a ring")
if ring is self._base_ring:
if self._mutability._is_immutable:
return self
return self.__copy__()
try:
return self._change_ring(ring)
except (AttributeError, NotImplementedError):
M = sage.matrix.matrix_space.MatrixSpace(ring, self._nrows, self._ncols, sparse=self.is_sparse())
mat = M(self.list(), coerce=True, copy=False)
mat.subdivide(self.subdivisions())
return mat
def _test_change_ring(self, **options):
"""
Checks that :meth:`change_ring` works.
EXAMPLES::
sage: a=matrix([[1,2],[3,4]])
sage: a._test_change_ring()
"""
tester = self._tester(**options)
tester.assert_(self.change_ring(self.base_ring()) is not self)
def _matrix_(self, R):
"""
EXAMPLES::
sage: A = Matrix(ZZ[['t']], 2, 2, range(4))
sage: A.parent()
Full MatrixSpace of 2 by 2 dense matrices over Power Series Ring in t over Integer Ring
sage: A._matrix_(QQ[['t']])
[0 1]
[2 3]
sage: A._matrix_(QQ[['t']]).parent()
Full MatrixSpace of 2 by 2 dense matrices over Power Series Ring in t over Rational Field
"""
return self.change_ring(R)
def __repr__(self):
"""
EXAMPLES::
sage: A = matrix([[1,2], [3,4], [5,6]])
sage: A.__repr__()
'[1 2]\n[3 4]\n[5 6]'
sage: print A
[1 2]
[3 4]
[5 6]
If the matrix is too big, don't print all of the elements::
sage: A = random_matrix(ZZ, 100)
sage: A.__repr__()
"100 x 100 dense matrix over Integer Ring (type 'print A.str()' to see all of the entries)"
sage: print A
100 x 100 dense matrix over Integer Ring (type 'print A.str()' to see all of the entries)
If there are several names for the same matrix, write it as "obj"::
sage: B = A; print B
100 x 100 dense matrix over Integer Ring (type 'print obj.str()' to see all of the entries)
If the matrix doesn't have a name, don't print the extra string::
sage: A.transpose()
100 x 100 dense matrix over Integer Ring
sage: T = A.transpose(); T
100 x 100 dense matrix over Integer Ring (type 'print T.str()' to see all of the entries)
"""
from sage.misc.sageinspect import sage_getvariablename
if self._nrows < max_rows and self._ncols < max_cols:
return self.str()
if self.is_sparse():
s = 'sparse'
else:
s = 'dense'
rep = "%s x %s %s matrix over %s"%(self._nrows, self._ncols, s, self.base_ring())
name = sage_getvariablename(self)
if isinstance(name, list) and len(name) == 0:
return rep
if isinstance(name, list):
name = [x for x in name if not x.startswith('_')]
if len(name) == 1:
name = name[0]
if not isinstance(name, str):
name = "obj"
return rep + " (type 'print %s.str()' to see all of the entries)" % name
def str(self, rep_mapping=None, zero=None, plus_one=None, minus_one=None):
r"""
Return a nice string representation of the matrix.
INPUT:
- ``rep_mapping`` - a dictionary or callable used to override
the usual representation of elements.
If ``rep_mapping`` is a dictionary then keys should be
elements of the base ring and values the desired string
representation. Values sent in via the other keyword
arguments will override values in the dictionary.
Use of a dictionary can potentially take a very long time
due to the need to hash entries of the matrix. Matrices
with entries from ``QQbar`` are one example.
If ``rep_mapping`` is callable then it will be called with
elements of the matrix and must return a string. Simply
call :func:`repr` on elements which should have the default
representation.
- ``zero`` - string (default: ``None``); if not ``None`` use
the value of ``zero`` as the representation of the zero
element.
- ``plus_one`` - string (default: ``None``); if not ``None``
use the value of ``plus_one`` as the representation of the
one element.
- ``minus_one`` - string (default: ``None``); if not ``None``
use the value of ``minus_one`` as the representation of the
negative of the one element.
EXAMPLES::
sage: R = PolynomialRing(QQ,6,'z')
sage: a = matrix(2,3, R.gens())
sage: a.__repr__()
'[z0 z1 z2]\n[z3 z4 z5]'
sage: M = matrix([[1,0],[2,-1]])
sage: M.str()
'[ 1 0]\n[ 2 -1]'
sage: M.str(plus_one='+',minus_one='-',zero='.')
'[+ .]\n[2 -]'
sage: M.str({1:"not this one",2:"II"},minus_one="*",plus_one="I")
'[ I 0]\n[II *]'
sage: def print_entry(x):
... if x>0:
... return '+'
... elif x<0:
... return '-'
... else: return '.'
...
sage: M.str(print_entry)
'[+ .]\n[+ -]'
sage: M.str(repr)
'[ 1 0]\n[ 2 -1]'
TESTS:
Prior to Trac #11544 this could take a full minute to run (2011). ::
sage: A = matrix(QQ, 4, 4, [1, 2, -2, 2, 1, 0, -1, -1, 0, -1, 1, 1, -1, 2, 1/2, 0])
sage: e = A.eigenvalues()[3]
sage: K = (A-e).kernel()
sage: P = K.basis_matrix()
sage: P.str()
'[ 1.000000000000000? + 0.?e-17*I -2.116651487479748? + 0.0255565807096352?*I -0.2585224251020429? + 0.288602340904754?*I -0.4847545623533090? - 1.871890760086142?*I]'
"""
cdef Py_ssize_t nr, nc, r, c
nr = self._nrows
nc = self._ncols
if nr == 0 or nc == 0:
return "[]"
row_divs, col_divs = self.subdivisions()
if rep_mapping is None:
rep_mapping = {}
if isinstance(rep_mapping, dict):
if zero is not None:
rep_mapping[self.base_ring().zero()] = zero
if plus_one is not None:
rep_mapping[self.base_ring().one()] = plus_one
if minus_one is not None:
rep_mapping[-self.base_ring().one()] = minus_one
S = []
for x in self.list():
if callable(rep_mapping):
rep = rep_mapping(x)
elif rep_mapping and rep_mapping.has_key(x):
rep = rep_mapping.get(x)
else:
rep = repr(x)
S.append(rep)
tmp = []
for x in S:
tmp.append(len(x))
width = max(tmp)
rows = []
m = 0
left_bracket = "["
right_bracket = "]"
while nc in col_divs:
right_bracket = "|" + right_bracket
col_divs.remove(nc)
while 0 in col_divs:
left_bracket += "|"
col_divs.remove(0)
line = '+'.join(['-'*((width+1)*(b-a)-1) for a,b in zip([0] + col_divs, col_divs + [nc])])
hline = (left_bracket + line + right_bracket).replace('|', '+')
for r from 0 <= r < nr:
rows += [hline] * row_divs.count(r)
s = ""
for c from 0 <= c < nc:
if c+1 in col_divs:
sep = "|"*col_divs.count(c+1)
elif c == nc - 1:
sep=""
else:
sep=" "
entry = S[r*nc+c]
if c == 0:
m = max(m, len(entry))
entry = " "*(width-len(entry)) + entry
s = s + entry + sep
rows.append(left_bracket + s + right_bracket)
rows += [hline] * row_divs.count(nr)
s = "\n".join(rows)
return s
def _latex_(self):
r"""
Return latex representation of this matrix. The matrix is
enclosed in parentheses by default, but the delimiters can be
changed using the command
``latex.matrix_delimiters(...)``.
EXAMPLES::
sage: R = PolynomialRing(QQ,4,'z')
sage: a = matrix(2,2, R.gens())
sage: b = a*a
sage: latex(b) # indirect doctest
\left(\begin{array}{rr}
z_{0}^{2} + z_{1} z_{2} & z_{0} z_{1} + z_{1} z_{3} \\
z_{0} z_{2} + z_{2} z_{3} & z_{1} z_{2} + z_{3}^{2}
\end{array}\right)
Latex representation for block matrices::
sage: B = matrix(3,4)
sage: B.subdivide([2,2], [3])
sage: latex(B)
\left(\begin{array}{rrr|r}
0 & 0 & 0 & 0 \\
0 & 0 & 0 & 0 \\
\hline\hline
0 & 0 & 0 & 0
\end{array}\right)
Note that size-zero subdivisions are ignored in the notebook::
sage: sage.server.support.EMBEDDED_MODE = True
sage: latex(B)
\left(\begin{array}{rr}
\left(\begin{array}{rrr}
0 & 0 & 0 \\
0 & 0 & 0
\end{array}\right) & \left(\begin{array}{r}
0 \\
0
\end{array}\right) \\
\\
\left(\begin{array}{rrr}
0 & 0 & 0
\end{array}\right) & \left(\begin{array}{r}
0
\end{array}\right)
\end{array}\right)
sage: sage.server.support.EMBEDDED_MODE = False
"""
latex = sage.misc.latex.latex
matrix_delimiters = latex.matrix_delimiters()
cdef Py_ssize_t nr, nc, r, c
nr = self._nrows
nc = self._ncols
if nr == 0 or nc == 0:
return matrix_delimiters[0] + matrix_delimiters[1]
S = self.list()
rows = []
row_divs, col_divs = self.subdivisions()
from sage.server.support import EMBEDDED_MODE
if len(row_divs) + len(col_divs) > 0 and EMBEDDED_MODE:
for r in range(len(row_divs)+1):
s = ""
for c in range(len(col_divs)+1):
if c == len(col_divs):
sep=""
else:
sep=" & "
sub = self.subdivision(r,c)
if sub.nrows() > 0 and sub.ncols() > 0:
entry = latex(self.subdivision(r,c))
s = s + entry + sep
rows.append(s)
tmp = []
for row in rows:
tmp.append(str(row))
s = " \\\\\n".join(tmp)
format = 'r'*len(row_divs)
return "\\left" + matrix_delimiters[0] + "\\begin{array}{%s}\n"%format + s + "\n\\end{array}\\right" + matrix_delimiters[1]
for r from 0 <= r < nr:
if r in row_divs:
s = "\\hline"*row_divs.count(r) + "\n"
else:
s = ""
for c from 0 <= c < nc:
if c == nc-1:
sep=""
else:
sep=" & "
entry = latex(S[r*nc+c])
s = s + entry + sep
rows.append(s)
tmp = []
for row in rows:
tmp.append(str(row))
s = " \\\\\n".join(tmp)
tmp = ['r'*(b-a) for a,b in zip([0] + col_divs, col_divs + [nc])]
format = '|'.join(tmp)
return "\\left" + matrix_delimiters[0] + "\\begin{array}{%s}\n"%format + s + "\n\\end{array}\\right" + matrix_delimiters[1]
def ncols(self):
"""
Return the number of columns of this matrix.
EXAMPLES::
sage: M = MatrixSpace(QQ, 2, 3)
sage: A = M([1,2,3, 4,5,6])
sage: A
[1 2 3]
[4 5 6]
sage: A.ncols()
3
sage: A.nrows()
2
AUTHORS:
- Naqi Jaffery (2006-01-24): examples
"""
return self._ncols
def nrows(self):
r"""
Return the number of rows of this matrix.
EXAMPLES::
sage: M = MatrixSpace(QQ,6,7)
sage: A = M([1,2,3,4,5,6,7, 22,3/4,34,11,7,5,3, 99,65,1/2,2/3,3/5,4/5,5/6, 9,8/9, 9/8,7/6,6/7,76,4, 0,9,8,7,6,5,4, 123,99,91,28,6,1024,1])
sage: A
[ 1 2 3 4 5 6 7]
[ 22 3/4 34 11 7 5 3]
[ 99 65 1/2 2/3 3/5 4/5 5/6]
[ 9 8/9 9/8 7/6 6/7 76 4]
[ 0 9 8 7 6 5 4]
[ 123 99 91 28 6 1024 1]
sage: A.ncols()
7
sage: A.nrows()
6
AUTHORS:
- Naqi Jaffery (2006-01-24): examples
"""
return self._nrows
def dimensions(self):
r"""
Returns the dimensions of this matrix as the tuple (nrows, ncols).
EXAMPLES::
sage: M = matrix([[1,2,3],[4,5,6]])
sage: N = M.transpose()
sage: M.dimensions()
(2, 3)
sage: N.dimensions()
(3, 2)
AUTHORS:
- Benjamin Lundell (2012-02-09): examples
"""
return (self._nrows,self._ncols)
def act_on_polynomial(self, f):
"""
Returns the polynomial f(self\*x).
INPUT:
- ``self`` - an nxn matrix
- ``f`` - a polynomial in n variables x=(x1,...,xn)
OUTPUT: The polynomial f(self\*x).
EXAMPLES::
sage: R.<x,y> = QQ[]
sage: x, y = R.gens()
sage: f = x**2 - y**2
sage: M = MatrixSpace(QQ, 2)
sage: A = M([1,2,3,4])
sage: A.act_on_polynomial(f)
-8*x^2 - 20*x*y - 12*y^2
"""
cdef Py_ssize_t i, j, n
if self._nrows != self._ncols:
raise ArithmeticError("self must be a square matrix")
F = f.base_ring()
vars = f.parent().gens()
n = len(self.rows())
ans = []
for i from 0 <= i < n:
tmp = []
for j from 0 <= j < n:
tmp.append(self.get_unsafe(i,j)*vars[j])
ans.append( sum(tmp) )
return f(tuple(ans))
def __call__(self, *args, **kwargs):
"""
Calling a matrix returns the result of calling each component.
EXAMPLES::
sage: f(x,y) = x^2+y
sage: m = matrix([[f,f*f],[f^3,f^4]]); m
[ (x, y) |--> x^2 + y (x, y) |--> (x^2 + y)^2]
[(x, y) |--> (x^2 + y)^3 (x, y) |--> (x^2 + y)^4]
sage: m(1,2)
[ 3 9]
[27 81]
sage: m(y=2,x=1)
[ 3 9]
[27 81]
sage: m(2,1)
[ 5 25]
[125 625]
"""
from constructor import matrix
return matrix(self.nrows(), self.ncols(), [e(*args, **kwargs) for e in self.list()])
def commutator(self, other):
"""
Return the commutator self\*other - other\*self.
EXAMPLES::
sage: A = Matrix(ZZ, 2, 2, range(4))
sage: B = Matrix(ZZ, 2, 2, [0, 1, 0, 0])
sage: A.commutator(B)
[-2 -3]
[ 0 2]
sage: A.commutator(B) == -B.commutator(A)
True
"""
return self*other - other*self
cdef check_row_bounds_and_mutability(self, Py_ssize_t r1, Py_ssize_t r2):
if self._mutability._is_immutable:
raise ValueError("matrix is immutable; please change a copy instead (i.e., use copy(M) to change a copy of M).")
else:
self._cache = {}
if r1<0 or r1 >= self._nrows or r2<0 or r2 >= self._nrows:
raise IndexError("matrix row index out of range")
cdef check_column_bounds_and_mutability(self, Py_ssize_t c1, Py_ssize_t c2):
if self._mutability._is_immutable:
raise ValueError("matrix is immutable; please change a copy instead (i.e., use copy(M) to change a copy of M).")
else:
self._cache = {}
if c1<0 or c1 >= self._ncols or c2<0 or c2 >= self._ncols:
raise IndexError("matrix column index out of range")
def swap_columns(self, Py_ssize_t c1, Py_ssize_t c2):
"""
Swap columns c1 and c2 of self.
EXAMPLES: We create a rational matrix::
sage: M = MatrixSpace(QQ,3,3)
sage: A = M([1,9,-7,4/5,4,3,6,4,3])
sage: A
[ 1 9 -7]
[4/5 4 3]
[ 6 4 3]
Since the first column is numbered zero, this swaps the second and
third columns::
sage: A.swap_columns(1,2); A
[ 1 -7 9]
[4/5 3 4]
[ 6 3 4]
"""
self.check_column_bounds_and_mutability(c1, c2)
if c1 != c2:
self.swap_columns_c(c1, c2)
def with_swapped_columns(self, c1, c2):
r"""
Swap columns ``c1`` and ``c2`` of ``self`` and return a new matrix.
INPUT:
- ``c1``, ``c2`` - integers specifying columns of ``self`` to interchange
OUTPUT:
A new matrix, identical to ``self`` except that columns ``c1`` and ``c2``
are swapped.
EXAMPLES:
Remember that columns are numbered starting from zero. ::
sage: A = matrix(QQ, 4, range(20))
sage: A.with_swapped_columns(1, 2)
[ 0 2 1 3 4]
[ 5 7 6 8 9]
[10 12 11 13 14]
[15 17 16 18 19]
Trying to swap a column with itself will succeed, but still return
a new matrix. ::
sage: A = matrix(QQ, 4, range(20))
sage: B = A.with_swapped_columns(2, 2)
sage: A == B
True
sage: A is B
False
The column specifications are checked. ::
sage: A = matrix(4, range(20))
sage: A.with_swapped_columns(-1, 2)
Traceback (most recent call last):
...
IndexError: matrix column index out of range
sage: A.with_swapped_columns(2, 5)
Traceback (most recent call last):
...
IndexError: matrix column index out of range
"""
cdef Matrix temp
self.check_column_bounds_and_mutability(c1,c2)
temp = self.__copy__()
if c1 != c2:
temp.swap_columns_c(c1,c2)
return temp
cdef swap_columns_c(self, Py_ssize_t c1, Py_ssize_t c2):
cdef Py_ssize_t r
for r from 0 <= r < self._nrows:
a = self.get_unsafe(r, c2)
self.set_unsafe(r, c2, self.get_unsafe(r,c1))
self.set_unsafe(r, c1, a)
def swap_rows(self, r1, r2):
"""
Swap rows r1 and r2 of self.
EXAMPLES: We create a rational matrix::
sage: M = MatrixSpace(QQ,3,3)
sage: A = M([1,9,-7,4/5,4,3,6,4,3])
sage: A
[ 1 9 -7]
[4/5 4 3]
[ 6 4 3]
Since the first row is numbered zero, this swaps the first and
third rows::
sage: A.swap_rows(0,2); A
[ 6 4 3]
[4/5 4 3]
[ 1 9 -7]
"""
self.check_row_bounds_and_mutability(r1, r2)
if r1 != r2:
self.swap_rows_c(r1, r2)
def with_swapped_rows(self, r1, r2):
r"""
Swap rows ``r1`` and ``r2`` of ``self`` and return a new matrix.
INPUT:
- ``r1``, ``r2`` - integers specifying rows of ``self`` to interchange
OUTPUT:
A new matrix, identical to ``self`` except that rows ``r1`` and ``r2``
are swapped.
EXAMPLES:
Remember that rows are numbered starting from zero. ::
sage: A = matrix(QQ, 4, range(20))
sage: A.with_swapped_rows(1, 2)
[ 0 1 2 3 4]
[10 11 12 13 14]
[ 5 6 7 8 9]
[15 16 17 18 19]
Trying to swap a row with itself will succeed, but still return
a new matrix. ::
sage: A = matrix(QQ, 4, range(20))
sage: B = A.with_swapped_rows(2, 2)
sage: A == B
True
sage: A is B
False
The row specifications are checked. ::
sage: A = matrix(4, range(20))
sage: A.with_swapped_rows(-1, 2)
Traceback (most recent call last):
...
IndexError: matrix row index out of range
sage: A.with_swapped_rows(2, 5)
Traceback (most recent call last):
...
IndexError: matrix row index out of range
"""
cdef Matrix temp
self.check_row_bounds_and_mutability(r1,r2)
temp = self.__copy__()
if r1 != r2:
temp.swap_rows_c(r1,r2)
return temp
cdef swap_rows_c(self, Py_ssize_t r1, Py_ssize_t r2):
cdef Py_ssize_t c
for c from 0 <= c < self._ncols:
a = self.get_unsafe(r2, c)
self.set_unsafe(r2, c, self.get_unsafe(r1, c))
self.set_unsafe(r1, c, a)
def add_multiple_of_row(self, Py_ssize_t i, Py_ssize_t j, s, Py_ssize_t start_col=0):
"""
Add s times row j to row i.
EXAMPLES: We add -3 times the first row to the second row of an
integer matrix, remembering to start numbering rows at zero::
sage: a = matrix(ZZ,2,3,range(6)); a
[0 1 2]
[3 4 5]
sage: a.add_multiple_of_row(1,0,-3)
sage: a
[ 0 1 2]
[ 3 1 -1]
To add a rational multiple, we first need to change the base ring::
sage: a = a.change_ring(QQ)
sage: a.add_multiple_of_row(1,0,1/3)
sage: a
[ 0 1 2]
[ 3 4/3 -1/3]
If not, we get an error message::
sage: a.add_multiple_of_row(1,0,i)
Traceback (most recent call last):
...
TypeError: Multiplying row by Symbolic Ring element cannot be done over Rational Field, use change_ring or with_added_multiple_of_row instead.
"""
self.check_row_bounds_and_mutability(i,j)
try:
s = self._coerce_element(s)
self.add_multiple_of_row_c(i, j, s, start_col)
except TypeError:
raise TypeError('Multiplying row by %s element cannot be done over %s, use change_ring or with_added_multiple_of_row instead.' % (s.parent(), self.base_ring()))
cdef add_multiple_of_row_c(self, Py_ssize_t i, Py_ssize_t j, s, Py_ssize_t start_col):
cdef Py_ssize_t c
for c from start_col <= c < self._ncols:
self.set_unsafe(i, c, self.get_unsafe(i, c) + s*self.get_unsafe(j, c))
def with_added_multiple_of_row(self, Py_ssize_t i, Py_ssize_t j, s, Py_ssize_t start_col=0):
"""
Add s times row j to row i, returning new matrix.
EXAMPLES: We add -3 times the first row to the second row of an
integer matrix, remembering to start numbering rows at zero::
sage: a = matrix(ZZ,2,3,range(6)); a
[0 1 2]
[3 4 5]
sage: b = a.with_added_multiple_of_row(1,0,-3); b
[ 0 1 2]
[ 3 1 -1]
The original matrix is unchanged::
sage: a
[0 1 2]
[3 4 5]
Adding a rational multiple is okay, and reassigning a variable is
okay::
sage: a = a.with_added_multiple_of_row(0,1,1/3); a
[ 1 7/3 11/3]
[ 3 4 5]
"""
cdef Matrix temp
self.check_row_bounds_and_mutability(i,j)
try:
s = self._coerce_element(s)
temp = self.__copy__()
temp.add_multiple_of_row_c(i, j, s, start_col)
return temp
except TypeError:
temp = self.change_ring(Sequence([s,self.base_ring()(0)]).universe())
s = temp._coerce_element(s)
temp.add_multiple_of_row_c(i, j, s, start_col)
return temp
def add_multiple_of_column(self, Py_ssize_t i, Py_ssize_t j, s, Py_ssize_t start_row=0):
"""
Add s times column j to column i.
EXAMPLES: We add -1 times the third column to the second column of
an integer matrix, remembering to start numbering cols at zero::
sage: a = matrix(ZZ,2,3,range(6)); a
[0 1 2]
[3 4 5]
sage: a.add_multiple_of_column(1,2,-1)
sage: a
[ 0 -1 2]
[ 3 -1 5]
To add a rational multiple, we first need to change the base ring::
sage: a = a.change_ring(QQ)
sage: a.add_multiple_of_column(1,0,1/3)
sage: a
[ 0 -1 2]
[ 3 0 5]
If not, we get an error message::
sage: a.add_multiple_of_column(1,0,i)
Traceback (most recent call last):
...
TypeError: Multiplying column by Symbolic Ring element cannot be done over Rational Field, use change_ring or with_added_multiple_of_column instead.
"""
self.check_column_bounds_and_mutability(i,j)
try:
s = self._coerce_element(s)
self.add_multiple_of_column_c(i, j, s, start_row)
except TypeError:
raise TypeError('Multiplying column by %s element cannot be done over %s, use change_ring or with_added_multiple_of_column instead.' % (s.parent(), self.base_ring()))
cdef add_multiple_of_column_c(self, Py_ssize_t i, Py_ssize_t j, s, Py_ssize_t start_row):
cdef Py_ssize_t r
for r from start_row <= r < self._nrows:
self.set_unsafe(r, i, self.get_unsafe(r, i) + s*self.get_unsafe(r, j))
def with_added_multiple_of_column(self, Py_ssize_t i, Py_ssize_t j, s, Py_ssize_t start_row=0):
"""
Add s times column j to column i, returning new matrix.
EXAMPLES: We add -1 times the third column to the second column of
an integer matrix, remembering to start numbering cols at zero::
sage: a = matrix(ZZ,2,3,range(6)); a
[0 1 2]
[3 4 5]
sage: b = a.with_added_multiple_of_column(1,2,-1); b
[ 0 -1 2]
[ 3 -1 5]
The original matrix is unchanged::
sage: a
[0 1 2]
[3 4 5]
Adding a rational multiple is okay, and reassigning a variable is
okay::
sage: a = a.with_added_multiple_of_column(0,1,1/3); a
[ 1/3 1 2]
[13/3 4 5]
"""
cdef Matrix temp
self.check_column_bounds_and_mutability(i,j)
try:
s = self._coerce_element(s)
temp = self.__copy__()
temp.add_multiple_of_column_c(i, j, s, start_row)
return temp
except TypeError:
temp = self.change_ring(Sequence([s,self.base_ring()(0)]).universe())
s = temp._coerce_element(s)
temp.add_multiple_of_column_c(i, j, s, start_row)
return temp
def rescale_row(self, Py_ssize_t i, s, Py_ssize_t start_col=0):
"""
Replace i-th row of self by s times i-th row of self.
INPUT:
- ``i`` - ith row
- ``s`` - scalar
- ``start_col`` - only rescale entries at this column
and to the right
EXAMPLES: We rescale the second row of a matrix over the rational
numbers::
sage: a = matrix(QQ,3,range(6)); a
[0 1]
[2 3]
[4 5]
sage: a.rescale_row(1,1/2); a
[ 0 1]
[ 1 3/2]
[ 4 5]
We rescale the second row of a matrix over a polynomial ring::
sage: R.<x> = QQ[]
sage: a = matrix(R,3,[1,x,x^2,x^3,x^4,x^5]);a
[ 1 x]
[x^2 x^3]
[x^4 x^5]
sage: a.rescale_row(1,1/2); a
[ 1 x]
[1/2*x^2 1/2*x^3]
[ x^4 x^5]
We try and fail to rescale a matrix over the integers by a
non-integer::
sage: a = matrix(ZZ,2,3,[0,1,2, 3,4,4]); a
[0 1 2]
[3 4 4]
sage: a.rescale_row(1,1/2)
Traceback (most recent call last):
...
TypeError: Rescaling row by Rational Field element cannot be done over Integer Ring, use change_ring or with_rescaled_row instead.
To rescale the matrix by 1/2, you must change the base ring to the
rationals::
sage: a = a.change_ring(QQ); a
[0 1 2]
[3 4 4]
sage: a.rescale_col(1,1/2); a
[ 0 1/2 2]
[ 3 2 4]
"""
self.check_row_bounds_and_mutability(i, i)
try:
s = self._coerce_element(s)
self.rescale_row_c(i, s, start_col)
except TypeError:
raise TypeError('Rescaling row by %s element cannot be done over %s, use change_ring or with_rescaled_row instead.' % (s.parent(), self.base_ring()))
cdef rescale_row_c(self, Py_ssize_t i, s, Py_ssize_t start_col):
cdef Py_ssize_t j
for j from start_col <= j < self._ncols:
self.set_unsafe(i, j, self.get_unsafe(i, j)*s)
def with_rescaled_row(self, Py_ssize_t i, s, Py_ssize_t start_col=0):
"""
Replaces i-th row of self by s times i-th row of self, returning
new matrix.
EXAMPLES: We rescale the second row of a matrix over the integers::
sage: a = matrix(ZZ,3,2,range(6)); a
[0 1]
[2 3]
[4 5]
sage: b = a.with_rescaled_row(1,-2); b
[ 0 1]
[-4 -6]
[ 4 5]
The original matrix is unchanged::
sage: a
[0 1]
[2 3]
[4 5]
Adding a rational multiple is okay, and reassigning a variable is
okay::
sage: a = a.with_rescaled_row(2,1/3); a
[ 0 1]
[ 2 3]
[4/3 5/3]
"""
cdef Matrix temp
self.check_row_bounds_and_mutability(i,i)
try:
s = self._coerce_element(s)
temp = self.__copy__()
temp.rescale_row_c(i, s, start_col)
return temp
except TypeError:
temp = self.change_ring(Sequence([s,self.base_ring()(0)]).universe())
s = temp._coerce_element(s)
temp.rescale_row_c(i, s, start_col)
return temp
def rescale_col(self, Py_ssize_t i, s, Py_ssize_t start_row=0):
"""
Replace i-th col of self by s times i-th col of self.
INPUT:
- ``i`` - ith column
- ``s`` - scalar
- ``start_row`` - only rescale entries at this row
and lower
EXAMPLES: We rescale the last column of a matrix over the rational
numbers::
sage: a = matrix(QQ,2,3,range(6)); a
[0 1 2]
[3 4 5]
sage: a.rescale_col(2,1/2); a
[ 0 1 1]
[ 3 4 5/2]
sage: R.<x> = QQ[]
We rescale the last column of a matrix over a polynomial ring::
sage: a = matrix(R,2,3,[1,x,x^2,x^3,x^4,x^5]); a
[ 1 x x^2]
[x^3 x^4 x^5]
sage: a.rescale_col(2,1/2); a
[ 1 x 1/2*x^2]
[ x^3 x^4 1/2*x^5]
We try and fail to rescale a matrix over the integers by a
non-integer::
sage: a = matrix(ZZ,2,3,[0,1,2, 3,4,4]); a
[0 1 2]
[3 4 4]
sage: a.rescale_col(2,1/2)
Traceback (most recent call last):
...
TypeError: Rescaling column by Rational Field element cannot be done over Integer Ring, use change_ring or with_rescaled_col instead.
To rescale the matrix by 1/2, you must change the base ring to the
rationals::
sage: a = a.change_ring(QQ); a
[0 1 2]
[3 4 4]
sage: a.rescale_col(2,1/2); a
[0 1 1]
[3 4 2]
"""
self.check_column_bounds_and_mutability(i, i)
try:
s = self._coerce_element(s)
self.rescale_col_c(i, s, start_row)
except TypeError:
raise TypeError('Rescaling column by %s element cannot be done over %s, use change_ring or with_rescaled_col instead.' % (s.parent(), self.base_ring()))
cdef rescale_col_c(self, Py_ssize_t i, s, Py_ssize_t start_row):
cdef Py_ssize_t j
for j from start_row <= j < self._nrows:
self.set_unsafe(j, i, self.get_unsafe(j, i)*s)
def with_rescaled_col(self, Py_ssize_t i, s, Py_ssize_t start_row=0):
"""
Replaces i-th col of self by s times i-th col of self, returning
new matrix.
EXAMPLES: We rescale the last column of a matrix over the
integers::
sage: a = matrix(ZZ,2,3,range(6)); a
[0 1 2]
[3 4 5]
sage: b = a.with_rescaled_col(2,-2); b
[ 0 1 -4]
[ 3 4 -10]
The original matrix is unchanged::
sage: a
[0 1 2]
[3 4 5]
Adding a rational multiple is okay, and reassigning a variable is
okay::
sage: a = a.with_rescaled_col(1,1/3); a
[ 0 1/3 2]
[ 3 4/3 5]
"""
cdef Matrix temp
self.check_column_bounds_and_mutability(i,i)
try:
s = self._coerce_element(s)
temp = self.__copy__()
temp.rescale_col_c(i, s, start_row)
return temp
except TypeError:
temp = self.change_ring(Sequence([s,self.base_ring()(0)]).universe())
s = temp._coerce_element(s)
temp.rescale_col_c(i, s, start_row)
return temp
def set_row_to_multiple_of_row(self, Py_ssize_t i, Py_ssize_t j, s):
"""
Set row i equal to s times row j.
EXAMPLES: We change the second row to -3 times the first row::
sage: a = matrix(ZZ,2,3,range(6)); a
[0 1 2]
[3 4 5]
sage: a.set_row_to_multiple_of_row(1,0,-3)
sage: a
[ 0 1 2]
[ 0 -3 -6]
If we try to multiply a row by a rational number, we get an error
message::
sage: a.set_row_to_multiple_of_row(1,0,1/2)
Traceback (most recent call last):
...
TypeError: Multiplying row by Rational Field element cannot be done over Integer Ring, use change_ring or with_row_set_to_multiple_of_row instead.
"""
self.check_row_bounds_and_mutability(i,j)
cdef Py_ssize_t n
try:
s = self._coerce_element(s)
for n from 0 <= n < self._ncols:
self.set_unsafe(i, n, s * self.get_unsafe(j, n))
except TypeError:
raise TypeError('Multiplying row by %s element cannot be done over %s, use change_ring or with_row_set_to_multiple_of_row instead.' % (s.parent(), self.base_ring()))
def with_row_set_to_multiple_of_row(self, Py_ssize_t i, Py_ssize_t j, s):
"""
Set row i equal to s times row j, returning a new matrix.
EXAMPLES: We change the second row to -3 times the first row::
sage: a = matrix(ZZ,2,3,range(6)); a
[0 1 2]
[3 4 5]
sage: b = a.with_row_set_to_multiple_of_row(1,0,-3); b
[ 0 1 2]
[ 0 -3 -6]
Note that the original matrix is unchanged::
sage: a
[0 1 2]
[3 4 5]
Adding a rational multiple is okay, and reassigning a variable is
okay::
sage: a = a.with_row_set_to_multiple_of_row(1,0,1/2); a
[ 0 1 2]
[ 0 1/2 1]
"""
self.check_row_bounds_and_mutability(i,j)
cdef Matrix temp
cdef Py_ssize_t n
try:
s = self._coerce_element(s)
temp = self.__copy__()
for n from 0 <= n < temp._ncols:
temp.set_unsafe(i, n, s * temp.get_unsafe(j, n))
return temp
except TypeError:
temp = self.change_ring(Sequence([s,self.base_ring()(0)]).universe())
s = temp._coerce_element(s)
for n from 0 <= n < temp._ncols:
temp.set_unsafe(i, n, s * temp.get_unsafe(j, n))
return temp
def set_col_to_multiple_of_col(self, Py_ssize_t i, Py_ssize_t j, s):
"""
Set column i equal to s times column j.
EXAMPLES: We change the second column to -3 times the first
column.
::
sage: a = matrix(ZZ,2,3,range(6)); a
[0 1 2]
[3 4 5]
sage: a.set_col_to_multiple_of_col(1,0,-3)
sage: a
[ 0 0 2]
[ 3 -9 5]
If we try to multiply a column by a rational number, we get an
error message::
sage: a.set_col_to_multiple_of_col(1,0,1/2)
Traceback (most recent call last):
...
TypeError: Multiplying column by Rational Field element cannot be done over Integer Ring, use change_ring or with_col_set_to_multiple_of_col instead.
"""
self.check_column_bounds_and_mutability(i,j)
cdef Py_ssize_t n
try:
s = self._coerce_element(s)
for n from 0 <= n < self._nrows:
self.set_unsafe(n, i, s * self.get_unsafe(n, j))
except TypeError:
raise TypeError('Multiplying column by %s element cannot be done over %s, use change_ring or with_col_set_to_multiple_of_col instead.' % (s.parent(), self.base_ring()))
def with_col_set_to_multiple_of_col(self, Py_ssize_t i, Py_ssize_t j, s):
"""
Set column i equal to s times column j, returning a new matrix.
EXAMPLES: We change the second column to -3 times the first
column.
::
sage: a = matrix(ZZ,2,3,range(6)); a
[0 1 2]
[3 4 5]
sage: b = a.with_col_set_to_multiple_of_col(1,0,-3); b
[ 0 0 2]
[ 3 -9 5]
Note that the original matrix is unchanged::
sage: a
[0 1 2]
[3 4 5]
Adding a rational multiple is okay, and reassigning a variable is
okay::
sage: a = a.with_col_set_to_multiple_of_col(1,0,1/2); a
[ 0 0 2]
[ 3 3/2 5]
"""
self.check_column_bounds_and_mutability(i,j)
cdef Py_ssize_t n
cdef Matrix temp
try:
s = self._coerce_element(s)
temp = self.__copy__()
for n from 0 <= n < temp._nrows:
temp.set_unsafe(n, i, s * temp.get_unsafe(n, j))
return temp
except TypeError:
temp = self.change_ring(Sequence([s,self.base_ring()(0)]).universe())
s = temp._coerce_element(s)
for n from 0 <= n < temp._nrows:
temp.set_unsafe(n, i, s * temp.get_unsafe(n, j))
return temp
def _set_row_to_negative_of_row_of_A_using_subset_of_columns(self, Py_ssize_t i, Matrix A,
Py_ssize_t r, cols,
cols_index=None):
"""
Set row i of self to -(row r of A), but where we only take the
given column positions in that row of A. We do not zero out the
other entries of self's row i either.
INPUT:
- ``i`` - integer, index into the rows of self
- ``A`` - a matrix
- ``r`` - integer, index into rows of A
- ``cols`` - a *sorted* list of integers.
- ``(cols_index`` - ignored)
EXAMPLES::
sage: a = matrix(QQ,2,3,range(6)); a
[0 1 2]
[3 4 5]
sage: a._set_row_to_negative_of_row_of_A_using_subset_of_columns(0,a,1,[1,2])
sage: a
[-4 -5 2]
[ 3 4 5]
"""
self.check_row_bounds_and_mutability(i,i)
if r < 0 or r >= A.nrows():
raise IndexError("invalid row")
cdef Py_ssize_t l
l = 0
for k in cols:
self.set_unsafe(i,l,-A.get_unsafe(r,k))
l += 1
def mutate(self, Py_ssize_t k ):
"""
Mutates ``self`` at row and column index ``k``.
.. warning:: Only makes sense if ``self`` is skew-symmetrizable.
INPUT:
- ``k`` -- integer at which row/column ``self`` is mutated.
EXAMPLES:
Mutation of the B-matrix of the quiver of type `A_3`::
sage: M = matrix(ZZ,3,[0,1,0,-1,0,-1,0,1,0]); M
[ 0 1 0]
[-1 0 -1]
[ 0 1 0]
sage: M.mutate(0); M
[ 0 -1 0]
[ 1 0 -1]
[ 0 1 0]
sage: M.mutate(1); M
[ 0 1 -1]
[-1 0 1]
[ 1 -1 0]
sage: M = matrix(ZZ,6,[0,1,0,-1,0,-1,0,1,0,1,0,0,0,1,0,0,0,1]); M
[ 0 1 0]
[-1 0 -1]
[ 0 1 0]
[ 1 0 0]
[ 0 1 0]
[ 0 0 1]
sage: M.mutate(0); M
[ 0 -1 0]
[ 1 0 -1]
[ 0 1 0]
[-1 1 0]
[ 0 1 0]
[ 0 0 1]
REFERENCES:
- [FZ2001] S. Fomin, A. Zelevinsky. Cluster Algebras 1: Foundations, arXiv:math/0104151 (2001).
"""
cdef Py_ssize_t i,j,_
cdef list pairs, k0_pairs, k1_pairs
if k < 0 or k >= self._nrows or k >= self._ncols:
raise IndexError("The mutation index is invalid")
pairs = self.nonzero_positions()
k0_pairs = [ pair for pair in pairs if pair[0] == k ]
k1_pairs = [ pair for pair in pairs if pair[1] == k ]
for _,j in k0_pairs:
self[k,j] = -self.get_unsafe(k,j)
for i,_ in k1_pairs:
self[i,k] = -self.get_unsafe(i,k)
for i,_ in k1_pairs:
ik = self.get_unsafe(i,k)
ineg = True if ik < 0 else False
for _,j in k0_pairs:
kj = self.get_unsafe(k,j)
jneg = True if kj < 0 else False
if ineg == jneg == True:
self[i,j] = self.get_unsafe(i,j) + self.get_unsafe(i,k)*self.get_unsafe(k,j)
elif ineg == jneg == False:
self[i,j] = self.get_unsafe(i,j) - self.get_unsafe(i,k)*self.get_unsafe(k,j)
def _travel_column( self, dict d, int k, int sign, positive ):
r"""
Helper function for testing symmetrizability. Tests dependencies within entries in ``self`` and entries in the dictionary ``d``.
.. warning:: the dictionary ``d`` gets new values for keys in L.
INPUT:
- ``d`` -- dictionary modelling partial entries of a diagonal matrix.
- ``k`` -- integer for which row and column of self should be tested with the dictionary d.
- ``sign`` -- `\pm 1`, depending on symmetric or skew-symmetric is tested.
- ``positive`` -- if True, only positive entries for the values of the dictionary are allowed.
OUTPUT:
- ``L`` -- list of new keys in d
EXAMPLES::
sage: M = matrix(ZZ,3,[0,1,0,-1,0,-1,0,1,0]); M
[ 0 1 0]
[-1 0 -1]
[ 0 1 0]
sage: M._travel_column({0:1},0,-1,True)
[1]
"""
cdef list L = []
cdef int i
for i from 0 <= i < self._ncols:
if i not in d:
self_ik = self.get_unsafe(i,k)
self_ki = self.get_unsafe(k,i)
if bool(self_ik) != bool(self_ki):
return False
if self_ik != 0:
L.append(i)
d[i] = sign * d[k] * self_ki / self_ik
if positive and not d[i] > 0:
return False
for j in d:
if d[i] * self.get_unsafe(i,j) != sign * d[j] * self.get_unsafe(j,i):
return False
return L
def _check_symmetrizability(self, return_diag=False, skew=False, positive=True):
r"""
This function takes a square matrix over an *ordered integral domain* and checks if it is (skew-)symmetrizable.
A matrix `B` is (skew-)symmetrizable iff there exists an invertible diagonal matrix `D` such that `DB` is (skew-)symmetric.
INPUT:
- ``return_diag`` -- bool(default:False) if True and ``self`` is (skew)-symmetrizable the diagonal entries of the matrix `D` are returned.
- ``skew`` -- bool(default:False) if True, (skew-)symmetrizability is checked.
- ``positive`` -- bool(default:True) if True, the condition that `D` has positive entries is added.
OUTPUT:
- True -- if ``self`` is (skew-)symmetrizable and ``return_diag`` is False
- the diagonal entries of the matrix `D` such that `DB` is (skew-)symmetric -- iff ``self`` is (skew-)symmetrizable and ``return_diag`` is True
- False -- iff ``self`` is not (skew-)symmetrizable
EXAMPLES::
sage: matrix([[0,6],[3,0]])._check_symmetrizability(positive=False)
True
sage: matrix([[0,6],[3,0]])._check_symmetrizability(positive=True)
True
sage: matrix([[0,6],[3,0]])._check_symmetrizability(skew=True, positive=False)
True
sage: matrix([[0,6],[3,0]])._check_symmetrizability(skew=True, positive=True)
False
REFERENCES:
- [FZ2001] S. Fomin, A. Zelevinsky. Cluster Algebras 1: Foundations, arXiv:math/0104151 (2001).
"""
cdef dict d = {}
cdef list queue = range( self._ncols )
cdef int l, sign, i, j
if skew:
zero = self.parent().base_ring().zero()
for i from 0 <= i < self._nrows:
if not self.get_unsafe(i,i) == zero:
return False
sign = -1
else:
sign = 1
while queue:
i = queue.pop(0)
d[i] = 1
L = self._travel_column( d, i, sign, positive )
if L is False:
return False
while L:
l = L.pop(0)
queue.remove( l )
L_prime = self._travel_column( d, l, sign, positive )
if L_prime is False:
return False
else:
L.extend( L_prime )
if return_diag:
return [ d[i] for i in xrange(self._nrows) ]
else:
return True
def linear_combination_of_rows(self, v):
r"""
Return the linear combination of the rows of ``self`` given by the
coefficients in the list ``v``.
INPUT:
- ``v`` - a list of scalars. The length can be less than
the number of rows of ``self`` but not greater.
OUTPUT:
The vector (or free module element) that is a linear
combination of the rows of ``self``. If the list of
scalars has fewer entries than the number of rows,
additional zeros are appended to the list until it
has as many entries as the number of rows.
EXAMPLES::
sage: a = matrix(ZZ,2,3,range(6)); a
[0 1 2]
[3 4 5]
sage: a.linear_combination_of_rows([1,2])
(6, 9, 12)
sage: a.linear_combination_of_rows([0,0])
(0, 0, 0)
sage: a.linear_combination_of_rows([1/2,2/3])
(2, 19/6, 13/3)
The list ``v`` can be anything that is iterable. Perhaps most
naturally, a vector may be used. ::
sage: v = vector(ZZ, [1,2])
sage: a.linear_combination_of_rows(v)
(6, 9, 12)
We check that a matrix with no rows behaves properly. ::
sage: matrix(QQ,0,2).linear_combination_of_rows([])
(0, 0)
The object returned is a vector, or a free module element. ::
sage: B = matrix(ZZ, 4, 3, range(12))
sage: w = B.linear_combination_of_rows([-1,2,-3,4])
sage: w
(24, 26, 28)
sage: w.parent()
Ambient free module of rank 3 over the principal ideal domain Integer Ring
sage: x = B.linear_combination_of_rows([1/2,1/3,1/4,1/5])
sage: x
(43/10, 67/12, 103/15)
sage: x.parent()
Vector space of dimension 3 over Rational Field
The length of v can be less than the number of rows, but not
greater. ::
sage: A = matrix(QQ,3,4,range(12))
sage: A.linear_combination_of_rows([2,3])
(12, 17, 22, 27)
sage: A.linear_combination_of_rows([1,2,3,4])
Traceback (most recent call last):
...
ValueError: length of v must be at most the number of rows of self
"""
if len(v) > self._nrows:
raise ValueError("length of v must be at most the number of rows of self")
if self._nrows == 0:
return self.parent().row_space().zero_vector()
from constructor import matrix
v = matrix(list(v)+[0]*(self._nrows-len(v)))
return (v * self)[0]
def linear_combination_of_columns(self, v):
r"""
Return the linear combination of the columns of ``self`` given by the
coefficients in the list ``v``.
INPUT:
- ``v`` - a list of scalars. The length can be less than
the number of columns of ``self`` but not greater.
OUTPUT:
The vector (or free module element) that is a linear
combination of the columns of ``self``. If the list of
scalars has fewer entries than the number of columns,
additional zeros are appended to the list until it
has as many entries as the number of columns.
EXAMPLES::
sage: a = matrix(ZZ,2,3,range(6)); a
[0 1 2]
[3 4 5]
sage: a.linear_combination_of_columns([1,1,1])
(3, 12)
sage: a.linear_combination_of_columns([0,0,0])
(0, 0)
sage: a.linear_combination_of_columns([1/2,2/3,3/4])
(13/6, 95/12)
The list ``v`` can be anything that is iterable. Perhaps most
naturally, a vector may be used. ::
sage: v = vector(ZZ, [1,2,3])
sage: a.linear_combination_of_columns(v)
(8, 26)
We check that a matrix with no columns behaves properly. ::
sage: matrix(QQ,2,0).linear_combination_of_columns([])
(0, 0)
The object returned is a vector, or a free module element. ::
sage: B = matrix(ZZ, 4, 3, range(12))
sage: w = B.linear_combination_of_columns([-1,2,-3])
sage: w
(-4, -10, -16, -22)
sage: w.parent()
Ambient free module of rank 4 over the principal ideal domain Integer Ring
sage: x = B.linear_combination_of_columns([1/2,1/3,1/4])
sage: x
(5/6, 49/12, 22/3, 127/12)
sage: x.parent()
Vector space of dimension 4 over Rational Field
The length of v can be less than the number of columns, but not
greater. ::
sage: A = matrix(QQ,3,5, range(15))
sage: A.linear_combination_of_columns([1,-2,3,-4])
(-8, -18, -28)
sage: A.linear_combination_of_columns([1,2,3,4,5,6])
Traceback (most recent call last):
...
ValueError: length of v must be at most the number of columns of self
"""
if len(v) > self._ncols:
raise ValueError("length of v must be at most the number of columns of self")
if self._ncols == 0:
return self.parent().column_space().zero_vector()
from constructor import matrix
v = matrix(self._ncols, 1, list(v)+[0]*(self._ncols-len(v)))
return (self * v).column(0)
def is_symmetric(self):
"""
Returns True if this is a symmetric matrix.
EXAMPLES::
sage: m=Matrix(QQ,2,range(0,4))
sage: m.is_symmetric()
False
sage: m=Matrix(QQ,2,(1,1,1,1,1,1))
sage: m.is_symmetric()
False
sage: m=Matrix(QQ,1,(2,))
sage: m.is_symmetric()
True
"""
if self._ncols != self._nrows: return False
cdef Py_ssize_t i,j
for i from 0 <= i < self._nrows:
for j from 0 <= j < i:
if self.get_unsafe(i,j) != self.get_unsafe(j,i):
return False
return True
def is_hermitian(self):
r"""
Returns ``True`` if the matrix is equal to its conjugate-transpose.
OUTPUT:
``True`` if the matrix is square and equal to the transpose
with every entry conjugated, and ``False`` otherwise.
Note that if conjugation has no effect on elements of the base
ring (such as for integers), then the :meth:`is_symmetric`
method is equivalent and faster.
This routine is for matrices over exact rings and so may not
work properly for matrices over ``RR`` or ``CC``. For matrices with
approximate entries, the rings of double-precision floating-point
numbers, ``RDF`` and ``CDF``, are a better choice since the
:meth:`sage.matrix.matrix_double_dense.Matrix_double_dense.is_hermitian`
method has a tolerance parameter. This provides control over
allowing for minor discrepancies between entries when checking
equality.
The result is cached.
EXAMPLES::
sage: A = matrix(QQbar, [[ 1 + I, 1 - 6*I, -1 - I],
... [-3 - I, -4*I, -2],
... [-1 + I, -2 - 8*I, 2 + I]])
sage: A.is_hermitian()
False
sage: B = A*A.conjugate_transpose()
sage: B.is_hermitian()
True
Sage has several fields besides the entire complex numbers
where conjugation is non-trivial. ::
sage: F.<b> = QuadraticField(-7)
sage: C = matrix(F, [[-2*b - 3, 7*b - 6, -b + 3],
... [-2*b - 3, -3*b + 2, -2*b],
... [ b + 1, 0, -2]])
sage: C.is_hermitian()
False
sage: C = C*C.conjugate_transpose()
sage: C.is_hermitian()
True
A matrix that is nearly Hermitian, but for a non-real
diagonal entry. ::
sage: A = matrix(QQbar, [[ 2, 2-I, 1+4*I],
... [ 2+I, 3+I, 2-6*I],
... [1-4*I, 2+6*I, 5]])
sage: A.is_hermitian()
False
sage: A[1,1] = 132
sage: A.is_hermitian()
True
Rectangular matrices are never Hermitian. ::
sage: A = matrix(QQbar, 3, 4)
sage: A.is_hermitian()
False
A square, empty matrix is trivially Hermitian. ::
sage: A = matrix(QQ, 0, 0)
sage: A.is_hermitian()
True
"""
key = 'hermitian'
h = self.fetch(key)
if not h is None:
return h
if not self.is_square():
self.cache(key, False)
return False
if self._nrows == 0:
self.cache(key, True)
return True
cdef Py_ssize_t i,j
hermitian = True
for i in range(self._nrows):
for j in range(i+1):
if self.get_unsafe(i,j) != self.get_unsafe(j,i).conjugate():
hermitian = False
break
if not hermitian:
break
self.cache(key, hermitian)
return hermitian
def is_skew_symmetric(self):
"""
Returns True if this is a skew symmetric matrix.
EXAMPLES::
sage: m = matrix(QQ, [[0,2], [-2,0]])
sage: m.is_skew_symmetric()
True
sage: m = matrix(QQ, [[1,2], [2,1]])
sage: m.is_skew_symmetric()
False
"""
if self._ncols != self._nrows: return False
cdef Py_ssize_t i,j
for i from 0 <= i < self._nrows:
for j from 0 <= j <= i:
if self.get_unsafe(i,j) != -self.get_unsafe(j,i):
return False
return True
def is_symmetrizable(self, return_diag=False, positive=True):
r"""
This function takes a square matrix over an *ordered integral domain* and checks if it is symmetrizable.
A matrix `B` is symmetrizable iff there exists an invertible diagonal matrix `D` such that `DB` is symmetric.
.. warning:: Expects ``self`` to be a matrix over an *ordered integral domain*.
INPUT:
- ``return_diag`` -- bool(default:False) if True and ``self`` is symmetrizable the diagonal entries of the matrix `D` are returned.
- ``positive`` -- bool(default:True) if True, the condition that `D` has positive entries is added.
OUTPUT:
- True -- if ``self`` is symmetrizable and ``return_diag`` is False
- the diagonal entries of a matrix `D` such that `DB` is symmetric -- iff ``self`` is symmetrizable and ``return_diag`` is True
- False -- iff ``self`` is not symmetrizable
EXAMPLES::
sage: matrix([[0,6],[3,0]]).is_symmetrizable(positive=False)
True
sage: matrix([[0,6],[3,0]]).is_symmetrizable(positive=True)
True
sage: matrix([[0,6],[0,0]]).is_symmetrizable(return_diag=True)
False
sage: matrix([2]).is_symmetrizable(positive=True)
True
sage: matrix([[1,2],[3,4]]).is_symmetrizable(return_diag=true)
[1, 2/3]
REFERENCES:
- [FZ2001] S. Fomin, A. Zelevinsky. Cluster Algebras 1: Foundations, arXiv:math/0104151 (2001).
"""
if self._ncols != self._nrows:
raise ValueError, "The matrix is not a square matrix"
return self._check_symmetrizability(return_diag=return_diag, skew=False, positive=positive)
def is_skew_symmetrizable(self, return_diag=False, positive=True):
r"""
This function takes a square matrix over an *ordered integral domain* and checks if it is skew-symmetrizable.
A matrix `B` is skew-symmetrizable iff there exists an invertible diagonal matrix `D` such that `DB` is skew-symmetric.
.. warning:: Expects ``self`` to be a matrix over an *ordered integral domain*.
INPUT:
- ``return_diag`` -- bool(default:False) if True and ``self`` is skew-symmetrizable the diagonal entries of the matrix `D` are returned.
- ``positive`` -- bool(default:True) if True, the condition that `D` has positive entries is added.
OUTPUT:
- True -- if ``self`` is skew-symmetrizable and ``return_diag`` is False
- the diagonal entries of a matrix `D` such that `DB` is skew-symmetric -- iff ``self`` is skew-symmetrizable and ``return_diag`` is True
- False -- iff ``self`` is not skew-symmetrizable
EXAMPLES::
sage: matrix([[0,6],[3,0]]).is_skew_symmetrizable(positive=False)
True
sage: matrix([[0,6],[3,0]]).is_skew_symmetrizable(positive=True)
False
sage: M = matrix(4,[0,1,0,0,-1,0,-1,0,0,2,0,1,0,0,-1,0]); M
[ 0 1 0 0]
[-1 0 -1 0]
[ 0 2 0 1]
[ 0 0 -1 0]
sage: M.is_skew_symmetrizable(return_diag=True)
[1, 1, 1/2, 1/2]
sage: M2 = diagonal_matrix([1,1,1/2,1/2])*M; M2
[ 0 1 0 0]
[ -1 0 -1 0]
[ 0 1 0 1/2]
[ 0 0 -1/2 0]
sage: M2.is_skew_symmetric()
True
REFERENCES:
- [FZ2001] S. Fomin, A. Zelevinsky. Cluster Algebras 1: Foundations, arXiv:math/0104151 (2001).
"""
if self._ncols != self._nrows:
raise ValueError, "The matrix is not a square matrix"
return self._check_symmetrizability(return_diag=return_diag, skew=True, positive=positive)
def is_dense(self):
"""
Returns True if this is a dense matrix.
In Sage, being dense is a property of the underlying
representation, not the number of nonzero entries.
EXAMPLES::
sage: matrix(QQ,2,2,range(4)).is_dense()
True
sage: matrix(QQ,2,2,range(4),sparse=True).is_dense()
False
"""
return self.is_dense_c()
def is_sparse(self):
"""
Return True if this is a sparse matrix.
In Sage, being sparse is a property of the underlying
representation, not the number of nonzero entries.
EXAMPLES::
sage: matrix(QQ,2,2,range(4)).is_sparse()
False
sage: matrix(QQ,2,2,range(4),sparse=True).is_sparse()
True
"""
return self.is_sparse_c()
def is_square(self):
"""
Return True precisely if this matrix is square, i.e., has the same
number of rows and columns.
EXAMPLES::
sage: matrix(QQ,2,2,range(4)).is_square()
True
sage: matrix(QQ,2,3,range(6)).is_square()
False
"""
return self._nrows == self._ncols
def is_invertible(self):
r"""
Return True if this matrix is invertible.
EXAMPLES: The following matrix is invertible over
`\QQ` but not over `\ZZ`.
::
sage: A = MatrixSpace(ZZ, 2)(range(4))
sage: A.is_invertible()
False
sage: A.matrix_over_field().is_invertible()
True
The inverse function is a constructor for matrices over the
fraction field, so it can work even if A is not invertible.
::
sage: ~A # inverse of A
[-3/2 1/2]
[ 1 0]
The next matrix is invertible over `\ZZ`.
::
sage: A = MatrixSpace(IntegerRing(),2)([1,10,0,-1])
sage: A.is_invertible()
True
sage: ~A # compute the inverse
[ 1 10]
[ 0 -1]
The following nontrivial matrix is invertible over
`\ZZ[x]`.
::
sage: R.<x> = PolynomialRing(IntegerRing())
sage: A = MatrixSpace(R,2)([1,x,0,-1])
sage: A.is_invertible()
True
sage: ~A
[ 1 x]
[ 0 -1]
"""
return self.is_square() and self.determinant().is_unit()
def is_singular(self):
r"""
Returns ``True`` if ``self`` is singular.
OUTPUT:
A square matrix is singular if it has a zero
determinant and this method will return ``True``
in exactly this case. When the entries of the
matrix come from a field, this is equivalent
to having a nontrivial kernel, or lacking an
inverse, or having linearly dependent rows,
or having linearly dependent columns.
For square matrices over a field the methods
:meth:`is_invertible` and :meth:`is_singular`
are logical opposites. However, it is an error
to apply :meth:`is_singular` to a matrix that
is not square, while :meth:`is_invertible` will
always return ``False`` for a matrix that is not
square.
EXAMPLES:
A singular matrix over the field ``QQ``. ::
sage: A = matrix(QQ, 4, [-1,2,-3,6,0,-1,-1,0,-1,1,-5,7,-1,6,5,2])
sage: A.is_singular()
True
sage: A.right_kernel().dimension()
1
A matrix that is not singular, i.e. nonsingular, over a field. ::
sage: B = matrix(QQ, 4, [1,-3,-1,-5,2,-5,-2,-7,-2,5,3,4,-1,4,2,6])
sage: B.is_singular()
False
sage: B.left_kernel().dimension()
0
For "rectangular" matrices, invertibility is always
``False``, but asking about singularity will give an error. ::
sage: C = matrix(QQ, 5, range(30))
sage: C.is_invertible()
False
sage: C.is_singular()
Traceback (most recent call last):
...
ValueError: self must be a square matrix
When the base ring is not a field, then a matrix
may be both not invertible and not singular. ::
sage: D = matrix(ZZ, 4, [2,0,-4,8,2,1,-2,7,2,5,7,0,0,1,4,-6])
sage: D.is_invertible()
False
sage: D.is_singular()
False
sage: d = D.determinant(); d
2
sage: d.is_unit()
False
"""
if self.ncols() == self.nrows():
return self.rank() != self.nrows()
else:
raise ValueError("self must be a square matrix")
def pivots(self):
"""
Return the pivot column positions of this matrix.
OUTPUT: a tuple of Python integers: the position of the
first nonzero entry in each row of the echelon form.
This returns a tuple so it is immutable; see #10752.
EXAMPLES:
sage: A = matrix(QQ, 2, 2, range(4))
sage: A.pivots()
(0, 1)
"""
x = self.fetch('pivots')
if not x is None: return tuple(x)
self.echelon_form()
x = self.fetch('pivots')
if x is None:
print self
print self.nrows()
print self.dict()
raise RuntimeError("BUG: matrix pivots should have been set but weren't, matrix parent = '%s'"%self.parent())
return tuple(x)
def rank(self):
"""
TESTS:
We should be able to compute the rank of a matrix whose
entries are polynomials over a finite field (trac #5014)::
sage: P.<x> = PolynomialRing(GF(17))
sage: m = matrix(P, [ [ 6*x^2 + 8*x + 12, 10*x^2 + 4*x + 11],
... [8*x^2 + 12*x + 15, 8*x^2 + 9*x + 16] ])
sage: m.rank()
2
"""
x = self.fetch('rank')
if not x is None: return x
if self._nrows == 0 or self._ncols == 0:
return 0
r = len(self.pivots())
self.cache('rank', r)
return r
cdef _set_pivots(self, X):
self.cache('pivots', X)
def nonpivots(self):
"""
Return the list of i such that the i-th column of self is NOT a
pivot column of the reduced row echelon form of self.
OUTPUT: sorted tuple of (Python) integers
EXAMPLES::
sage: a = matrix(QQ,3,3,range(9)); a
[0 1 2]
[3 4 5]
[6 7 8]
sage: a.echelon_form()
[ 1 0 -1]
[ 0 1 2]
[ 0 0 0]
sage: a.nonpivots()
(2,)
"""
x = self.fetch('nonpivots')
if not x is None: return tuple(x)
X = set(self.pivots())
np = []
for j in xrange(self.ncols()):
if not (j in X):
np.append(j)
np = tuple(np)
self.cache('nonpivots',np)
return np
def nonzero_positions(self, copy=True, column_order=False):
"""
Returns the sorted list of pairs (i,j) such that self[i,j] != 0.
INPUT:
- ``copy`` - (default: True) It is safe to change the
resulting list (unless you give the option copy=False).
- ``column_order`` - (default: False) If true,
returns the list of pairs (i,j) such that self[i,j] != 0, but
sorted by columns, i.e., column j=0 entries occur first, then
column j=1 entries, etc.
EXAMPLES::
sage: a = matrix(QQ, 2,3, [1,2,0,2,0,0]); a
[1 2 0]
[2 0 0]
sage: a.nonzero_positions()
[(0, 0), (0, 1), (1, 0)]
sage: a.nonzero_positions(copy=False)
[(0, 0), (0, 1), (1, 0)]
sage: a.nonzero_positions(column_order=True)
[(0, 0), (1, 0), (0, 1)]
sage: a = matrix(QQ, 2,3, [1,2,0,2,0,0], sparse=True); a
[1 2 0]
[2 0 0]
sage: a.nonzero_positions()
[(0, 0), (0, 1), (1, 0)]
sage: a.nonzero_positions(copy=False)
[(0, 0), (0, 1), (1, 0)]
sage: a.nonzero_positions(column_order=True)
[(0, 0), (1, 0), (0, 1)]
"""
if column_order:
return self._nonzero_positions_by_column(copy)
else:
return self._nonzero_positions_by_row(copy)
def _nonzero_positions_by_row(self, copy=True):
"""
Returns the list of pairs (i,j) such that self[i,j] != 0.
It is safe to change the resulting list (unless you give the option copy=False).
EXAMPLE::
sage: M = Matrix(CC, [[1,0],[0,1]], sparse=True)
sage: M._nonzero_positions_by_row()
[(0, 0), (1, 1)]
"""
x = self.fetch('nonzero_positions')
if not x is None:
if copy:
return list(x)
return x
cdef Py_ssize_t i, j
z = self._base_ring(0)
nzp = []
for i from 0 <= i < self._nrows:
for j from 0 <= j < self._ncols:
if self.get_unsafe(i,j) != z:
nzp.append((i,j))
self.cache('nonzero_positions', nzp)
if copy:
return list(nzp)
return nzp
def _nonzero_positions_by_column(self, copy=True):
"""
Returns the list of pairs (i,j) such that self[i,j] != 0, but
sorted by columns, i.e., column j=0 entries occur first, then
column j=1 entries, etc.
It is safe to change the resulting list (unless you give the option
copy=False).
EXAMPLES::
sage: m=matrix(QQ,2,[1,0,1,1,1,0])
sage: m._nonzero_positions_by_column()
[(0, 0), (1, 0), (1, 1), (0, 2)]
"""
x = self.fetch('nonzero_positions_by_column')
if not x is None:
if copy:
return list(x)
return x
cdef Py_ssize_t i, j
z = self._base_ring(0)
nzp = []
for j from 0 <= j < self._ncols:
for i from 0 <= i < self._nrows:
if self.get_unsafe(i,j) != z:
nzp.append((i,j))
self.cache('nonzero_positions_by_column', nzp)
if copy:
return list(nzp)
return nzp
def nonzero_positions_in_column(self, Py_ssize_t i):
"""
Return a sorted list of the integers j such that self[j,i] is
nonzero, i.e., such that the j-th position of the i-th column is
nonzero.
INPUT:
- ``i`` - an integer
OUTPUT: list
EXAMPLES::
sage: a = matrix(QQ, 3,2, [1,2,0,2,0,0]); a
[1 2]
[0 2]
[0 0]
sage: a.nonzero_positions_in_column(0)
[0]
sage: a.nonzero_positions_in_column(1)
[0, 1]
You'll get an IndexError, if you select an invalid column::
sage: a.nonzero_positions_in_column(2)
Traceback (most recent call last):
...
IndexError: matrix column index out of range
"""
cdef Py_ssize_t j
z = self._base_ring(0)
tmp = []
if i<0 or i >= self._ncols:
raise IndexError("matrix column index out of range")
for j from 0 <= j < self._nrows:
if self.get_unsafe(j,i) != z:
tmp.append(j)
return tmp
def nonzero_positions_in_row(self, Py_ssize_t i):
"""
Return the integers j such that self[i,j] is nonzero, i.e., such
that the j-th position of the i-th row is nonzero.
INPUT:
- ``i`` - an integer
OUTPUT: list
EXAMPLES::
sage: a = matrix(QQ, 3,2, [1,2,0,2,0,0]); a
[1 2]
[0 2]
[0 0]
sage: a.nonzero_positions_in_row(0)
[0, 1]
sage: a.nonzero_positions_in_row(1)
[1]
sage: a.nonzero_positions_in_row(2)
[]
"""
cdef Py_ssize_t j
if i<0 or i >= self._nrows:
raise IndexError("matrix row index out of range")
z = self._base_ring(0)
tmp = []
for j from 0 <= j < self._ncols:
if self.get_unsafe(i,j) != z:
tmp.append(j)
return tmp
def multiplicative_order(self):
"""
Return the multiplicative order of this matrix, which must
therefore be invertible.
EXAMPLES::
sage: A = matrix(GF(59),3,[10,56,39,53,56,33,58,24,55])
sage: A.multiplicative_order()
580
sage: (A^580).is_one()
True
::
sage: B = matrix(GF(10007^3,'b'),0)
sage: B.multiplicative_order()
1
::
sage: C = matrix(GF(2^10,'c'),2,3,[1]*6)
sage: C.multiplicative_order()
Traceback (most recent call last):
...
ArithmeticError: self must be invertible ...
::
sage: D = matrix(IntegerModRing(6),3,[5,5,3,0,2,5,5,4,0])
sage: D.multiplicative_order()
Traceback (most recent call last):
...
NotImplementedError: ... only ... over finite fields
::
sage: E = MatrixSpace(GF(11^2,'e'),5).random_element()
sage: (E^E.multiplicative_order()).is_one()
True
REFERENCES:
- Frank Celler and C. R. Leedham-Green, "Calculating the Order of an Invertible Matrix", 1997
"""
if not self.is_invertible():
raise ArithmeticError("self must be invertible to have a multiplicative order")
K = self.base_ring()
if not (K.is_field() and K.is_finite()):
raise NotImplementedError("multiplicative order is only implemented for matrices over finite fields")
from sage.rings.integer import Integer
from sage.groups.generic import order_from_multiple
P = self.minimal_polynomial()
if P.degree()==0:
return 1
R = P.parent()
P = P.factor()
q = K.cardinality()
p = K.characteristic()
a = 0
res = Integer(1)
for f,m in P:
a = max(a,m)
S = R.quotient(f,'y')
res = res._lcm(order_from_multiple(S.gen(),q**f.degree()-1,operation='*'))
ppart = p**Integer(a).exact_log(p)
if ppart<a: ppart*=p
return res*ppart
cdef Vector _vector_times_matrix_(self, Vector v):
"""
Returns the vector times matrix product.
INPUT:
- ``v`` - a free module element.
OUTPUT: The vector times matrix product v\*A.
EXAMPLES::
sage: B = matrix(QQ,2, [1,2,3,4])
sage: V = VectorSpace(QQ, 2)
sage: v = V([-1,5])
sage: v*B
(14, 18)
sage: -1*B.row(0) + 5*B.row(1)
(14, 18)
sage: B*v # computes B*v, where v is interpreted as a column vector.
(9, 17)
sage: -1*B.column(0) + 5*B.column(1)
(9, 17)
We mix dense and sparse over different rings::
sage: v = FreeModule(ZZ, 3, sparse=True)([1, 2, 3])
sage: m = matrix(QQ, 3, 4, range(12))
sage: v * m
(32, 38, 44, 50)
sage: v = FreeModule(ZZ, 3, sparse=False)([1, 2, 3])
sage: m = matrix(QQ, 3, 4, range(12), sparse=True)
sage: v * m
(32, 38, 44, 50)
sage: (v * m).parent() is m.row(0).parent()
True
"""
M = sage.modules.free_module.FreeModule(self._base_ring, self.ncols(), sparse=self.is_sparse())
if self.nrows() != v.degree():
raise ArithmeticError("number of rows of matrix must equal degree of vector")
s = M(0)
zero = self.base_ring()(0)
cdef Py_ssize_t i
for i from 0 <= i < self._nrows:
if v[i] != zero:
s += v[i]*self.row(i, from_list=True)
return s
cdef Vector _matrix_times_vector_(self, Vector v):
"""
EXAMPLES::
sage: v = FreeModule(ZZ, 3, sparse=True)([1, 2, 3])
sage: m = matrix(QQ, 4, 3, range(12))
sage: m * v
(8, 26, 44, 62)
sage: v = FreeModule(ZZ, 3, sparse=False)([1, 2, 3])
sage: m = matrix(QQ, 4, 3, range(12), sparse=True)
sage: m * v
(8, 26, 44, 62)
sage: (m * v).parent() is m.column(0).parent()
True
"""
M = sage.modules.free_module.FreeModule(self._base_ring, self.nrows(), sparse=self.is_sparse())
if not PY_TYPE_CHECK(v, sage.modules.free_module_element.FreeModuleElement):
v = M(v)
if self.ncols() != v.degree():
raise ArithmeticError("number of columns of matrix must equal degree of vector")
s = M(0)
for i in xrange(self.ncols()):
if v[i] != 0:
s = s + self.column(i, from_list=True)*v[i]
return s
def iterates(self, v, n, rows=True):
r"""
Let `A` be this matrix and `v` be a free module
element. If rows is True, return a matrix whose rows are the
entries of the following vectors:
.. math::
v, v A, v A^2, \ldots, v A^{n-1}.
If rows is False, return a matrix whose columns are the entries of
the following vectors:
.. math::
v, Av, A^2 v, \ldots, A^{n-1} v.
INPUT:
- ``v`` - free module element
- ``n`` - nonnegative integer
EXAMPLES::
sage: A = matrix(ZZ,2, [1,1,3,5]); A
[1 1]
[3 5]
sage: v = vector([1,0])
sage: A.iterates(v,0)
[]
sage: A.iterates(v,5)
[ 1 0]
[ 1 1]
[ 4 6]
[ 22 34]
[124 192]
Another example::
sage: a = matrix(ZZ,3,range(9)); a
[0 1 2]
[3 4 5]
[6 7 8]
sage: v = vector([1,0,0])
sage: a.iterates(v,4)
[ 1 0 0]
[ 0 1 2]
[ 15 18 21]
[180 234 288]
sage: a.iterates(v,4,rows=False)
[ 1 0 15 180]
[ 0 3 42 558]
[ 0 6 69 936]
"""
n = int(n)
if n >= 2 and self.nrows() != self.ncols():
raise ArithmeticError("matrix must be square if n >= 2.")
if n == 0:
return self.matrix_space(n, self.ncols())(0)
m = self.nrows()
M = sage.modules.free_module.FreeModule(self._base_ring, m, sparse=self.is_sparse())
v = M(v)
X = [v]
if rows:
for _ in range(n-1):
X.append(X[len(X)-1]*self)
MS = self.matrix_space(n, m)
return MS(X)
else:
for _ in range(n-1):
X.append(self*X[len(X)-1])
MS = self.matrix_space(n, m)
return MS(X).transpose()
cpdef ModuleElement _add_(self, ModuleElement right):
"""
Add two matrices with the same parent.
EXAMPLES::
sage: R.<x,y> = FreeAlgebra(QQ,2)
sage: a = matrix(2,2, [1,2,x*y,y*x])
sage: b = matrix(2,2, [1,2,y*x,y*x])
sage: a+b # indirect doctest
[ 2 4]
[x*y + y*x 2*y*x]
"""
cdef Py_ssize_t i, j
cdef Matrix A
A = self.new_matrix()
for i from 0 <= i < self._nrows:
for j from 0 <= j < self._ncols:
A.set_unsafe(i,j, self.get_unsafe(i,j) + (<Matrix>right).get_unsafe(i,j))
return A
cpdef ModuleElement _sub_(self, ModuleElement right):
"""
Subtract two matrices with the same parent.
EXAMPLES::
sage: R.<x,y> = FreeAlgebra(QQ,2)
sage: a = matrix(2,2, [1,2,x*y,y*x])
sage: b = matrix(2,2, [1,2,y*x,y*x])
sage: a-b # indirect doctest
[ 0 0]
[x*y - y*x 0]
"""
cdef Py_ssize_t i, j
cdef Matrix A
A = self.new_matrix()
for i from 0 <= i < self._nrows:
for j from 0 <= j < self._ncols:
A.set_unsafe(i,j, self.get_unsafe(i,j) - (<Matrix>right).get_unsafe(i,j))
return A
def __mod__(self, p):
r"""
Return matrix mod `p`, returning again a matrix over the
same base ring.
.. note::
Use ``A.Mod(p)`` to obtain a matrix over the residue class
ring modulo `p`.
EXAMPLES::
sage: M = Matrix(ZZ, 2, 2, [5, 9, 13, 15])
sage: M % 7
[5 2]
[6 1]
sage: parent(M % 7)
Full MatrixSpace of 2 by 2 dense matrices over Integer Ring
"""
cdef Py_ssize_t i
v = self.list()
for i from 0 <= i < len(v):
v[i] = v[i] % p
return self.new_matrix(entries = v, copy=False, coerce=True)
def mod(self, p):
"""
Return matrix mod `p`, over the reduced ring.
EXAMPLES::
sage: M = matrix(ZZ, 2, 2, [5, 9, 13, 15])
sage: M.mod(7)
[5 2]
[6 1]
sage: parent(M.mod(7))
Full MatrixSpace of 2 by 2 dense matrices over Ring of integers modulo 7
"""
return self.change_ring(self._base_ring.quotient_ring(p))
cpdef ModuleElement _rmul_(self, RingElement left):
"""
EXAMPLES::
sage: a = matrix(QQ['x'],2,range(6))
sage: (3/4) * a
[ 0 3/4 3/2]
[ 9/4 3 15/4]
sage: R.<x,y> = QQ[]
sage: a = matrix(R,2,3,[1,x,y,-x*y,x+y,x-y]); a
[ 1 x y]
[ -x*y x + y x - y]
sage: (x*y) * a
[ x*y x^2*y x*y^2]
[ -x^2*y^2 x^2*y + x*y^2 x^2*y - x*y^2]
sage: R.<x,y> = FreeAlgebra(ZZ,2)
sage: a = matrix(R,2,3,[1,x,y,-x*y,x+y,x-y]); a
[ 1 x y]
[ -x*y x + y x - y]
sage: (x*y) * a # indirect doctest
[ x*y x*y*x x*y^2]
[ -x*y*x*y x*y*x + x*y^2 x*y*x - x*y^2]
"""
if PY_TYPE_CHECK(self._base_ring, CommutativeRing):
return self._lmul_(left)
cdef Py_ssize_t r,c
cpdef RingElement x
x = self._base_ring(left)
cdef Matrix ans
ans = self._parent.zero_matrix().__copy__()
for r from 0 <= r < self._nrows:
for c from 0 <= c < self._ncols:
ans.set_unsafe(r, c, x._mul_(<RingElement>self.get_unsafe(r, c)))
return ans
cpdef ModuleElement _lmul_(self, RingElement right):
"""
EXAMPLES:
A simple example in which the base ring is commutative::
sage: a = matrix(QQ['x'],2,range(6))
sage: a*(3/4)
[ 0 3/4 3/2]
[ 9/4 3 15/4]
An example in which the base ring is not commutative::
sage: F.<x,y> = FreeAlgebra(QQ,2)
sage: a = matrix(2,[x,y,x^2,y^2]); a
[ x y]
[x^2 y^2]
sage: x * a # indirect doctest
[ x^2 x*y]
[ x^3 x*y^2]
sage: a * y
[ x*y y^2]
[x^2*y y^3]
sage: R.<x,y> = FreeAlgebra(ZZ,2)
sage: a = matrix(R,2,3,[1,x,y,-x*y,x+y,x-y]); a
[ 1 x y]
[ -x*y x + y x - y]
sage: a * (x*y)
[ x*y x^2*y y*x*y]
[ -x*y*x*y x^2*y + y*x*y x^2*y - y*x*y]
"""
cdef Py_ssize_t r,c
cpdef RingElement x
x = self._base_ring(right)
cdef Matrix ans
ans = self._parent.zero_matrix().__copy__()
for r from 0 <= r < self._nrows:
for c from 0 <= c < self._ncols:
ans.set_unsafe(r, c, (<RingElement>self.get_unsafe(r, c))._mul_(x))
return ans
cdef sage.structure.element.Matrix _matrix_times_matrix_(self, sage.structure.element.Matrix right):
r"""
Return the product of two matrices.
EXAMPLE of matrix times matrix over same base ring: We multiply
matrices over `\QQ[x,y]`.
::
sage: R.<x,y> = QQ[]
sage: a = matrix(R,2,3,[1,x,y,-x*y,x+y,x-y]); a
[ 1 x y]
[ -x*y x + y x - y]
sage: b = a.transpose(); b
[ 1 -x*y]
[ x x + y]
[ y x - y]
sage: a*b # indirect doctest
[ x^2 + y^2 + 1 x^2 + x*y - y^2]
[ x^2 + x*y - y^2 x^2*y^2 + 2*x^2 + 2*y^2]
sage: b*a # indirect doctest
[ x^2*y^2 + 1 -x^2*y - x*y^2 + x -x^2*y + x*y^2 + y]
[ -x^2*y - x*y^2 + x 2*x^2 + 2*x*y + y^2 x^2 + x*y - y^2]
[ -x^2*y + x*y^2 + y x^2 + x*y - y^2 x^2 - 2*x*y + 2*y^2]
We verify that the matrix multiplies are correct by comparing them
with what PARI gets::
sage: gp(a)*gp(b) - gp(a*b)
[0, 0; 0, 0]
sage: gp(b)*gp(a) - gp(b*a)
[0, 0, 0; 0, 0, 0; 0, 0, 0]
EXAMPLE of matrix times matrix over different base rings::
sage: a = matrix(ZZ,2,2,range(4))
sage: b = matrix(GF(7),2,2,range(4))
sage: c = matrix(QQ,2,2,range(4))
sage: d = a*b; d
[2 3]
[6 4]
sage: parent(d)
Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7
sage: parent(b*a)
Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7
sage: d = a*c; d
[ 2 3]
[ 6 11]
sage: parent(d)
Full MatrixSpace of 2 by 2 dense matrices over Rational Field
sage: d = b+c
Traceback (most recent call last):
...
TypeError: unsupported operand parent(s) for '+': 'Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7' and 'Full MatrixSpace of 2 by 2 dense matrices over Rational Field'
sage: d = b+c.change_ring(GF(7)); d
[0 2]
[4 6]
EXAMPLE of matrix times matrix where one matrix is sparse and the
other is dense (in such mixed cases, the result is always dense)::
sage: a = matrix(ZZ,2,2,range(4),sparse=True)
sage: b = matrix(GF(7),2,2,range(4),sparse=False)
sage: c = a*b; c
[2 3]
[6 4]
sage: parent(c)
Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7
sage: c = b*a; c
[2 3]
[6 4]
sage: parent(c)
Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7
EXAMPLE of matrix multiplication over a noncommutative base ring::
sage: R.<x,y> = FreeAlgebra(QQ,2)
sage: x*y - y*x
x*y - y*x
sage: a = matrix(2,2, [1,2,x,y])
sage: b = matrix(2,2, [x,y,x^2,y^2])
sage: a*b
[ x + 2*x^2 y + 2*y^2]
[x^2 + y*x^2 x*y + y^3]
sage: b*a
[ x + y*x 2*x + y^2]
[x^2 + y^2*x 2*x^2 + y^3]
EXAMPLE of row vector times matrix (vectors are row vectors, so
matrices act from the right)::
sage: a = matrix(2,3, range(6)); a
[0 1 2]
[3 4 5]
sage: V = ZZ^2
sage: v = V([-2,3]); v
(-2, 3)
sage: v*a
(9, 10, 11)
This is not allowed, since v is a *row* vector::
sage: a*v
Traceback (most recent call last):
...
TypeError: unsupported operand parent(s) for '*': 'Full MatrixSpace of 2 by 3 dense matrices over Integer Ring' and 'Ambient free module of rank 2 over the principal ideal domain Integer Ring'
This illustrates how coercion works::
sage: V = QQ^2
sage: v = V([-2,3]); v
(-2, 3)
sage: parent(v*a)
Vector space of dimension 3 over Rational Field
EXAMPLE of matrix times column vector: (column vectors are not
implemented yet) TODO TODO
EXAMPLE of scalar times matrix::
sage: a = matrix(2,3, range(6)); a
[0 1 2]
[3 4 5]
sage: b = 3*a; b
[ 0 3 6]
[ 9 12 15]
sage: parent(b)
Full MatrixSpace of 2 by 3 dense matrices over Integer Ring
sage: b = (2/3)*a; b
[ 0 2/3 4/3]
[ 2 8/3 10/3]
sage: parent(b)
Full MatrixSpace of 2 by 3 dense matrices over Rational Field
EXAMPLE of matrix times scalar::
sage: a = matrix(2,3, range(6)); a
[0 1 2]
[3 4 5]
sage: b = a*3; b
[ 0 3 6]
[ 9 12 15]
sage: parent(b)
Full MatrixSpace of 2 by 3 dense matrices over Integer Ring
sage: b = a*(2/3); b
[ 0 2/3 4/3]
[ 2 8/3 10/3]
sage: parent(b)
Full MatrixSpace of 2 by 3 dense matrices over Rational Field
EXAMPLE of scalar multiplication in the noncommutative case::
sage: R.<x,y> = FreeAlgebra(ZZ,2)
sage: a = matrix(2,[x,y,x^2,y^2])
sage: a * x
[ x^2 y*x]
[ x^3 y^2*x]
sage: x * a
[ x^2 x*y]
[ x^3 x*y^2]
sage: a*x - x*a
[ 0 -x*y + y*x]
[ 0 -x*y^2 + y^2*x]
"""
if self._will_use_strassen(right):
return self._multiply_strassen(right)
else:
return self._multiply_classical(right)
cdef bint _will_use_strassen(self, Matrix right) except -2:
"""
Whether or not matrix multiplication of self by right should be
done using Strassen.
Overload _strassen_default_cutoff to return -1 to not use
Strassen by default.
"""
cdef int n
n = self._strassen_default_cutoff(right)
if n == -1:
return 0
if self._nrows > n and self._ncols > n and \
right._nrows > n and right._ncols > n:
return 1
return 0
cdef bint _will_use_strassen_echelon(self) except -2:
"""
Whether or not matrix multiplication of self by right should be
done using Strassen.
Overload this in derived classes to not use Strassen by default.
"""
cdef int n
n = self._strassen_default_echelon_cutoff()
if n == -1:
return 0
if self._nrows > n and self._ncols > n:
return 1
return 0
def __neg__(self):
"""
Return the negative of self.
EXAMPLES::
sage: a = matrix(ZZ,2,range(4))
sage: a.__neg__()
[ 0 -1]
[-2 -3]
sage: -a
[ 0 -1]
[-2 -3]
"""
return self._lmul_(self._base_ring(-1))
def __invert__(self):
r"""
Return this inverse of this matrix, as a matrix over the fraction
field.
Raises a ``ZeroDivisionError`` if the matrix has zero
determinant, and raises an ``ArithmeticError``, if the
inverse doesn't exist because the matrix is nonsquare. Also, note,
e.g., that the inverse of a matrix over `\ZZ` is
always a matrix defined over `\QQ` (even if the
entries are integers).
EXAMPLES::
sage: A = MatrixSpace(ZZ, 2)([1,1,3,5])
sage: ~A
[ 5/2 -1/2]
[-3/2 1/2]
sage: A.__invert__()
[ 5/2 -1/2]
[-3/2 1/2]
Even if the inverse lies in the base field, the result is still a
matrix over the fraction field.
::
sage: I = MatrixSpace(ZZ,2)(1) # identity matrix
sage: ~I
[1 0]
[0 1]
sage: (~I).parent()
Full MatrixSpace of 2 by 2 dense matrices over Rational Field
This is analogous to the situation for ring elements, e.g., for
`\ZZ` we have::
sage: parent(~1)
Rational Field
A matrix with 0 rows and 0 columns is invertible (see trac #3734)::
sage: M = MatrixSpace(RR,0,0)(0); M
[]
sage: M.determinant()
1.00000000000000
sage: M.is_invertible()
True
sage: M.inverse() == M
True
Matrices over the integers modulo a composite modulus::
sage: m = matrix(Zmod(49),2,[2,1,3,3])
sage: type(m)
<type 'sage.matrix.matrix_modn_dense_float.Matrix_modn_dense_float'>
sage: ~m
[ 1 16]
[48 17]
sage: m = matrix(Zmod(2^100),2,[2,1,3,3])
sage: type(m)
<type 'sage.matrix.matrix_generic_dense.Matrix_generic_dense'>
sage: (~m)*m
[1 0]
[0 1]
sage: ~m
[ 1 422550200076076467165567735125]
[1267650600228229401496703205375 422550200076076467165567735126]
This matrix isn't invertible::
sage: m = matrix(Zmod(9),2,[2,1,3,3])
sage: ~m
Traceback (most recent call last):
...
ZeroDivisionError: input matrix must be nonsingular
Check to make sure that trac #2256 is still fixed::
sage: M = MatrixSpace(CC, 2)(-1.10220440881763)
sage: N = ~M
sage: (N*M).norm()
1.0
"""
if not self.base_ring().is_field():
try:
return ~self.matrix_over_field()
except TypeError:
if is_IntegerModRing(self.base_ring()):
try:
return (~self.lift()).change_ring(self.base_ring())
except (TypeError, ZeroDivisionError):
raise ZeroDivisionError("input matrix must be nonsingular")
raise
if not self.is_square():
raise ArithmeticError("self must be a square matrix")
if self.nrows()==0:
return self
A = self.augment(self.parent().identity_matrix())
B = A.echelon_form()
if self.base_ring().is_exact():
if B[self._nrows-1, self._ncols-1] != 1:
raise ZeroDivisionError("input matrix must be nonsingular")
else:
if not B[self._nrows-1, self._ncols-1]:
raise ZeroDivisionError("input matrix must be nonsingular")
return B.matrix_from_columns(range(self._ncols, 2*self._ncols))
def __pos__(self):
"""
Return +self, which is just self, of course.
EXAMPLES::
sage: a = matrix(ZZ,2,range(4))
sage: +a
[0 1]
[2 3]
sage: a.__pos__()
[0 1]
[2 3]
"""
return self
def __pow__(self, n, ignored):
"""
EXAMPLES::
sage: MS = MatrixSpace(QQ, 3, 3)
sage: A = MS([0, 0, 1, 1, 0, '-2/11', 0, 1, '-3/11'])
sage: A * A^(-1) == 1
True
sage: A^4
[ -3/11 -13/121 1436/1331]
[ 127/121 -337/1331 -4445/14641]
[ -13/121 1436/1331 -8015/14641]
sage: A.__pow__(4)
[ -3/11 -13/121 1436/1331]
[ 127/121 -337/1331 -4445/14641]
[ -13/121 1436/1331 -8015/14641]
Sage follows Python's convention 0^0 = 1, as each of the following
examples show::
sage: a = Matrix([[1,0],[0,0]]); a
[1 0]
[0 0]
sage: a^0 # lower right entry is 0^0
[1 0]
[0 1]
sage: Matrix([[0]])^0
[1]
sage: 0^0
1
"""
if not self.is_square():
raise ArithmeticError("self must be a square matrix")
return RingElement.__pow__(self, n, ignored)
def __hash__(self):
"""
Return the hash of this (immutable) matrix
EXAMPLES::
sage: m=matrix(QQ,2,[1,2,3,4])
sage: m.set_immutable()
sage: m.__hash__()
8
"""
return self._hash()
cdef long _hash(self) except -1:
raise NotImplementedError
cdef int _cmp_c_impl(left,Element right) except -2:
"""
Compare two matrices.
Matrices are compared in lexicographic order on the underlying list
of coefficients. A dense matrix and a sparse matrix are equal if
their coefficients are the same.
EXAMPLES: EXAMPLE comparing sparse and dense matrices::
sage: matrix(QQ,2,range(4)) == matrix(QQ,2,range(4),sparse=True)
True
sage: matrix(QQ,2,range(4)) == matrix(QQ,2,range(4),sparse=True)
True
Dictionary order::
sage: matrix(ZZ,2,[1,2,3,4]) < matrix(ZZ,2,[3,2,3,4])
True
sage: matrix(ZZ,2,[1,2,3,4]) > matrix(ZZ,2,[3,2,3,4])
False
sage: matrix(ZZ,2,[0,2,3,4]) < matrix(ZZ,2,[0,3,3,4], sparse=True)
True
"""
raise NotImplementedError
def __nonzero__(self):
"""
EXAMPLES::
sage: M = Matrix(ZZ, 2, 2, [0, 0, 0, 0])
sage: bool(M)
False
sage: M = Matrix(ZZ, 2, 2, [1, 2, 3, 5])
sage: bool(M)
True
"""
z = self._base_ring(0)
cdef Py_ssize_t i, j
for i from 0 <= i < self._nrows:
for j from 0 <= j < self._ncols:
if self.get_unsafe(i,j) != z:
return True
return False
cdef int _strassen_default_cutoff(self, Matrix right) except -2:
return -1
cdef int _strassen_default_echelon_cutoff(self) except -2:
return -1
def unpickle(cls, parent, mutability, cache, data, version):
r"""
Unpickle a matrix. This is only used internally by Sage. Users
should never call this function directly.
EXAMPLES: We illustrating saving and loading several different
types of matrices.
OVER `\ZZ`::
sage: A = matrix(ZZ,2,range(4))
sage: loads(dumps(A)) # indirect doctest
[0 1]
[2 3]
Sparse OVER `\QQ`:
Dense over `\QQ[x,y]`:
Dense over finite field.
"""
cdef Matrix A
A = cls.__new__(cls, parent, 0,0,0)
A._parent = parent
A._nrows = parent.nrows()
A._ncols = parent.ncols()
A._mutability = mutability
A._base_ring = parent.base_ring()
A._cache = cache
if version >= 0:
A._unpickle(data, version)
else:
A._unpickle_generic(data, version)
return A
max_rows = 20
max_cols = 50
def set_max_rows(n):
"""
Sets the global variable max_rows (which is used in deciding how to output a matrix).
EXAMPLES::
sage: from sage.matrix.matrix0 import set_max_rows
sage: set_max_rows(20)
"""
global max_rows
max_rows = n
def set_max_cols(n):
"""
Sets the global variable max_cols (which is used in deciding how to output a matrix).
EXAMPLES::
sage: from sage.matrix.matrix0 import set_max_cols
sage: set_max_cols(50)
"""
global max_cols
max_cols = n