Documentation for the matrix module¶
This module matrix defines the matrix.Matrix
class, as asked for the project.
Below is included a documentation (automatically generated from the docstrings present in the source file).
Complete solution for the CS101 Programming Project about matrices.
This file defines a class Matrix
, designed to be as complete as possible.
Do not worry, I was not asking you to do as much.
Examples¶
Importing the module:
>>> from matrix import *
>>> from matrix import Matrix as M # shortcut
Defining a matrix by giving its list of rows:
>>> A = M([[1, 0], [0, 1]])
>>> A == eye(A.n)
True
>>> B = 2*(A**2) + 4*A + eye(A.n)
>>> B
[[7, 0], [0, 7]]
>>> B == 7 * eye(A.n)
True
Indexing and slicing:
>>> A[1,:] = 2; A
[[1, 0], [2, 2]]
>>> A[0, 0] = -5; A
[[-5, 0], [2, 2]]
Addition, multiplication, power etc:
>>> C = eye(2); C
[[1, 0], [0, 1]]
>>> C + (3 * C) - C
[[3, 0], [0, 3]]
>>> (4 * C) ** 2
[[16, 0], [0, 16]]
Many more examples are given below:
Things that could still be worked on for this solution¶
Todo
Implement the QR, SVD and other matrix decompositions.
Todo
Try to add a randomized matrix decomposition (or any less-original matrix decomposition method)? Note: I worked on this aspect, for a project in January 2016 for my M.Sc. : https://bitbucket.org/lbesson/mva15-project-parcimonie-compressed-sensing/.
Todo
Implement a nice wrapper for a linear equations solver (with LU).
Todo
More doctests for PLUdecomposition()
, and implement the non-permuted LU decomposition?
Todo
Add more doctests and examples for Gauss, Gauss-Jordan, Gram-Schmidt (gauss()
, gauss_jordan()
, gram_schmidt()
)?
- Date: Saturday 18 juin 2016, 10:31:25.
- Author: Lilian Besson for the CS101 course at Mahindra Ecole Centrale, 2015,
- Licence: MIT Licence.
See also
I also wrote a complete solution for the other project I was in charge of, about numerical algorithms to compute integrals.
-
class
matrix.
Decimal
[source]¶ Extended
decimal.Decimal
class to improve thestr
andrepr
methods.If there is not digit after the comma, print it as an integer.
-
__weakref__
¶ list of weak references to the object (if defined)
-
-
class
matrix.
Fraction
[source]¶ Extended
fractions.Fraction
class to improve thestr
andrepr
methods.If the denominator is 1, print it as an integer.
-
__weakref__
¶ list of weak references to the object (if defined)
-
-
class
matrix.
Matrix
(listrows)[source]¶ A class to represent matrices of size
(n, m)
.M = Matrix(listrows)
will have three attributes:M.listrows
list of rows vectors (as list),M.n
orM.rows
number of rows,M.
orM.cols
number of columns (ie. length of the rows).
All the required special methods are implemented, so
Matrix
objects can be used as numbers, with a very natural syntax.Warning
All the rows should have the same size.
-
__init__
(listrows)[source]¶ Create a
Matrix
object from the list of row vectorsM
.>>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> A.listrows [[1, 2, 3], [4, 5, 6]]
-
listrows
= None¶ self.listrows is the list of rows for self
-
n
¶ Getter for the read-only attribute
A.n
(number of rows).>>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> A.n 2 >>> A.rows == A.n True
-
rows
¶ Getter for the read-only attribute
A.n
(number of rows).>>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> A.n 2 >>> A.rows == A.n True
-
m
¶ Getter for the read-only attribute
A.m
(size of the rows, ie. number of columns).>>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> A.m 3 >>> A.cols == A.m True
-
cols
¶ Getter for the read-only attribute
A.m
(size of the rows, ie. number of columns).>>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> A.m 3 >>> A.cols == A.m True
-
__getitem__
(ij)[source]¶ A[i, j]
<->A.listrows[i][j]
reads the (i, j
) element of the matrixA
.- Experimental support of slices:
A[a:b:k, j]
, orA[i, c:d:l]
orA[a:b:k, c:d:l]
. - Default values for
a
andc
is a start point of0
,b
andd
is a end point of maximum size, andk
andl
is a step of1
.
>>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> A[0, 0] 1 >>> A[0, :] [[1, 2, 3]] >>> A[-1, :] [[4, 5, 6]] >>> A[:, 0] [[1], [4]] >>> A[1:, 1:] [[5, 6]] >>> A[:, ::2] [[1, 3], [4, 6]]
- Experimental support of slices:
-
__setitem__
(ij, value)[source]¶ A[i, j] = value
: will update the(i, j)
element of the matrixA
.- Support for slice arguments:
A[a:b:k, j] = sub_row
, orA[i, c:d:l] = sub_column
orA[a:b:k, c:d:l] = submatrix
. - Default values for
a
andc
is a start point of0
,b
andd
is a end point of maximum size, andk
andl
is a step of1
.
>>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> A[0, 0] = 4; A [[4, 2, 3], [4, 5, 6]] >>> A[:, 0] [[4], [4]] >>> A[-1, :] = 9; A [[4, 2, 3], [9, 9, 9]] >>> A[1, 1] = 3; A [[4, 2, 3], [9, 3, 9]] >>> A[0, :] = [3, 2, 1]; A [[3, 2, 1], [9, 3, 9]] >>> A[1:, 1:] = -1; A [[3, 2, 1], [9, -1, -1]] >>> A[1:, 1:] *= -8; A [[3, 2, 1], [9, 8, 8]]
- Support for slice arguments:
-
row
(i)[source]¶ A.row(i)
<-> extracts thei
-th row ofA
, as a new matrix.Warning
Modifying
A.row(i)
does NOT modify the matrixA
.>>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> A.row(0) [[1, 2, 3]] >>> A.row(1) [[4, 5, 6]] >>> r = A.row(0); r *= 3 >>> A # it has not been modified! [[1, 2, 3], [4, 5, 6]]
-
col
(j)[source]¶ A.col(j)
<-> extracts thej
-th column ofA
, as a new matrix.Warning
Modifying
A.col(j)
does NOT modify the matrix A.>>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> A.col(0) [[1], [4]] >>> A.col(2) [[3], [6]] >>> c = A.col(1); c *= 6 >>> A # it has not been modified! [[1, 2, 3], [4, 5, 6]]
-
copy
()[source]¶ A.copy()
<-> a shallow copy of the matrixA
(ie. a new and fresh matrix with same values).>>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> B = A.copy() >>> A[0, 0] = -10; A [[-10, 2, 3], [4, 5, 6]] >>> B # It has not been modified! [[1, 2, 3], [4, 5, 6]]
-
__len__
()[source]¶ len(A)
returnsA.n * A.m
, the number of values in the matrix.>>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> len(A) 6 >>> len(A) == A.n * A.m True
-
shape
¶ A.shape
is(A.n, A.m)
(similar to the shape attribute of NumPy arrays).>>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> A.shape (2, 3)
-
transpose
()[source]¶ A.transpose()
is the transposition of the matrixA
.- Returns a new matrix!
- Definition: if
B = A.transpose()
, thenB[i, j] is A[j, i]
.
>>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> A.transpose() [[1, 4], [2, 5], [3, 6]] >>> A.transpose().transpose() == A True
-
T
¶ A.T
<->A.transpose()
is the transposition of the matrixA
, useful shortcut as in NumPy.>>> B = Matrix([[1, 4], [2, 5], [3, 6]]) >>> B.T [[1, 2, 3], [4, 5, 6]] >>> B == B.T.T True
-
__str__
()[source]¶ str(A)
<->A.__str__()
converts the matrixA
to a string (showing the list of rows vectors).>>> B = Matrix([[1, 4], [2, 5], [3, 6]]) >>> str(B) '[[1, 4], [2, 5], [3, 6]]'
-
__repr__
()[source]¶ repr(A)
<->A.__repr__()
converts the matrix A to a string (showing the list of rows vectors).>>> B = Matrix([[1, 4], [2, 5], [3, 6]]) >>> repr(B) '[[1, 4], [2, 5], [3, 6]]'
-
__eq__
(B)[source]¶ A == B
<->A.__eq__(B)
compares the matrixA
withB
.- Time complexity is \(\mathcal{O}(n m)\) for matrices of size
(n, m)
.
>>> B = Matrix([[1, 4], [2, 5], [3, 6]]) >>> B == B True >>> B + B + B == 3*B == B + 2*B == 2*B + B True >>> B - B + B == 1*B == -B + 2*B == 2*B - B == 2*B + (-B) True >>> B != B False
- Time complexity is \(\mathcal{O}(n m)\) for matrices of size
-
almosteq
(B, epsilon=1e-10)[source]¶ A.almosteq(B)
compares the matrixA
withB
, numerically with an error threshold ofepsilon
.- Default epsilon is \(10^{-10}\).
- Time complexity is \(\mathcal{O}(n m)\) for matrices of size
(n, m)
.
>>> B = Matrix([[1, 4], [2, 5], [3, 6]]) >>> C = B.copy(); C[0,0] += 4*1e-6 >>> B == C False >>> B.almosteq(C) False >>> B.almosteq(C, epsilon=1e-4) True >>> B.almosteq(C, epsilon=1e-5) True >>> B.almosteq(C, epsilon=1e-6) False
-
__lt__
(B)[source]¶ A < B
<-> \(A_{i,j} < B_{i,j} \forall i,j\) compares the matrixA
withB
.- Time complexity is \(\mathcal{O}(n m)\) for matrices of size
(n, m)
. - Time complexity is \(\mathcal{O}(n m)\) for matrices of size
(n, m)
. A > B
,A <= B
,A >= B
are all computed automatically with__eq__()
and__lt__()
.
>>> B = Matrix([[1, 4], [2, 5], [3, 6]]) >>> B < B False >>> B < B + 4 True >>> B > B False >>> B > B - 12 True
- Time complexity is \(\mathcal{O}(n m)\) for matrices of size
-
__add__
(B)[source]¶ A + B
<->A.__add__(B)
computes the sum of the matrixA
andB
.- Returns a new matrix!
- Time and memory complexity is \(\mathcal{O}(n m)\) for matrices of size
(n, m)
. - If
B
is a number, the sum is done coefficient wise.
>>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> A + A [[2, 4, 6], [8, 10, 12]] >>> B = ones(A.n, A.m); B [[1, 1, 1], [1, 1, 1]] >>> A + B [[2, 3, 4], [5, 6, 7]] >>> B + A [[2, 3, 4], [5, 6, 7]] >>> B + B + B + B + B + B + B [[7, 7, 7], [7, 7, 7]] >>> B + 4 # Coefficient wise! [[5, 5, 5], [5, 5, 5]] >>> B + (-2) # Coefficient wise! [[-1, -1, -1], [-1, -1, -1]] >>> B + (-1.0) # Coefficient wise! [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
-
__radd__
(B)[source]¶ B + A
<->A.__radd__(B)
computes the sum ofB
and the matrixA
.- Returns a new matrix!
- Time and memory complexity is \(\mathcal{O}(n m)\) for matrices of size
(n, m)
. - If
B
is a number, the sum is done coefficient wise.
>>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> 1 + A [[2, 3, 4], [5, 6, 7]] >>> B = ones(A.n, A.m) >>> 4 + B # Coefficient wise! [[5, 5, 5], [5, 5, 5]] >>> (-2) + B # Coefficient wise! [[-1, -1, -1], [-1, -1, -1]] >>> (-1.0) + B # Coefficient wise! [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
-
__sub__
(B)[source]¶ A - B
<->A.__sub__(B)
computes the difference of the matrixA
andB
.- Returns a new matrix!
- Time and memory complexity is \(\mathcal{O}(n m)\) for matrices of size
(n, m)
. - If
B
is a number, the sum is done coefficient wise.
>>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> B = ones(A.n, A.m) >>> A - B [[0, 1, 2], [3, 4, 5]] >>> B - A [[0, -1, -2], [-3, -4, -5]] >>> A - 1 # Coefficient wise! [[0, 1, 2], [3, 4, 5]] >>> B - 2 # Coefficient wise! [[-1, -1, -1], [-1, -1, -1]] >>> (A - 3.14).round() # Coefficient wise! [[-2.14, -1.14, -0.14], [0.86, 1.86, 2.86]]
-
__neg__
()[source]¶ -A
<->A.__neg__()
computes the opposite of the matrixA
.- Returns a new matrix!
- Time and memory complexity is \(\mathcal{O}(n m)\) for a matrix of size
(n, m)
.
>>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> -A [[-1, -2, -3], [-4, -5, -6]] >>> A - A == A + (-A) True >>> -(-A) == A True >>> -------A == -A # Crazy syntax! True >>> s = '-------' >>> len(s) % 2 == 1 # We check that we had an od number of minus symbol True
-
__pos__
()[source]¶ +
<->A.__pos__()
computes the positive of the matrix A.- Returns a new matrix!
- Useless?
- Time and memory complexity is \(\mathcal{O}(n m)\) for a matrix of size
(n, m)
.
>>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> +A == A True >>> +-+-+-+-+++----+-+-+----++++A == A # Crazy syntax, again! True >>> s = '+-+-+-+-+++----+-+-+----++++' >>> s.count('-') % 2 == 0 # We check that we had an even number of minus symbol True
-
__rsub__
(B)[source]¶ B - A
<->A.__rsub__(B)
computes the difference ofB
and the matrixA
.- Returns a new matrix!
- Time and memory complexity is \(\mathcal{O}(n m)\) for matrices of size
(n, m)
. - If
B
is a number, the sum is done coefficient wise. - If
B
is aMatrix
object,B - A
will in fact beB.__sub__(A)
and notA.__rsub__(B)
.
>>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> 1 - A # Coefficient wise! [[0, -1, -2], [-3, -4, -5]] >>> B = ones(A.n, A.m) >>> (-1) - B # Coefficient wise! [[-2, -2, -2], [-2, -2, -2]] >>> ((-1) - B) == -(1 + B) == -(B + B) True
-
__mul__
(B)[source]¶ A * B
<->A.__mul__(B)
computes the product of the matrixA
andB
.- Returns a new matrix!
- Time and memory complexity is \(\mathcal{O}(n m p)\) for a matrix
A
of size(n, m)
andB
of size(m, p)
. - If
B
is a number, the product is done coefficient wise.
Warning
Matrix product is not commutative!
>>> A = Matrix([[1, 2], [3, 4]]) >>> B = eye(A.n); B [[1, 0], [0, 1]] >>> A * B == B * A == A True >>> A * A [[7, 10], [15, 22]] >>> A * (A * A) == (A * A) * A True >>> A * 1 == A # Coefficient wise! True >>> A * 12.011993 # Coefficient wise! [[12.011993, 24.023986], [36.035979, 48.047972]]
-
__rmul__
(B)[source]¶ B * A
<->A.__rmul__(B)
computes the product ofB
and the matrixA
.- Returns a new matrix!
- Time and memory complexity is \(\mathcal{O}(n m p)\) for a matrix
A
of size(n, m)
andB
of size(m, p)
. - If B is a number, the product is done coefficient wise.
- If
B
is aMatrix
object,B * A
will in fact beB.__mul__(A)
and notA.__rmul__(B)
.
Warning
Matrix product is not commutative!
>>> A = Matrix([[1, 2], [3, 4]]) >>> 1 * A == A # Coefficient wise! True >>> 12.011993 * A # Coefficient wise! [[12.011993, 24.023986], [36.035979, 48.047972]]
-
multiply_elementwise
(B)[source]¶ A.multiply_elementwise(B)
computes the product of the matrixA
andB
, element-wise (it is called a Hadamard product).- Returns a new matrix!
- Time and memory complexity is \(\mathcal{O}(n m p)\) for a matrix
A
of size(n, m)
andB
of size(m, p)
.
>>> A = Matrix([[1, 2], [3, 4]]) >>> B = eye(A.n) >>> A.multiply_elementwise(B) [[1, 0], [0, 4]] >>> A.multiply_elementwise(A) # A .^ 2 in Matlab? [[1, 4], [9, 16]]
-
__div__
(B)[source]¶ A / B
<->A * (B ** (-1))
computes the division of the matrixA
byB
.- Returns a new matrix!
- Performs true division!
- Time and memory complexity is \(\mathcal{O}(n m p \max(m, p)^2)\) for a matrix
A
of size(n, m)
andB
of size(m, p)
. - If
B
is a number, the division is done coefficient wise.
>>> A = Matrix([[1, 2], [3, 4]]) >>> B = eye(A.n) >>> B.almosteq(A / A) True >>> C = B.map(float) >>> A / C == A * C == A True >>> A / B == A * B == A True >>> A / 2 # Coefficient wise! [[0.5, 1.0], [1.5, 2.0]] >>> A / 2.0 # Coefficient wise! [[0.5, 1.0], [1.5, 2.0]]
-
__truediv__
(B)¶ A / B
<->A * (B ** (-1))
computes the division of the matrixA
byB
.- Returns a new matrix!
- Performs true division!
- Time and memory complexity is \(\mathcal{O}(n m p \max(m, p)^2)\) for a matrix
A
of size(n, m)
andB
of size(m, p)
. - If
B
is a number, the division is done coefficient wise.
>>> A = Matrix([[1, 2], [3, 4]]) >>> B = eye(A.n) >>> B.almosteq(A / A) True >>> C = B.map(float) >>> A / C == A * C == A True >>> A / B == A * B == A True >>> A / 2 # Coefficient wise! [[0.5, 1.0], [1.5, 2.0]] >>> A / 2.0 # Coefficient wise! [[0.5, 1.0], [1.5, 2.0]]
-
__floordiv__
(B)[source]¶ A // B
<->A * (B ** (-1))
computes the division of the matrixA
byB
.- Returns a new matrix!
- Time and memory complexity is \(\mathcal{O}(n m p)\) for a matrix
A
of size(n, m)
andB
of size(m, p)
. - If
B
is a number, the division is done coefficient wise with an integer division//
.
>>> A = Matrix([[1, 2], [3, 4]]) >>> B = eye(A.n); C = B.map(float) >>> A // C == A * C == A True >>> A // B == A * B == A True >>> A // 2 # Coefficient wise! [[0, 1], [1, 2]] >>> A // 2.0 # Coefficient wise! [[0.0, 1.0], [1.0, 2.0]]
-
__mod__
(b)[source]¶ A % b
<->A.__mod__(b)
computes the modulus coefficient-wise of the matrixA
byb
.- Returns a new matrix!
- Time and memory complexity is \(\mathcal{O}(n m)\) for a matrix
A
of size(n, m)
.
>>> A = Matrix([[1, 2], [3, 4]]) >>> A % 2 [[1, 0], [1, 0]] >>> (A*100) % 31 [[7, 14], [21, 28]] >>> (A*100) % 33 == A # Curious property True >>> (A*100) % 35 [[30, 25], [20, 15]]
Warning
A % B
for two matrices means the coefficient-wise modulus.>>> A = Matrix([[1, 2], [3, 4]]) >>> B = Matrix([[2, 3], [2, 2]]) >>> A % B [[1, 2], [1, 0]]
-
__rdiv__
(B)[source]¶ B / A
<->A.__rdiv__(B)
computes the division ofB
byA
.Warning
If
B
is1
(B == 1
),1 / A
isA.inv()
(special case!)- If
B
is a number, the division is done coefficient wise. - Returns a new matrix!
- Time and memory complexity is \(\mathcal{O}(n m p)\) for a matrix
A
of size(n, m)
andB
of size(m, p)
.
>>> A = Matrix([[1, 2], [3, 4]]) >>> Ainv = Matrix([[-2.0, 1.0], [1.5, -0.5]]) >>> B = eye(A.n) >>> B == A * Ainv == Ainv * A True >>> 1 / B == B == B / 1 True >>> C = B.map(float) >>> 1 / B == B == B / 1 True >>> A.inv() == 1 / A # special case! True >>> 1 / A # This is like 1 / A [[-2.0, 1.0], [1.5, -0.5]] >>> 2 / (2*A) # Warning This is coefficient wise ! [[1.0, 0.5], [0.333333..., 0.25]]
- If
-
__rtruediv__
(B)¶ B / A
<->A.__rdiv__(B)
computes the division ofB
byA
.Warning
If
B
is1
(B == 1
),1 / A
isA.inv()
(special case!)- If
B
is a number, the division is done coefficient wise. - Returns a new matrix!
- Time and memory complexity is \(\mathcal{O}(n m p)\) for a matrix
A
of size(n, m)
andB
of size(m, p)
.
>>> A = Matrix([[1, 2], [3, 4]]) >>> Ainv = Matrix([[-2.0, 1.0], [1.5, -0.5]]) >>> B = eye(A.n) >>> B == A * Ainv == Ainv * A True >>> 1 / B == B == B / 1 True >>> C = B.map(float) >>> 1 / B == B == B / 1 True >>> A.inv() == 1 / A # special case! True >>> 1 / A # This is like 1 / A [[-2.0, 1.0], [1.5, -0.5]] >>> 2 / (2*A) # Warning This is coefficient wise ! [[1.0, 0.5], [0.333333..., 0.25]]
- If
-
__rfloordiv__
(B)[source]¶ B // A
<->A.__rdiv__(B)
computes the division ofB
byA
.Warning
If
B
is1
(B == 1
),1 / A
isA.inv()
(special case!)- If
B
is a number, the division is done coefficient wise. - Returns a new matrix!
- Time and memory complexity is \(\mathcal{O}(n m p)\) for a matrix
A
of size(n, m)
andB
of size(m, p)
.
>>> A = Matrix([[1, 2], [3, 4]]) >>> B = eye(A.n) >>> 1 // B == B == B // 1 True >>> C = B.map(float) >>> 1 // B == B == B // 1 True >>> A.inv() == 1 // A # special case! True >>> 2 // (2*A) # XXX This is coefficient wise ! [[1, 0], [0, 0]]
- If
-
__pow__
(k)[source]¶ A ** k
<->A.__pow__(k)
to compute the product of the square matrixA
(with the quick exponentation trick).- Returns a new matrix!
k
has to be an integer (ValueError
will be returned otherwise).- Time complexity is \(\mathcal{O}(n^3 \log(k))\) for a matrix
A
of size (n, n). - Memory complexity is \(\mathcal{O}(n^2)\).
- It uses
A.inv()
(inv()
) to (try to) compute the inverse ifk < 0
. - More details are in the solution for the Problem II of the 2nd Mid-Term Exam for CS101.
>>> A = Matrix([[1, 2], [3, 4]]) >>> A ** 1 == A True >>> A ** 2 [[7, 10], [15, 22]] >>> A * A == A ** 2 True >>> B = eye(A.n) >>> B == B ** 1 == A ** 0 == B ** 0 True >>> divmod(2015, 2) (1007, 1) >>> 2015 == 1007*2 + 1 True >>> A ** 2015 == ((A ** 1007) ** 2 ) * A True >>> C = diag([1, 4]) >>> C ** 100 [[1, 0], [0, 1606938044258990275541962092341162602522202993782792835301376]] >>> C ** 100 == diag([1**100, 4**100]) True
It also accept negative integers:
>>> A ** (-1) == A.inv() True >>> C = (A ** (-1)); C [[-2.0, 1.0], [1.5, -0.5]] >>> C * A == eye(A.n) == A * C True >>> C.listrows # Rounding mistakes can happen (but not here) [[-2.0, 1.0], [1.5, -0.5]] >>> D = C.round(); D.listrows [[-2.0, 1.0], [1.5, -0.5]] >>> D * A == eye(A.n) == A * D # No rounding mistake! True >>> (C * A).almosteq(eye(A.n)) True >>> (A ** (-5)) == (A ** 5).inv() == (A.inv()) ** 5 False >>> (A ** (-5)).round() == ((A ** 5).inv()).round() == ((A.inv()) ** 5).round() # No rounding mistake! True
-
exp
(limit=30)[source]¶ A.exp()
computes a numerical approximation of the exponential of the square matrixA
.- Raise a ValueError exception if
A
is not square. - Note: \(\exp(A) = \mathrm{e}^A\) is defined as the series \(\sum\limits_{k=0}^{+\infty} \frac{A^k}{k!}\).
- We only compute the first
limit
terms of this series, hopping that the partial sum will be close to the entire series. - Default value for
limit
is 30 (it should be enough for any matrix).
>>> import math >>> e = math.e >>> I = eye(10); I[0, :] [[1, 0, 0, 0, 0, 0, 0, 0, 0, 0]] >>> I * e == I.exp() == diag([e] * I.n) # Rounding mistakes! False >>> (I * e).round() == I.exp().round() == diag([e] * I.n).round() # No more rounding mistakes! True >>> C = diag([1, 4]) >>> C.exp() == diag([e ** 1, e ** 4]) == diag([math.exp(1), math.exp(4)]) # Rounding mistakes! False >>> C.exp().almosteq(diag([e ** 1, e ** 4])) # No more rounding mistakes! True >>> diag([e ** 1, e ** 4]).almosteq(diag([math.exp(1), math.exp(4)])) True
- Raise a ValueError exception if
-
inv
()[source]¶ A.inv()
computes the inverse of the square matrixA
(if possible), with the Gauss-Jordan algorithm.- Raise a
ValueError
exception ifA
is not square. - Raise a
ValueError
exception ifA
is singular.
>>> A = Matrix([[1, 2], [3, 4]]) >>> A.inv() [[-2.0, 1.0], [1.5, -0.5]] >>> A * A.inv() == A.inv() * A == eye(A.n) # Rounding mistake can happen (but not here) True >>> Ai = A.inv().round() # No more rounding mistake! >>> A * Ai == Ai * A == eye(A.n) True >>> A.det -2 >>> O = Matrix([[1, 2], [0, 0]]) # O and not 0 >>> O.is_singular True >>> O.inv() # O is singular! Traceback (most recent call last): ... ValueError: A.inv() on a singular matrix (ie. non inversible). >>> O.det 0 Traceback (most recent call last): ... ValueError: A.inv() on a singular matrix (ie. non inversible).
- Raise a
-
gauss
(det=False, verb=False, mode=None, maxpivot=False)[source]¶ A.gauss()
implements the Gauss elimination process on matrixA
.When possible, the Gauss elimination process produces a row echelon form by applying linear operations to
A
.- If
maxpivot
is True, we look for the pivot with higher absolute value (can help reducing rounding mistakes). - If
verb
is True, some details are printed at each steps of the algorithm. mode
can beNone
(default), or'f'
for fractions (Fraction
) or'd'
for decimal numbers (Decimal
).- Reference is https://en.wikipedia.org/wiki/Gaussian_elimination#Definitions_and_example_of_algorithm
- We chosed to apply rows operations only: it uses elementary operations on lines/rows: \(L_i' \longrightarrow L_i - \gamma \times L_k\) (method
swap_rows()
). - Can swap two columns in order to select the bigger pivot (increases the numerical stability).
- The function will raise a
ValueError
if the matrixA
is singular (ie. Gauss process cannot conclude). - If
det
isTrue
, the returned value isc, d
withc
the row echelon form, andd
the determinant. Reference for this part is this wikipedia page.
>>> Matrix([[1, 2], [3, 4]]).gauss() [[1, 2], [0, -2]] >>> Matrix([[1, 2], [1, 2]]).gauss() [[1, 2], [0, 0]] >>> Matrix([[1, 2], [-1, -0.5]]).gauss() [[1, 2], [0, 1.5]] >>> Matrix([[1, 2], [3, 4]]).gauss(maxpivot=True) [[2, 1], [0, 1]] >>> Matrix([[1, 2], [1, 2]]).gauss(maxpivot=True) [[2, 1], [0, 0]] >>> Matrix([[1, 2], [3, 4]]).gauss(det=True) ([[1, 2], [0, -2]], -2) >>> Matrix([[1, 2], [1, 2]]).gauss(det=True) ([[1, 2], [0, 0]], 0)
- If
-
gauss_jordan
(inv=False, verb=False, mode=None, maxpivot=False)[source]¶ A.gauss_jordan()
implements the Gauss elimination process on matrixA
.- If
inv
isTrue
, the returned value isJ_n, A**(-1)
withJ_n
the reduced row echelon form ofA
, andA**(-1)
the computed inverse of A. - If
maxpivot
isTrue
, we look for the pivot with higher absolute value (can help reducing rounding mistakes).
- If
-
rank
¶ A.rank
uses the Gauss elimination process to compute the rank of the matrixA
, by simply counting the number of non-zero elements on the diagonal of the echelon form.Todo
The Gauss process (
gauss()
) has to be changed, and improved for singular matrices (when the rank is not maximum!).>>> Matrix([[1, 2], [3, 4]]).rank 2 >>> Matrix([[1, 2], [1, 2]]).rank 1 >>> zeros(7).rank 0 >>> eye(19).rank 19
-
det
¶ A.det
uses the Gauss elimination process to compute the determinant of the matrixA
.Note
Because it depends of the number of elementary operations performed in the Gauss method, we had to modify the
gauss()
method...>>> Matrix([[1, 2], [3, 4]]).det -2 >>> Matrix([[1, 2], [1, 2]]).det 0 >>> zeros(7).det 0 >>> eye(19).det 1
-
count
(value)[source]¶ A.count(value)
counts how many times the elementvalue
is in the matrixA
.>>> Matrix([[1, 2], [3, 4]]).count(2) 1 >>> Matrix([[1, 2], [1, 2]]).count(2) 2 >>> zeros(7).count(2) 0 >>> zeros(7).count(0) 49 >>> eye(19).count(1) 19 >>> eye(19).count(0) 342
-
__contains__
(value)[source]¶ value in A
<->A.__contains__(value)
tells if the elementvalue
is present in the matrixA
.>>> 4 in Matrix([[1, 2], [3, 4]]) True >>> 4 in Matrix([[1, 2], [1, 2]]) False >>> O, I = zeros(7), eye(7) >>> 3 * I**2 + 2 * I + O ** 0 [[6, 0, 0, 0, 0, 0, 0], [0, 6, 0, 0, 0, 0, 0], [0, 0, 6, 0, 0, 0, 0], [0, 0, 0, 6, 0, 0, 0], [0, 0, 0, 0, 6, 0, 0], [0, 0, 0, 0, 0, 6, 0], [0, 0, 0, 0, 0, 0, 6]] >>> 6 in (3 * I**2 + 2 * I + O ** 0) True
-
map
(f, *args, **kwargs)[source]¶ Apply the function
f
to each of the coefficient of the matrixA
(returns a new matrix).>>> O, I = zeros(2), eye(2) >>> I.map(lambda x: x * 4) [[4, 0], [0, 4]] >>> O.map(lambda x: x + 6) [[6, 6], [6, 6]] >>> A = Matrix([[-1j, -2j], [-2j, -1j]]) >>> A.map(lambda z: abs(z)) [[1.0, 2.0], [2.0, 1.0]] >>> A.map(lambda z: int(abs(z))) [[1, 2], [2, 1]] >>> A.map(lambda z: z + 1j) [[0j, -1j], [-1j, 0j]] >>> A.map(lambda z: '"%s"' % str(z)) [["-1j", "-2j"], ["-2j", "-1j"]] >>> A.map(lambda z: "Look: %s" % str(z)) [[Look: -1j, Look: -2j], [Look: -2j, Look: -1j]]
- If
f
needs arguments or key-words arguments, use the*args
and**kwargs
:
>>> def f(x, n, offset=0): ... return (x ** n) + offset >>> A = Matrix([[1, 2], [2, 1]]) >>> A.map(f, 2) [[1, 4], [4, 1]] >>> A.map(f, 2, offset=4) [[5, 8], [8, 5]]
- If
-
round
(ndigits=8)[source]¶ A.round([ndigits=8])
<-> rounds every coefficient ofA
tondigits
digits after the comma.>>> A = (1. / 3.) * eye(2) + 4 >>> A.round(0) [[4.0, 4.0], [4.0, 4.0]] >>> A.round(2) [[4.33, 4.0], [4.0, 4.33]] >>> A.round(7) [[4.3333333, 4.0], [4.0, 4.3333333]]
-
__iter__
()[source]¶ iter(A)
<->A.__iter__()
is used to create an iterator from the matrixA
.- The values are looped rows by rows, then columns then columns.
- This method is called when an iterator is required for a container. This method should return a new iterator object that can iterate over all the objects in the container.
>>> A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) >>> list(A) [1, 2, 3, 4, 5, 6, 7, 8, 9]
-
next
()[source]¶ Generator for iterating the matrix
A
.- The values are looped rows by rows, then columns then columns.
>>> A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) >>> for x in A: ... print(x) 1 2 3 4 5 6 7 8 9 >>> for i, x in enumerate(A): ... print(i, "th value of A is", x) 0 th value of A is 1 1 th value of A is 2 2 th value of A is 3 3 th value of A is 4 4 th value of A is 5 5 th value of A is 6 6 th value of A is 7 7 th value of A is 8 8 th value of A is 9
-
real
¶ Real part of the matrix
A
, coefficient wise.>>> A = Matrix([[1j, 2j], [2j, 1j]]) >>> A.real [[0.0, 0.0], [0.0, 0.0]] >>> A = Matrix([[1+6j, 2], [-1+2j, 1+9j]]) >>> A.real [[1.0, 2], [-1.0, 1.0]]
-
imag
¶ Imaginary part of the matrix
A
, coefficient wise.>>> A = Matrix([[-1j, -2j], [-2j, -1j]]) >>> A.imag [[-1.0, -2.0], [-2.0, -1.0]]
-
conjugate
()[source]¶ Conjugate part of the matrix
A
, coefficient wise.>>> A = Matrix([[-1j, -2j], [-2j, -1j]]) >>> A.conjugate() [[1j, 2j], [2j, 1j]]
-
dot
(v)[source]¶ A.dot(v)
computes the dot multiplication of the matrixA
and the vectorv
(\(A \dot v\)).v
can be a matrix (Matrix
) of size(m, 1)
, or a list of sizem
.
>>> A = Matrix([[1, 1], [1, -1]]) >>> v = [2, 3] >>> A.dot(v) [[5], [-1]] >>> v = Matrix([[2], [-3]]) >>> A.dot(v) [[-1], [5]]
Warning
An exception
ValueError
is raised if the sizes does not allow the dot product:>>> A.dot(v.T) # v.T is not a column vector! Traceback (most recent call last): ... ValueError: A.dot(v): the vector v = [[2, -3]] is not a vector: v.m = 2 != 1. >>> v = Matrix([[2], [-3], [7]]) >>> A.dot(v) Traceback (most recent call last): ... ValueError: A.dot(v): the size of the vector v = [[2], [-3], [7]] should be compatible with the size of the matrix self = [[1, 1], [1, -1]]. Here self.m = 2 and v.n = 3, are different. >>> v = [1, 2, 3, 4, 5] >>> A.dot(v) Traceback (most recent call last): ... ValueError: A.dot(v): the size of the vector v = [[1], [2], [3], [4], [5]] should be compatible with the size of the matrix self = [[1, 1], [1, -1]]. Here self.m = 2 and v.n = 5, are different. Traceback (most recent call last): ... ValueError: A.dot(v): the size of the vector v = [[1], [2], [3], [4], [5]] should be compatible with the size of the matrix self = [[1, 1], [1, -1]]. Here self.m = 2 and v.n = 5, are different.
-
norm
(p=2)[source]¶ A.norm(p)
computes the p-norm of the matrixA
, default isp = 2
.- Mathematically defined as p-root of the sum of the p-power of modulus of its coefficients :
\[\|A\|_{p} := \left( \sum\limits_{1 \leq i \leq n, 1 \leq j \leq m} {|A_{i,j}|}^p \right)^{\frac{1}{p}}\]- If
p = 'inf'
, the max norm is returned (ie. infinity norm), defined by \(\|A\|_{\infty} := \max_{i,j} |A_{i,j}|\). - Reference is Matrix norm (on Wikipedia).
>>> A = Matrix([[1, 2], [-3, -1]]) >>> A.norm() # (1)**2 + (2)**2 + (-3)**2 + (-1)**2 3.872983346207417 >>> 15**0.5 3.872983346207417 >>> A.norm('inf') 3 >>> A.norm(1) == 7 # (1) + (2) + (3) + (1) True >>> A.norm(3) 3.332221851645953
-
normalized
(fnorm=None, *args, **kwargs)[source]¶ A.normalized()
return a new matrix, which columns vectors are normalized by using the norm2
(or the given functionfnorm
).- Will not fail if a vector has norm
0
(it is just not modified). - Reference is Orthogonalization (on Wikipedia).
- Any extra arguments
args
,kwargs
are given to the functionfnorm
.
>>> A = Matrix([[1, 2], [-3, -1]]) >>> A.normalized(p='inf') [[0.333333..., 1.0], [-1.0, -0.5]] >>> eye(5).normalized(p='inf').map(int) # normalize then round to an int [[1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1]] >>> B = -eye(5) >>> (2*B).normalized() # each vector is divided by its norm = 2 [[-1.0, 0.0, 0.0, 0.0, 0.0], [0.0, -1.0, 0.0, 0.0, 0.0], [0.0, 0.0, -1.0, 0.0, 0.0], [0.0, 0.0, 0.0, -1.0, 0.0], [0.0, 0.0, 0.0, 0.0, -1.0]] >>> B.normalized(p='inf') [[-1.0, 0.0, 0.0, 0.0, 0.0], [0.0, -1.0, 0.0, 0.0, 0.0], [0.0, 0.0, -1.0, 0.0, 0.0], [0.0, 0.0, 0.0, -1.0, 0.0], [0.0, 0.0, 0.0, 0.0, -1.0]]
It works also for a simple vector:
>>> v = Matrix([[1], [-2], [3]]) >>> v.normalized() [[0.267261...], [-0.534522...], [0.801783...]] >>> v.normalized(p=2) [[0.267261...], [-0.534522...], [0.801783...]] >>> v.normalized() * (14**0.5) [[1.0], [-2.0], [3.0]] >>> v.normalized(p=1) [[0.166666...], [-0.333333...], [0.5]] >>> v.normalized(p=1) * 6 [[1.0], [-2.0], [3.0]] >>> 6 * v.normalized(p=1) [[1.0], [-2.0], [3.0]]
- Will not fail if a vector has norm
-
__abs__
()[source]¶ abs(A)
<->A.abs()
<->A.__abs__()
computes the absolute value / modulus ofA
coefficient-wise.>>> A = Matrix([[-4, 2+2j], [0, 4j]]) >>> abs(A) [[4, 2.828427...], [0, 4.0]] >>> B = -eye(2) >>> B.abs() [[1, 0], [0, 1]]
-
abs
()¶ abs(A)
<->A.abs()
<->A.__abs__()
computes the absolute value / modulus ofA
coefficient-wise.>>> A = Matrix([[-4, 2+2j], [0, 4j]]) >>> abs(A) [[4, 2.828427...], [0, 4.0]] >>> B = -eye(2) >>> B.abs() [[1, 0], [0, 1]]
-
trace
()[source]¶ A.trace()
computes the trace ofA
:\[\mathrm{Tr}(A) := \sum\limits_{1 \leq i \leq \min(n, m)} A_{i, i}\]>>> A = Matrix([[-4, 2+2j], [0, 4j]]) >>> A.trace() (-4+4j) >>> eye(19).trace() 19 >>> zeros(20).trace() 0 >>> ones(100).trace() 100
-
is_square
¶ A.is_square
tests ifA
is square or not.>>> A = Matrix([[-4, 2+2j], [0, 4j]]) >>> A.is_square True >>> v = Matrix([[-4], [0]]) >>> v.is_square False
-
is_symetric
¶ A.is_symetric
tests ifA
is symetric or not.>>> A = Matrix([[-4, 2+2j], [0, 4j]]) >>> A.is_symetric False >>> eye(30).is_symetric True
-
is_anti_symetric
¶ A.is_anti_symetric
tests ifA
is anti-symetric or not.>>> A = Matrix([[0, 1], [-1, 0]]) >>> A.is_anti_symetric True >>> eye(30).is_anti_symetric False
-
is_diagonal
¶ A.is_diagonal
tests if A is diagonal or not.>>> eye(40).is_diagonal True >>> A = Matrix([[0, 1], [-1, 0]]) >>> A.is_diagonal False >>> A = diag(range(30)) >>> A.is_diagonal True
-
is_hermitian
¶ A.is_hermitian
tests ifA
is Hermitian or not (tests if \(A^{*} = A\), ie.conjugate(A.T) == A)
).>>> A = Matrix([[1, 2j], [-2j, 1]]) >>> A.is_hermitian True >>> eye(30).is_hermitian True >>> (1j * ones(3)).is_hermitian False
-
is_lower
¶ A.is_lower
tests ifA
is lower triangular or not.>>> A = Matrix([[8, 1], [0, 7]]) >>> A.is_lower False >>> A.T.is_lower True
-
is_upper
¶ A.is_upper
tests ifA
is upper triangular or not.>>> A = Matrix([[2, 0], [3, 4]]) >>> A.is_upper False >>> A.T.is_upper True
-
is_zero
¶ A.is_zero
tests ifA
is the zero matrix or not.>>> A = Matrix([[2, 0], [3, 4]]) >>> A.is_zero False >>> zeros(30).is_zero True >>> (0 * A).is_zero True
-
is_singular
¶ A.is_singular
tests ifA
is singular (ie. non-invertible) or not.Note
It computes the determinant by using the Gauss elimination process (
det()
).>>> A = Matrix([[2, 0], [3, 4]]) >>> A.is_singular False >>> zeros(3).is_singular True >>> (0 * A).is_singular True >>> Matrix([[2, 0], [4, 0]]).is_singular True
-
swap_cols
(j1, j2)[source]¶ A.swap_cols(j1, j2)
changes in place thej1
-th andj2
-th columns of the matrixA
.>>> A = Matrix([[2, 0], [3, 4]]); A [[2, 0], [3, 4]] >>> A.swap_cols(0, 1); A [[0, 2], [4, 3]]
-
swap_rows
(i1, i2)[source]¶ A.swap_rows(i1, i2)
changes in place thei1
-th andi2
-th rows of the matrixA
.>>> A = Matrix([[2, 0], [3, 4]]); A [[2, 0], [3, 4]] >>> A.swap_rows(0, 1); A [[3, 4], [2, 0]]
-
minor
(i, j)[source]¶ A.minor(i, j)
<->minor(A, i, j)
returns the(i, j)
minor ofA
, defined as the determinant of the submatrixA[i0, j0]
fori0 != i
andj0 != j
.- Complexities: memory is \(\mathcal{O}(n^2)\), time is \(\mathcal{O}(n^3)\) (1 determinant of size
n - 1
).
>>> A = Matrix([[1, 2], [3, 4]]) >>> A.minor(0, 0) 4 >>> A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) >>> A.minor(0, 0) # | 5 6 8 9 | = 5 * 9 - 6 * 8 = -3 -3.000000000000007 >>> A.minor(1, 0) # | 2 3 8 9 | = 2 * 9 - 3 * 8 = -6 -6
- Complexities: memory is \(\mathcal{O}(n^2)\), time is \(\mathcal{O}(n^3)\) (1 determinant of size
-
cofactor
(i, j)[source]¶ A.cofactor(i, j)
<->cofactor(A, i, j)
returns the(i, j)
cofactor ofA
, defined as the(-1)**(i + j)
times to(i, j)
minor ofA
(cf.minor()
).- Complexities: memory is \(\mathcal{O}(n^2)\), time is \(\mathcal{O}(n^3)\) (1 determinant of size
n - 1
).
>>> A = Matrix([[1, 2], [3, 4]]) >>> A.cofactor(0, 0) 4 >>> A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) >>> A.cofactor(0, 0) # (-1)**0 * | 5 6 8 9 | = 5 * 9 - 6 * 8 = -3 -3.000000000000007 >>> A.cofactor(1, 0) # (-1)**1 * | 2 3 8 9 | = -(2 * 9 - 3 * 8) = 6 6
- Complexities: memory is \(\mathcal{O}(n^2)\), time is \(\mathcal{O}(n^3)\) (1 determinant of size
-
adjugate
()[source]¶ A.adjugate()
<->adjugate(A)
returns the adjugate matrix ofA
.- Reference is https://en.wikipedia.org/wiki/Adjugate_matrix#Inverses.
- Complexities: memory is \(\mathcal{O}(n^2)\), time is \(\mathcal{O}(n^5)\) (\(n^2\) determinants of size
n - 1
). - Using the adjugate matrix for computing the inverse is a BAD method : too time-consuming ! LU or Gauss-elimination is only \(\mathcal{O}(n^3)\).
>>> A = Matrix([[2, 0], [3, 4]]) >>> A.adjugate() [[4, -3], [0, 2]] >>> A * A.adjugate() == A.det * eye(A.n) False >>> A * A.adjugate().T == A.det * eye(A.n) True
-
__weakref__
¶ list of weak references to the object (if defined)
-
matrix.
ones
(n, m=None)[source]¶ ones(n, m)
is a matrix of size(n, m)
filled with1
.>>> ones(3, 2) [[1, 1], [1, 1], [1, 1]] >>> ones(2, 3) [[1, 1, 1], [1, 1, 1]]
- It works with only one dimension, or with a tuple
(n, m)
:
>>> ones(2) [[1, 1], [1, 1]] >>> ones((2, 3)) [[1, 1, 1], [1, 1, 1]]
- It works with only one dimension, or with a tuple
-
matrix.
zeros
(n, m=None)[source]¶ zeros(n, m)
is a matrix of size(n, m)
filled with0
.>>> zeros(3, 2) [[0, 0], [0, 0], [0, 0]] >>> zeros(2, 3) [[0, 0, 0], [0, 0, 0]] >>> ones(2, 3) == zeros(2, 3) + 1 True >>> zeros(2, 3) == ones(2, 3) * 0 True
- It works with only one dimension, or with a tuple
(n, m)
:
>>> zeros(2) [[0, 0], [0, 0]] >>> zeros((2, 3)) [[0, 0, 0], [0, 0, 0]]
- It works with only one dimension, or with a tuple
-
matrix.
eye
(n)[source]¶ eye(n)
is the (square) identity matrix of size(n, n)
(1
on the diagonal,0
outside).>>> eye(2) [[1, 0], [0, 1]] >>> zeros(18) == eye(18) * 0 True >>> eye(60).is_diagonal True >>> eye(40).is_square True >>> eye(20).is_singular False >>> eye(5).det 1 >>> eye(7).trace() 7
-
matrix.
diag
(d, n=None)[source]¶ diag(d)
creates a matrix from a listd
(or iterator) of diagonal values, or withn
-times the valued
ifd
is not an iterator andn
is an integer.>>> D = diag(range(1,6)) >>> D[2, :] [[0, 0, 3, 0, 0]]
We can check the usual properties of diagonal matrices:
>>> D.trace() 15 >>> D.trace() == sum(range(1,6)) True >>> D.det 120 >>> from math import factorial >>> D.det == factorial(5) True
Other examples:
>>> diag([-1, 1]) [[-1, 0], [0, 1]] >>> diag([-4, 1]) + 3 [[-1, 3], [3, 4]]
We can also use the optional argument
n
:>>> diag(3.14, 3) [[3.14, 0, 0], [0, 3.14, 0], [0, 0, 3.14]] >>> diag([3.14]*3) # Same ! [[3.14, 0, 0], [0, 3.14, 0], [0, 0, 3.14]]
-
matrix.
mat_from_f
(f, n, m=None, *args, **kwargs)[source]¶ mat_from_f(f, n, m=None)
creates a matrix of size(n, m)
initialized with the functionf
:A[i, j] = f(i, j)
.- Default value for
m
isn
(square matrix).
Warning
f
has to accept (at least) two argumentsi, j
.>>> mat_from_f(lambda i, j: 1 if i == j else 0, 3) == eye(3) True >>> mat_from_f(lambda i, j: 1, 3) == ones(3) True >>> mat_from_f(lambda i, j: i+j, 3) [[0, 1, 2], [1, 2, 3], [2, 3, 4]] >>> mat_from_f(lambda i, j: i*j, 3) [[0, 0, 0], [0, 1, 2], [0, 2, 4]]
- Any extra arguments
args
,kwargs
are given to the functionf
.
>>> def f(i, j, e, offset=0): ... return (i * e) + offset >>> mat_from_f(f, 2, 2, 4) # n = 2, m = 2, e = 4 [[0, 0], [4, 4]] >>> mat_from_f(f, 2, 2, 4, offset=10) # n = 2, m = 2, e = 4, offset = 10 [[10, 10], [14, 14]]
- Remark: it is similar to
Array.make
(orArray.init
) in OCaml (v3.12+) orString.create
(orString.make
).
- Default value for
-
matrix.
det
(A)[source]¶ det(A)
<->A.det
computes the determinant ofA
(in \(\mathcal{O}(n^3)\)).>>> det(eye(2)) 1 >>> det((-1) * eye(4)) 1 >>> det((-1) * eye(5)) -1
-
matrix.
rank
(A)[source]¶ rank(A)
<->A.rank
computes the rank ofA
(in \(\mathcal{O}(n^3)\)).>>> rank(eye(2)) 2
-
matrix.
gauss
(A, *args, **kwargs)[source]¶ gauss(A)
<->A.gauss()
applies the Gauss elimination process onA
(in \(\mathcal{O}(n^3)\)).
-
matrix.
gauss_jordan
(A, *args, **kwargs)[source]¶ gauss_jordan(A)
<->A.gauss_jordan()
applies the Gauss-Jordan elimination process onA
(in \(\mathcal{O}(n^3)\)).
-
matrix.
inv
(A)[source]¶ inv(A)
<->A.inv()
tries to compute the inverse ofA
(in \(\mathcal{O}(n^3)\)).>>> inv(eye(2)) == eye(2) True
-
matrix.
exp
(A, *args, **kwargs)[source]¶ exp(A)
<->A.exp()
computes an approximation of the exponential ofA
(in \(\mathcal{O}(n^3 * limit)\)).>>> import math >>> e = math.exp(1.0) >>> C = diag([1, 4]) >>> exp(C) == diag([e ** 1, e ** 4]) == diag([math.exp(1), math.exp(4)]) # Rounding mistakes! False >>> exp(C).almosteq(diag([e ** 1, e ** 4])) # No more rounding mistakes! True >>> diag([e ** 1, e ** 4]).almosteq(diag([math.exp(1), math.exp(4)])) True
-
matrix.
PLUdecomposition
(A, mode=None)[source]¶ PLUdecomposition(A)
computes the permuted LU decomposition for the matrixA
.- Operates in time complexity of \(\mathcal{O}(n^3)\), memory of \(\mathcal{O}(n^2)\).
mode
can beNone
(default), or'f'
for fractions (Fractions
) or'd'
for decimal (Decimal
) numbers.- Returned
P, L, U
that satisfiesP*A = L*U
, withP
being a permutation matrix,L
a lower triangular matrix,U
an upper triangular matrix. - Will raise a
ValueError
exception ifA
is singular. - Reference is Gauss elimination (on Wikipedia).
- We chosed to apply rows operations only: it uses elementary operations on lines/rows: \(L_i' \longrightarrow L_i - \gamma \times L_k\) (method swap_rows).
- Can swap two columns in order to select the bigger pivot (increases the numerical stability).
-
matrix.
norm
(A, p=2, *args, **kwargs)[source]¶ norm(A, p)
<->A.norm(p)
computes the p-norm ofA
(default isp = 2
).
-
matrix.
rand_matrix
(n=1, m=1, k=10)[source]¶ rand_matrix(n, m, k)
generates a new random matrix of size(n, m)
with each coefficients being integers, randomly taken between-k
andk
(bound included).>>> from random import seed >>> seed(0) # We want the examples to always be the same >>> rand_matrix(2, 3) [[7, 5, -2], [-5, 0, -2]] >>> rand_matrix(3, 2, 40) [[23, -16], [-2, 7], [33, 0]] >>> rand_matrix(4, 4, 100) [[-44, 51, 24, -50], [82, 97, 62, 81], [-38, 46, 80, 37], [-6, -80, -13, 22]]
-
matrix.
rand_matrix_float
(n=1, m=1, k=10)[source]¶ rand_matrix_float(n, m, k)
generates a new random matrix of size(n, m)
with each coefficients being float numbers, randomly taken between-k
andk
(right bound excluded).>>> from random import seed >>> seed(0) # We want the examples to always be the same >>> rand_matrix_float(2, 3) [[6.8884370305, 5.15908805881, -1.58856838338], [-4.82166499414, 0.225494427372, -1.90131725099]] >>> rand_matrix_float(3, 2, 1) [[0.56759717807, -0.393374547842], [-0.0468060916953, 0.16676407891], [0.816225770391, 0.00937371163478]] >>> rand_matrix_float(4, 4, 20) [[-8.72648622401, 10.2321681663, 4.73475986701, -9.9797463455], [16.3898502387, 19.3114190415, 12.4086894399, 16.0866380176], [-7.59409722723, 9.19326993041, 15.9535315187, 7.35935727662], [-1.11429138189, -15.9719516773, -2.63312658185, 4.43547893775]]
-
matrix.
_argmax
(indexes, array)[source]¶ Compute the index
i
inindexes
such that thearray[i]
is the bigger.
-
matrix.
_prod
(iterator)[source]¶ Compute the product of the values in the iterator
iterator
. Empty product is 1.
-
matrix.
_ifnone
(a, b)[source]¶ b if (a is None), else a
.- Useful for converting a
slice
object to arange
object (slice
,range
).
- Useful for converting a
-
matrix.
_slice_to_range
(sliceobject)[source]¶ Get a
range
of indeces from aslice
object (slice
,range
).- Thanks to this answer on stackoverflow.com.
-
matrix.
innerproduct
(vx, vy)[source]¶ (Hermitian) dot product of the two vectors
vx
andvy
(sum ofconjugate(vx[i]) * vy[i]
) :\[\mathbf{x} . \mathbf{y} = \langle \mathbf{x}, \mathbf{y} \rangle := \sum_{1 \leq i \leq n} \overline{x_i} \times y_i.\]>>> vx = [1, 2, 3]; vy = [-1, 0, 4] >>> innerproduct(vx, vy) 11
Warning
The conjugate is on the first vector, as always for Hermite spaces and Hermitian inner product.
>>> vx = [1j, 2j, 3j]; vy = [-1, 0, 4] >>> (-1j) * (-1) + (-2j) * (0) + (-3j) * (4) -11j >>> innerproduct(vx, vy) -11j
-
matrix.
norm_square
(u)[source]¶ Shortcut for the square of the norm of the vector
u
:\[\| u \|^2 := \langle u, u \rangle.\]>>> u = [1, 2, 3] >>> norm_square(u) 14
- It works for imaginary valued vectors:
>>> u = [1j, -2j, 3j] >>> norm_square(u) 14.0
- And it also works for complex valued vectors:
>>> u = [1+1j, 2-2j, 3+3j] >>> norm_square(u) 28.0
-
matrix.
norm2
(u)[source]¶ Shortcut for the canonical norm of the vector
u
:>>> u = [1, 2, 3] >>> norm2(u) 3.7416573867739413
- It works for imaginary valued vectors:
>>> u = [1j, -2j, 3j] >>> norm2(u) 3.7416573867739413
- And it also works for complex valued vectors:
>>> u = [1+1j, 2-2j, 3+3j] >>> norm2(u) 5.291502622129181
-
matrix.
vect_const_multi
(vx, c)[source]¶ Multiply the vector
vx
by the constantc
(scalar, ie. real or complex).>>> vx = [1, 2, 3]; vy = [-1, 0, 4] >>> vect_const_multi(vx, 2) [2, 4, 6] >>> vect_const_multi(vy, -4) [4, 0, -16]
-
matrix.
proj
(u, v)[source]¶ Projection of the vector
v
into the vectoru
(\(\mathrm{proj}_u(v)\) as written on Wikipedia).>>> u = [1, 2, 3]; v = [-1, 0, 4] >>> proj(u, v) # 11/14 * u [0.7857142857142857, 1.5714285714285714, 2.357142857142857] >>> proj(u, v) == [(11/14) * x for x in u] True
-
matrix.
gram_schmidt
(V, normalized=False)[source]¶ Basic implementation of the Gram-Schmidt process for the column vectors of the matrix
V
, in the easy case of \(\mathbb{R}^n\) with the usual dot product.- The matrix is interpreted as a family of column vectors.
- Reference for notations, concept and proof is Gram-Schmidt process (on Wikipedia).
- If
normalized
isTrue
, the vectors are normalized before being returned.
>>> V = Matrix([[1, 2, 3], [-1, 0, 4]]) >>> gram_schmidt(V) [[1, 2, 3], [-1, 0, 4]]
-
matrix.
minor
(A, i, j)[source]¶ minor(A, i, j)
<->A.minor(i, j)
returns the(i, j)
minor ofA
, defined as the determinant of the submatrixA[i0,j0]
fori0 != i
andj0 != j
.- Complexities: memory is \(\mathcal{O}(n^2)\), time is \(\mathcal{O}(n^3)\) (1 determinant of size
n - 1
).
- Complexities: memory is \(\mathcal{O}(n^2)\), time is \(\mathcal{O}(n^3)\) (1 determinant of size
-
matrix.
cofactor
(A, i, j)[source]¶ cofactor(A, i, j)
<->A.cofactor(i, j)
returns the(i, j)
cofactor ofA
, defined as the(-1)**(i + j)
times to(i, j)
minor ofA
(cf.minor()
).- Complexities: memory is \(\mathcal{O}(n^2)\), time is \(\mathcal{O}(n^3)\) (1 determinant of size
n - 1
).
- Complexities: memory is \(\mathcal{O}(n^2)\), time is \(\mathcal{O}(n^3)\) (1 determinant of size
-
matrix.
adjugate
(A)[source]¶ adjugate(A)
<->A.adjugate()
returns the adjugate matrix ofA
.- Reference is Adjugate matrix (on Wikipedia).
- Complexities: memory is \(\mathcal{O}(n^2)\), time is \(\mathcal{O}(n^5)\) (n^2 determinants of size
n - 1
). - Using the adjugate matrix for computing the inverse is a BAD method : too time-consuming ! LU or Gauss-elimination is only \(\mathcal{O}(n^3)\).