Matrix Expressions¶
The Matrix expression module allows users to write down statements like
>>> from sympy import MatrixSymbol, Matrix
>>> X = MatrixSymbol('X', 3, 3)
>>> Y = MatrixSymbol('Y', 3, 3)
>>> (X.T*X).I*Y
X**(-1)*X.T**(-1)*Y
>>> Matrix(X)
Matrix([
[X[0, 0], X[0, 1], X[0, 2]],
[X[1, 0], X[1, 1], X[1, 2]],
[X[2, 0], X[2, 1], X[2, 2]]])
>>> (X*Y)[1, 2]
X[1, 0]*Y[0, 2] + X[1, 1]*Y[1, 2] + X[1, 2]*Y[2, 2]
where X
and Y
are MatrixSymbol
’s rather than scalar symbols.
Matrix expression derivatives are supported. The derivative of a matrix by another matrix is generally a 4-dimensional array, but if some dimensions are trivial or diagonal, the derivation algorithm will try to express the result as a matrix expression:
>>> a = MatrixSymbol("a", 3, 1)
>>> b = MatrixSymbol("b", 3, 1)
>>> (a.T*X**2*b).diff(X)
a*b.T*X.T + X.T*a*b.T
>>> X.diff(X)
PermuteDims(ArrayTensorProduct(I, I), (3)(1 2))
The last output is an array expression, as the returned symbol is 4-dimensional.
Matrix Expressions Core Reference¶
- class sympy.matrices.expressions.MatrixExpr(*args, **kwargs)[source]¶
Superclass for Matrix Expressions
MatrixExprs represent abstract matrices, linear transformations represented within a particular basis.
Examples
>>> from sympy import MatrixSymbol >>> A = MatrixSymbol('A', 3, 3) >>> y = MatrixSymbol('y', 3, 1) >>> x = (A.T*A).I * A * y
See also
- property T¶
Matrix transposition
- as_explicit()[source]¶
Returns a dense Matrix with elements represented explicitly
Returns an object of type ImmutableDenseMatrix.
Examples
>>> from sympy import Identity >>> I = Identity(3) >>> I I >>> I.as_explicit() Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]])
See also
as_mutable
returns mutable Matrix type
- as_mutable()[source]¶
Returns a dense, mutable matrix with elements represented explicitly
Examples
>>> from sympy import Identity >>> I = Identity(3) >>> I I >>> I.shape (3, 3) >>> I.as_mutable() Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]])
See also
as_explicit
returns ImmutableDenseMatrix
- equals(other)[source]¶
Test elementwise equality between matrices, potentially of different types
>>> from sympy import Identity, eye >>> Identity(3).equals(eye(3)) True
- static from_index_summation(
- expr,
- first_index=None,
- last_index=None,
- dimensions=None,
Parse expression of matrices with explicitly summed indices into a matrix expression without indices, if possible.
This transformation expressed in mathematical notation:
\(\sum_{j=0}^{N-1} A_{i,j} B_{j,k} \Longrightarrow \mathbf{A}\cdot \mathbf{B}\)
Optional parameter
first_index
: specify which free index to use as the index starting the expression.Examples
>>> from sympy import MatrixSymbol, MatrixExpr, Sum >>> from sympy.abc import i, j, k, l, N >>> A = MatrixSymbol("A", N, N) >>> B = MatrixSymbol("B", N, N) >>> expr = Sum(A[i, j]*B[j, k], (j, 0, N-1)) >>> MatrixExpr.from_index_summation(expr) A*B
Transposition is detected:
>>> expr = Sum(A[j, i]*B[j, k], (j, 0, N-1)) >>> MatrixExpr.from_index_summation(expr) A.T*B
Detect the trace:
>>> expr = Sum(A[i, i], (i, 0, N-1)) >>> MatrixExpr.from_index_summation(expr) Trace(A)
More complicated expressions:
>>> expr = Sum(A[i, j]*B[k, j]*A[l, k], (j, 0, N-1), (k, 0, N-1)) >>> MatrixExpr.from_index_summation(expr) A*B.T*A.T
- class sympy.matrices.expressions.MatrixSymbol(name, n, m)[source]¶
Symbolic representation of a Matrix object
Creates a SymPy Symbol to represent a Matrix. This matrix has a shape and can be included in Matrix Expressions
Examples
>>> from sympy import MatrixSymbol, Identity >>> A = MatrixSymbol('A', 3, 4) # A 3 by 4 Matrix >>> B = MatrixSymbol('B', 4, 3) # A 4 by 3 Matrix >>> A.shape (3, 4) >>> 2*A*B + Identity(3) I + 2*A*B
- class sympy.matrices.expressions.MatAdd(
- *args,
- evaluate=False,
- check=None,
- _sympify=True,
A Sum of Matrix Expressions
MatAdd inherits from and operates like SymPy Add
Examples
>>> from sympy import MatAdd, MatrixSymbol >>> A = MatrixSymbol('A', 5, 5) >>> B = MatrixSymbol('B', 5, 5) >>> C = MatrixSymbol('C', 5, 5) >>> MatAdd(A, B, C) A + B + C
- class sympy.matrices.expressions.MatMul(
- *args,
- evaluate=False,
- check=None,
- _sympify=True,
A product of matrix expressions
Examples
>>> from sympy import MatMul, MatrixSymbol >>> A = MatrixSymbol('A', 5, 4) >>> B = MatrixSymbol('B', 4, 3) >>> C = MatrixSymbol('C', 3, 6) >>> MatMul(A, B, C) A*B*C
- sympy.matrices.expressions.hadamard_product(*matrices)[source]¶
Return the elementwise (aka Hadamard) product of matrices.
Examples
>>> from sympy import hadamard_product, MatrixSymbol >>> A = MatrixSymbol('A', 2, 3) >>> B = MatrixSymbol('B', 2, 3) >>> hadamard_product(A) A >>> hadamard_product(A, B) HadamardProduct(A, B) >>> hadamard_product(A, B)[0, 1] A[0, 1]*B[0, 1]
- class sympy.matrices.expressions.HadamardProduct(*args, evaluate=False, check=None)[source]¶
Elementwise product of matrix expressions
Examples
Hadamard product for matrix symbols:
>>> from sympy import hadamard_product, HadamardProduct, MatrixSymbol >>> A = MatrixSymbol('A', 5, 5) >>> B = MatrixSymbol('B', 5, 5) >>> isinstance(hadamard_product(A, B), HadamardProduct) True
Notes
This is a symbolic object that simply stores its argument without evaluating it. To actually compute the product, use the function
hadamard_product()
orHadamardProduct.doit
- class sympy.matrices.expressions.HadamardPower(base, exp)[source]¶
Elementwise power of matrix expressions
- Parameters:
base : scalar or matrix
exp : scalar or matrix
Notes
There are four definitions for the hadamard power which can be used. Let’s consider \(A, B\) as \((m, n)\) matrices, and \(a, b\) as scalars.
Matrix raised to a scalar exponent:
\[\begin{split}A^{\circ b} = \begin{bmatrix} A_{0, 0}^b & A_{0, 1}^b & \cdots & A_{0, n-1}^b \\ A_{1, 0}^b & A_{1, 1}^b & \cdots & A_{1, n-1}^b \\ \vdots & \vdots & \ddots & \vdots \\ A_{m-1, 0}^b & A_{m-1, 1}^b & \cdots & A_{m-1, n-1}^b \end{bmatrix}\end{split}\]Scalar raised to a matrix exponent:
\[\begin{split}a^{\circ B} = \begin{bmatrix} a^{B_{0, 0}} & a^{B_{0, 1}} & \cdots & a^{B_{0, n-1}} \\ a^{B_{1, 0}} & a^{B_{1, 1}} & \cdots & a^{B_{1, n-1}} \\ \vdots & \vdots & \ddots & \vdots \\ a^{B_{m-1, 0}} & a^{B_{m-1, 1}} & \cdots & a^{B_{m-1, n-1}} \end{bmatrix}\end{split}\]Matrix raised to a matrix exponent:
\[\begin{split}A^{\circ B} = \begin{bmatrix} A_{0, 0}^{B_{0, 0}} & A_{0, 1}^{B_{0, 1}} & \cdots & A_{0, n-1}^{B_{0, n-1}} \\ A_{1, 0}^{B_{1, 0}} & A_{1, 1}^{B_{1, 1}} & \cdots & A_{1, n-1}^{B_{1, n-1}} \\ \vdots & \vdots & \ddots & \vdots \\ A_{m-1, 0}^{B_{m-1, 0}} & A_{m-1, 1}^{B_{m-1, 1}} & \cdots & A_{m-1, n-1}^{B_{m-1, n-1}} \end{bmatrix}\end{split}\]Scalar raised to a scalar exponent:
\[a^{\circ b} = a^b\]
- class sympy.matrices.expressions.Inverse(mat, exp=-1)[source]¶
The multiplicative inverse of a matrix expression
This is a symbolic object that simply stores its argument without evaluating it. To actually compute the inverse, use the
.inverse()
method of matrices.Examples
>>> from sympy import MatrixSymbol, Inverse >>> A = MatrixSymbol('A', 3, 3) >>> B = MatrixSymbol('B', 3, 3) >>> Inverse(A) A**(-1) >>> A.inverse() == Inverse(A) True >>> (A*B).inverse() B**(-1)*A**(-1) >>> Inverse(A*B) (A*B)**(-1)
- class sympy.matrices.expressions.Transpose(*args, **kwargs)[source]¶
The transpose of a matrix expression.
This is a symbolic object that simply stores its argument without evaluating it. To actually compute the transpose, use the
transpose()
function, or the.T
attribute of matrices.Examples
>>> from sympy import MatrixSymbol, Transpose, transpose >>> A = MatrixSymbol('A', 3, 5) >>> B = MatrixSymbol('B', 5, 3) >>> Transpose(A) A.T >>> A.T == transpose(A) == Transpose(A) True >>> Transpose(A*B) (A*B).T >>> transpose(A*B) B.T*A.T
- class sympy.matrices.expressions.Trace(mat)[source]¶
Matrix Trace
Represents the trace of a matrix expression.
Examples
>>> from sympy import MatrixSymbol, Trace, eye >>> A = MatrixSymbol('A', 3, 3) >>> Trace(A) Trace(A) >>> Trace(eye(3)) Trace(Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]])) >>> Trace(eye(3)).simplify() 3
- class sympy.matrices.expressions.FunctionMatrix(rows, cols, lamda)[source]¶
Represents a matrix using a function (
Lambda
) which gives outputs according to the coordinates of each matrix entries.- Parameters:
rows : nonnegative integer. Can be symbolic.
cols : nonnegative integer. Can be symbolic.
lamda : Function, Lambda or str
If it is a SymPy
Function
orLambda
instance, it should be able to accept two arguments which represents the matrix coordinates.If it is a pure string containing Python
lambda
semantics, it is interpreted by the SymPy parser and casted into a SymPyLambda
instance.
Examples
Creating a
FunctionMatrix
fromLambda
:>>> from sympy import FunctionMatrix, symbols, Lambda, MatPow >>> i, j, n, m = symbols('i,j,n,m') >>> FunctionMatrix(n, m, Lambda((i, j), i + j)) FunctionMatrix(n, m, Lambda((i, j), i + j))
Creating a
FunctionMatrix
from a SymPy function:>>> from sympy import KroneckerDelta >>> X = FunctionMatrix(3, 3, KroneckerDelta) >>> X.as_explicit() Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]])
Creating a
FunctionMatrix
from a SymPy undefined function:>>> from sympy import Function >>> f = Function('f') >>> X = FunctionMatrix(3, 3, f) >>> X.as_explicit() Matrix([ [f(0, 0), f(0, 1), f(0, 2)], [f(1, 0), f(1, 1), f(1, 2)], [f(2, 0), f(2, 1), f(2, 2)]])
Creating a
FunctionMatrix
from Pythonlambda
:>>> FunctionMatrix(n, m, 'lambda i, j: i + j') FunctionMatrix(n, m, Lambda((i, j), i + j))
Example of lazy evaluation of matrix product:
>>> Y = FunctionMatrix(1000, 1000, Lambda((i, j), i + j)) >>> isinstance(Y*Y, MatPow) # this is an expression object True >>> (Y**2)[10,10] # So this is evaluated lazily 342923500
Notes
This class provides an alternative way to represent an extremely dense matrix with entries in some form of a sequence, in a most sparse way.
- class sympy.matrices.expressions.PermutationMatrix(perm)[source]¶
A Permutation Matrix
- Parameters:
perm : Permutation
The permutation the matrix uses.
The size of the permutation determines the matrix size.
See the documentation of
sympy.combinatorics.permutations.Permutation
for the further information of how to create a permutation object.
Examples
>>> from sympy import Matrix, PermutationMatrix >>> from sympy.combinatorics import Permutation
Creating a permutation matrix:
>>> p = Permutation(1, 2, 0) >>> P = PermutationMatrix(p) >>> P = P.as_explicit() >>> P Matrix([ [0, 1, 0], [0, 0, 1], [1, 0, 0]])
Permuting a matrix row and column:
>>> M = Matrix([0, 1, 2]) >>> Matrix(P*M) Matrix([ [1], [2], [0]])
>>> Matrix(M.T*P) Matrix([[2, 0, 1]])
- class sympy.matrices.expressions.MatrixPermute(mat, perm, axis=0)[source]¶
Symbolic representation for permuting matrix rows or columns.
- Parameters:
perm : Permutation, PermutationMatrix
The permutation to use for permuting the matrix. The permutation can be resized to the suitable one,
axis : 0 or 1
The axis to permute alongside. If \(0\), it will permute the matrix rows. If \(1\), it will permute the matrix columns.
Notes
This follows the same notation used in
sympy.matrices.matrixbase.MatrixBase.permute()
.Examples
>>> from sympy import Matrix, MatrixPermute >>> from sympy.combinatorics import Permutation
Permuting the matrix rows:
>>> p = Permutation(1, 2, 0) >>> A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) >>> B = MatrixPermute(A, p, axis=0) >>> B.as_explicit() Matrix([ [4, 5, 6], [7, 8, 9], [1, 2, 3]])
Permuting the matrix columns:
>>> B = MatrixPermute(A, p, axis=1) >>> B.as_explicit() Matrix([ [2, 3, 1], [5, 6, 4], [8, 9, 7]])
- class sympy.matrices.expressions.Identity(n)[source]¶
The Matrix Identity I - multiplicative identity
Examples
>>> from sympy import Identity, MatrixSymbol >>> A = MatrixSymbol('A', 3, 5) >>> I = Identity(3) >>> I*A A
- class sympy.matrices.expressions.ZeroMatrix(m, n)[source]¶
The Matrix Zero 0 - additive identity
Examples
>>> from sympy import MatrixSymbol, ZeroMatrix >>> A = MatrixSymbol('A', 3, 5) >>> Z = ZeroMatrix(3, 5) >>> A + Z A >>> Z*A.T 0
- class sympy.matrices.expressions.CompanionMatrix(poly)[source]¶
A symbolic companion matrix of a polynomial.
Examples
>>> from sympy import Poly, Symbol, symbols >>> from sympy.matrices.expressions import CompanionMatrix >>> x = Symbol('x') >>> c0, c1, c2, c3, c4 = symbols('c0:5') >>> p = Poly(c0 + c1*x + c2*x**2 + c3*x**3 + c4*x**4 + x**5, x) >>> CompanionMatrix(p) CompanionMatrix(Poly(x**5 + c4*x**4 + c3*x**3 + c2*x**2 + c1*x + c0, x, domain='ZZ[c0,c1,c2,c3,c4]'))
- class sympy.matrices.expressions.MatrixSet(n, m, set)[source]¶
MatrixSet represents the set of matrices with
shape = (n, m)
over the given set.Examples
>>> from sympy.matrices import MatrixSet >>> from sympy import S, I, Matrix >>> M = MatrixSet(2, 2, set=S.Reals) >>> X = Matrix([[1, 2], [3, 4]]) >>> X in M True >>> X = Matrix([[1, 2], [I, 4]]) >>> X in M False
Block Matrices¶
Block matrices allow you to construct larger matrices out of smaller
sub-blocks. They can work with MatrixExpr
or
ImmutableMatrix
objects.
- class sympy.matrices.expressions.blockmatrix.BlockMatrix(*args, **kwargs)[source]¶
A BlockMatrix is a Matrix comprised of other matrices.
The submatrices are stored in a SymPy Matrix object but accessed as part of a Matrix Expression
>>> from sympy import (MatrixSymbol, BlockMatrix, symbols, ... Identity, ZeroMatrix, block_collapse) >>> n,m,l = symbols('n m l') >>> X = MatrixSymbol('X', n, n) >>> Y = MatrixSymbol('Y', m, m) >>> Z = MatrixSymbol('Z', n, m) >>> B = BlockMatrix([[X, Z], [ZeroMatrix(m,n), Y]]) >>> print(B) Matrix([ [X, Z], [0, Y]])
>>> C = BlockMatrix([[Identity(n), Z]]) >>> print(C) Matrix([[I, Z]])
>>> print(block_collapse(C*B)) Matrix([[X, Z + Z*Y]])
Some matrices might be comprised of rows of blocks with the matrices in each row having the same height and the rows all having the same total number of columns but not having the same number of columns for each matrix in each row. In this case, the matrix is not a block matrix and should be instantiated by Matrix.
>>> from sympy import ones, Matrix >>> dat = [ ... [ones(3,2), ones(3,3)*2], ... [ones(2,3)*3, ones(2,2)*4]] ... >>> BlockMatrix(dat) Traceback (most recent call last): ... ValueError: Although this matrix is comprised of blocks, the blocks do not fill the matrix in a size-symmetric fashion. To create a full matrix from these arguments, pass them directly to Matrix. >>> Matrix(dat) Matrix([ [1, 1, 2, 2, 2], [1, 1, 2, 2, 2], [1, 1, 2, 2, 2], [3, 3, 3, 4, 4], [3, 3, 3, 4, 4]])
- LDUdecomposition()[source]¶
Returns the Block LDU decomposition of a 2x2 Block Matrix
- Returns:
(L, D, U) : Matrices
L : Lower Diagonal Matrix D : Diagonal Matrix U : Upper Diagonal Matrix
- Raises:
ShapeError
If the block matrix is not a 2x2 matrix
NonInvertibleMatrixError
If the matrix “A” is non-invertible
Examples
>>> from sympy import symbols, MatrixSymbol, BlockMatrix, block_collapse >>> m, n = symbols('m n') >>> A = MatrixSymbol('A', n, n) >>> B = MatrixSymbol('B', n, m) >>> C = MatrixSymbol('C', m, n) >>> D = MatrixSymbol('D', m, m) >>> X = BlockMatrix([[A, B], [C, D]]) >>> L, D, U = X.LDUdecomposition() >>> block_collapse(L*D*U) Matrix([ [A, B], [C, D]])
- LUdecomposition()[source]¶
Returns the Block LU decomposition of a 2x2 Block Matrix
- Returns:
(L, U) : Matrices
L : Lower Diagonal Matrix U : Upper Diagonal Matrix
- Raises:
ShapeError
If the block matrix is not a 2x2 matrix
NonInvertibleMatrixError
If the matrix “A” is non-invertible
Examples
>>> from sympy import symbols, MatrixSymbol, BlockMatrix, block_collapse >>> m, n = symbols('m n') >>> A = MatrixSymbol('A', n, n) >>> B = MatrixSymbol('B', n, m) >>> C = MatrixSymbol('C', m, n) >>> D = MatrixSymbol('D', m, m) >>> X = BlockMatrix([[A, B], [C, D]]) >>> L, U = X.LUdecomposition() >>> block_collapse(L*U) Matrix([ [A, B], [C, D]])
- UDLdecomposition()[source]¶
Returns the Block UDL decomposition of a 2x2 Block Matrix
- Returns:
(U, D, L) : Matrices
U : Upper Diagonal Matrix D : Diagonal Matrix L : Lower Diagonal Matrix
- Raises:
ShapeError
If the block matrix is not a 2x2 matrix
NonInvertibleMatrixError
If the matrix “D” is non-invertible
Examples
>>> from sympy import symbols, MatrixSymbol, BlockMatrix, block_collapse >>> m, n = symbols('m n') >>> A = MatrixSymbol('A', n, n) >>> B = MatrixSymbol('B', n, m) >>> C = MatrixSymbol('C', m, n) >>> D = MatrixSymbol('D', m, m) >>> X = BlockMatrix([[A, B], [C, D]]) >>> U, D, L = X.UDLdecomposition() >>> block_collapse(U*D*L) Matrix([ [A, B], [C, D]])
- schur(mat='A', generalized=False)[source]¶
Return the Schur Complement of the 2x2 BlockMatrix
- Parameters:
mat : String, optional
The matrix with respect to which the Schur Complement is calculated. ‘A’ is used by default
generalized : bool, optional
If True, returns the generalized Schur Component which uses Moore-Penrose Inverse
- Returns:
M : Matrix
The Schur Complement Matrix
- Raises:
ShapeError
If the block matrix is not a 2x2 matrix
NonInvertibleMatrixError
If given matrix is non-invertible
Examples
>>> from sympy import symbols, MatrixSymbol, BlockMatrix >>> m, n = symbols('m n') >>> A = MatrixSymbol('A', n, n) >>> B = MatrixSymbol('B', n, m) >>> C = MatrixSymbol('C', m, n) >>> D = MatrixSymbol('D', m, m) >>> X = BlockMatrix([[A, B], [C, D]])
The default Schur Complement is evaluated with “A”
>>> X.schur() -C*A**(-1)*B + D >>> X.schur('D') A - B*D**(-1)*C
Schur complement with non-invertible matrices is not defined. Instead, the generalized Schur complement can be calculated which uses the Moore-Penrose Inverse. To achieve this, \(generalized\) must be set to \(True\)
>>> X.schur('B', generalized=True) C - D*(B.T*B)**(-1)*B.T*A >>> X.schur('C', generalized=True) -A*(C.T*C)**(-1)*C.T*D + B
References
[R608]Wikipedia Article on Schur Component : https://en.wikipedia.org/wiki/Schur_complement
- transpose()[source]¶
Return transpose of matrix.
Examples
>>> from sympy import MatrixSymbol, BlockMatrix, ZeroMatrix >>> from sympy.abc import m, n >>> X = MatrixSymbol('X', n, n) >>> Y = MatrixSymbol('Y', m, m) >>> Z = MatrixSymbol('Z', n, m) >>> B = BlockMatrix([[X, Z], [ZeroMatrix(m,n), Y]]) >>> B.transpose() Matrix([ [X.T, 0], [Z.T, Y.T]]) >>> _.transpose() Matrix([ [X, Z], [0, Y]])
- class sympy.matrices.expressions.blockmatrix.BlockDiagMatrix(*mats)[source]¶
A sparse matrix with block matrices along its diagonals
Examples
>>> from sympy import MatrixSymbol, BlockDiagMatrix, symbols >>> n, m, l = symbols('n m l') >>> X = MatrixSymbol('X', n, n) >>> Y = MatrixSymbol('Y', m, m) >>> BlockDiagMatrix(X, Y) Matrix([ [X, 0], [0, Y]])
Notes
If you want to get the individual diagonal blocks, use
get_diag_blocks()
.See also
- get_diag_blocks()[source]¶
Return the list of diagonal blocks of the matrix.
Examples
>>> from sympy import BlockDiagMatrix, Matrix
>>> A = Matrix([[1, 2], [3, 4]]) >>> B = Matrix([[5, 6], [7, 8]]) >>> M = BlockDiagMatrix(A, B)
How to get diagonal blocks from the block diagonal matrix:
>>> diag_blocks = M.get_diag_blocks() >>> diag_blocks[0] Matrix([ [1, 2], [3, 4]]) >>> diag_blocks[1] Matrix([ [5, 6], [7, 8]])
- sympy.matrices.expressions.blockmatrix.block_collapse(expr)[source]¶
Evaluates a block matrix expression
>>> from sympy import MatrixSymbol, BlockMatrix, symbols, Identity, ZeroMatrix, block_collapse >>> n,m,l = symbols('n m l') >>> X = MatrixSymbol('X', n, n) >>> Y = MatrixSymbol('Y', m, m) >>> Z = MatrixSymbol('Z', n, m) >>> B = BlockMatrix([[X, Z], [ZeroMatrix(m, n), Y]]) >>> print(B) Matrix([ [X, Z], [0, Y]])
>>> C = BlockMatrix([[Identity(n), Z]]) >>> print(C) Matrix([[I, Z]])
>>> print(block_collapse(C*B)) Matrix([[X, Z + Z*Y]])