Initialisation du repository de Beta
This commit is contained in:
commit
14985f6dbb
9469 changed files with 1903273 additions and 0 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,34 @@
|
|||
from sympy.core import symbols, S
|
||||
from sympy.functions import adjoint, conjugate, transpose
|
||||
from sympy.matrices.expressions import MatrixSymbol, Adjoint, trace, Transpose
|
||||
from sympy.matrices import eye, Matrix
|
||||
|
||||
n, m, l, k, p = symbols('n m l k p', integer=True)
|
||||
A = MatrixSymbol('A', n, m)
|
||||
B = MatrixSymbol('B', m, l)
|
||||
C = MatrixSymbol('C', n, n)
|
||||
|
||||
|
||||
def test_adjoint():
|
||||
Sq = MatrixSymbol('Sq', n, n)
|
||||
|
||||
assert Adjoint(A).shape == (m, n)
|
||||
assert Adjoint(A*B).shape == (l, n)
|
||||
assert adjoint(Adjoint(A)) == A
|
||||
assert isinstance(Adjoint(Adjoint(A)), Adjoint)
|
||||
|
||||
assert conjugate(Adjoint(A)) == Transpose(A)
|
||||
assert transpose(Adjoint(A)) == Adjoint(Transpose(A))
|
||||
|
||||
assert Adjoint(eye(3)).doit() == eye(3)
|
||||
|
||||
assert Adjoint(S(5)).doit() == S(5)
|
||||
|
||||
assert Adjoint(Matrix([[1, 2], [3, 4]])).doit() == Matrix([[1, 3], [2, 4]])
|
||||
|
||||
assert adjoint(trace(Sq)) == conjugate(trace(Sq))
|
||||
assert trace(adjoint(Sq)) == conjugate(trace(Sq))
|
||||
|
||||
assert Adjoint(Sq)[0, 1] == conjugate(Sq[1, 0])
|
||||
|
||||
assert Adjoint(A*B).doit() == Adjoint(B) * Adjoint(A)
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
from sympy.core.symbol import symbols, Dummy
|
||||
from sympy.matrices.expressions.applyfunc import ElementwiseApplyFunction
|
||||
from sympy.core.function import Lambda
|
||||
from sympy.functions.elementary.exponential import exp
|
||||
from sympy.functions.elementary.trigonometric import sin
|
||||
from sympy.matrices.dense import Matrix
|
||||
from sympy.matrices.expressions.matexpr import MatrixSymbol
|
||||
from sympy.matrices.expressions.matmul import MatMul
|
||||
from sympy.simplify.simplify import simplify
|
||||
|
||||
|
||||
X = MatrixSymbol("X", 3, 3)
|
||||
Y = MatrixSymbol("Y", 3, 3)
|
||||
|
||||
k = symbols("k")
|
||||
Xk = MatrixSymbol("X", k, k)
|
||||
|
||||
Xd = X.as_explicit()
|
||||
|
||||
x, y, z, t = symbols("x y z t")
|
||||
|
||||
|
||||
def test_applyfunc_matrix():
|
||||
x = Dummy('x')
|
||||
double = Lambda(x, x**2)
|
||||
|
||||
expr = ElementwiseApplyFunction(double, Xd)
|
||||
assert isinstance(expr, ElementwiseApplyFunction)
|
||||
assert expr.doit() == Xd.applyfunc(lambda x: x**2)
|
||||
assert expr.shape == (3, 3)
|
||||
assert expr.func(*expr.args) == expr
|
||||
assert simplify(expr) == expr
|
||||
assert expr[0, 0] == double(Xd[0, 0])
|
||||
|
||||
expr = ElementwiseApplyFunction(double, X)
|
||||
assert isinstance(expr, ElementwiseApplyFunction)
|
||||
assert isinstance(expr.doit(), ElementwiseApplyFunction)
|
||||
assert expr == X.applyfunc(double)
|
||||
assert expr.func(*expr.args) == expr
|
||||
|
||||
expr = ElementwiseApplyFunction(exp, X*Y)
|
||||
assert expr.expr == X*Y
|
||||
assert expr.function.dummy_eq(Lambda(x, exp(x)))
|
||||
assert expr.dummy_eq((X*Y).applyfunc(exp))
|
||||
assert expr.func(*expr.args) == expr
|
||||
|
||||
assert isinstance(X*expr, MatMul)
|
||||
assert (X*expr).shape == (3, 3)
|
||||
Z = MatrixSymbol("Z", 2, 3)
|
||||
assert (Z*expr).shape == (2, 3)
|
||||
|
||||
expr = ElementwiseApplyFunction(exp, Z.T)*ElementwiseApplyFunction(exp, Z)
|
||||
assert expr.shape == (3, 3)
|
||||
expr = ElementwiseApplyFunction(exp, Z)*ElementwiseApplyFunction(exp, Z.T)
|
||||
assert expr.shape == (2, 2)
|
||||
|
||||
M = Matrix([[x, y], [z, t]])
|
||||
expr = ElementwiseApplyFunction(sin, M)
|
||||
assert isinstance(expr, ElementwiseApplyFunction)
|
||||
assert expr.function.dummy_eq(Lambda(x, sin(x)))
|
||||
assert expr.expr == M
|
||||
assert expr.doit() == M.applyfunc(sin)
|
||||
assert expr.doit() == Matrix([[sin(x), sin(y)], [sin(z), sin(t)]])
|
||||
assert expr.func(*expr.args) == expr
|
||||
|
||||
expr = ElementwiseApplyFunction(double, Xk)
|
||||
assert expr.doit() == expr
|
||||
assert expr.subs(k, 2).shape == (2, 2)
|
||||
assert (expr*expr).shape == (k, k)
|
||||
M = MatrixSymbol("M", k, t)
|
||||
expr2 = M.T*expr*M
|
||||
assert isinstance(expr2, MatMul)
|
||||
assert expr2.args[1] == expr
|
||||
assert expr2.shape == (t, t)
|
||||
expr3 = expr*M
|
||||
assert expr3.shape == (k, t)
|
||||
|
||||
expr1 = ElementwiseApplyFunction(lambda x: x+1, Xk)
|
||||
expr2 = ElementwiseApplyFunction(lambda x: x, Xk)
|
||||
assert expr1 != expr2
|
||||
|
||||
|
||||
def test_applyfunc_entry():
|
||||
|
||||
af = X.applyfunc(sin)
|
||||
assert af[0, 0] == sin(X[0, 0])
|
||||
|
||||
af = Xd.applyfunc(sin)
|
||||
assert af[0, 0] == sin(X[0, 0])
|
||||
|
||||
|
||||
def test_applyfunc_as_explicit():
|
||||
|
||||
af = X.applyfunc(sin)
|
||||
assert af.as_explicit() == Matrix([
|
||||
[sin(X[0, 0]), sin(X[0, 1]), sin(X[0, 2])],
|
||||
[sin(X[1, 0]), sin(X[1, 1]), sin(X[1, 2])],
|
||||
[sin(X[2, 0]), sin(X[2, 1]), sin(X[2, 2])],
|
||||
])
|
||||
|
||||
|
||||
def test_applyfunc_transpose():
|
||||
|
||||
af = Xk.applyfunc(sin)
|
||||
assert af.T.dummy_eq(Xk.T.applyfunc(sin))
|
||||
|
||||
|
||||
def test_applyfunc_shape_11_matrices():
|
||||
M = MatrixSymbol("M", 1, 1)
|
||||
|
||||
double = Lambda(x, x*2)
|
||||
|
||||
expr = M.applyfunc(sin)
|
||||
assert isinstance(expr, ElementwiseApplyFunction)
|
||||
|
||||
expr = M.applyfunc(double)
|
||||
assert isinstance(expr, MatMul)
|
||||
assert expr == 2*M
|
||||
|
|
@ -0,0 +1,469 @@
|
|||
from sympy.matrices.expressions.trace import Trace
|
||||
from sympy.testing.pytest import raises, slow
|
||||
from sympy.matrices.expressions.blockmatrix import (
|
||||
block_collapse, bc_matmul, bc_block_plus_ident, BlockDiagMatrix,
|
||||
BlockMatrix, bc_dist, bc_matadd, bc_transpose, bc_inverse,
|
||||
blockcut, reblock_2x2, deblock)
|
||||
from sympy.matrices.expressions import (
|
||||
MatrixSymbol, Identity, trace, det, ZeroMatrix, OneMatrix)
|
||||
from sympy.matrices.expressions.inverse import Inverse
|
||||
from sympy.matrices.expressions.matpow import MatPow
|
||||
from sympy.matrices.expressions.transpose import Transpose
|
||||
from sympy.matrices.exceptions import NonInvertibleMatrixError
|
||||
from sympy.matrices import (
|
||||
Matrix, ImmutableMatrix, ImmutableSparseMatrix, zeros)
|
||||
from sympy.core import Tuple, Expr, S, Function
|
||||
from sympy.core.symbol import Symbol, symbols
|
||||
from sympy.functions import transpose, im, re
|
||||
|
||||
i, j, k, l, m, n, p = symbols('i:n, p', integer=True)
|
||||
A = MatrixSymbol('A', n, n)
|
||||
B = MatrixSymbol('B', n, n)
|
||||
C = MatrixSymbol('C', n, n)
|
||||
D = MatrixSymbol('D', n, n)
|
||||
G = MatrixSymbol('G', n, n)
|
||||
H = MatrixSymbol('H', n, n)
|
||||
b1 = BlockMatrix([[G, H]])
|
||||
b2 = BlockMatrix([[G], [H]])
|
||||
|
||||
def test_bc_matmul():
|
||||
assert bc_matmul(H*b1*b2*G) == BlockMatrix([[(H*G*G + H*H*H)*G]])
|
||||
|
||||
def test_bc_matadd():
|
||||
assert bc_matadd(BlockMatrix([[G, H]]) + BlockMatrix([[H, H]])) == \
|
||||
BlockMatrix([[G+H, H+H]])
|
||||
|
||||
def test_bc_transpose():
|
||||
assert bc_transpose(Transpose(BlockMatrix([[A, B], [C, D]]))) == \
|
||||
BlockMatrix([[A.T, C.T], [B.T, D.T]])
|
||||
|
||||
def test_bc_dist_diag():
|
||||
A = MatrixSymbol('A', n, n)
|
||||
B = MatrixSymbol('B', m, m)
|
||||
C = MatrixSymbol('C', l, l)
|
||||
X = BlockDiagMatrix(A, B, C)
|
||||
|
||||
assert bc_dist(X+X).equals(BlockDiagMatrix(2*A, 2*B, 2*C))
|
||||
|
||||
def test_block_plus_ident():
|
||||
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]])
|
||||
Z = MatrixSymbol('Z', n + m, n + m)
|
||||
assert bc_block_plus_ident(X + Identity(m + n) + Z) == \
|
||||
BlockDiagMatrix(Identity(n), Identity(m)) + X + Z
|
||||
|
||||
def test_BlockMatrix():
|
||||
A = MatrixSymbol('A', n, m)
|
||||
B = MatrixSymbol('B', n, k)
|
||||
C = MatrixSymbol('C', l, m)
|
||||
D = MatrixSymbol('D', l, k)
|
||||
M = MatrixSymbol('M', m + k, p)
|
||||
N = MatrixSymbol('N', l + n, k + m)
|
||||
X = BlockMatrix(Matrix([[A, B], [C, D]]))
|
||||
|
||||
assert X.__class__(*X.args) == X
|
||||
|
||||
# block_collapse does nothing on normal inputs
|
||||
E = MatrixSymbol('E', n, m)
|
||||
assert block_collapse(A + 2*E) == A + 2*E
|
||||
F = MatrixSymbol('F', m, m)
|
||||
assert block_collapse(E.T*A*F) == E.T*A*F
|
||||
|
||||
assert X.shape == (l + n, k + m)
|
||||
assert X.blockshape == (2, 2)
|
||||
assert transpose(X) == BlockMatrix(Matrix([[A.T, C.T], [B.T, D.T]]))
|
||||
assert transpose(X).shape == X.shape[::-1]
|
||||
|
||||
# Test that BlockMatrices and MatrixSymbols can still mix
|
||||
assert (X*M).is_MatMul
|
||||
assert X._blockmul(M).is_MatMul
|
||||
assert (X*M).shape == (n + l, p)
|
||||
assert (X + N).is_MatAdd
|
||||
assert X._blockadd(N).is_MatAdd
|
||||
assert (X + N).shape == X.shape
|
||||
|
||||
E = MatrixSymbol('E', m, 1)
|
||||
F = MatrixSymbol('F', k, 1)
|
||||
|
||||
Y = BlockMatrix(Matrix([[E], [F]]))
|
||||
|
||||
assert (X*Y).shape == (l + n, 1)
|
||||
assert block_collapse(X*Y).blocks[0, 0] == A*E + B*F
|
||||
assert block_collapse(X*Y).blocks[1, 0] == C*E + D*F
|
||||
|
||||
# block_collapse passes down into container objects, transposes, and inverse
|
||||
assert block_collapse(transpose(X*Y)) == transpose(block_collapse(X*Y))
|
||||
assert block_collapse(Tuple(X*Y, 2*X)) == (
|
||||
block_collapse(X*Y), block_collapse(2*X))
|
||||
|
||||
# Make sure that MatrixSymbols will enter 1x1 BlockMatrix if it simplifies
|
||||
Ab = BlockMatrix([[A]])
|
||||
Z = MatrixSymbol('Z', *A.shape)
|
||||
assert block_collapse(Ab + Z) == A + Z
|
||||
|
||||
def test_block_collapse_explicit_matrices():
|
||||
A = Matrix([[1, 2], [3, 4]])
|
||||
assert block_collapse(BlockMatrix([[A]])) == A
|
||||
|
||||
A = ImmutableSparseMatrix([[1, 2], [3, 4]])
|
||||
assert block_collapse(BlockMatrix([[A]])) == A
|
||||
|
||||
def test_issue_17624():
|
||||
a = MatrixSymbol("a", 2, 2)
|
||||
z = ZeroMatrix(2, 2)
|
||||
b = BlockMatrix([[a, z], [z, z]])
|
||||
assert block_collapse(b * b) == BlockMatrix([[a**2, z], [z, z]])
|
||||
assert block_collapse(b * b * b) == BlockMatrix([[a**3, z], [z, z]])
|
||||
|
||||
def test_issue_18618():
|
||||
A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
|
||||
assert A == Matrix(BlockDiagMatrix(A))
|
||||
|
||||
def test_BlockMatrix_trace():
|
||||
A, B, C, D = [MatrixSymbol(s, 3, 3) for s in 'ABCD']
|
||||
X = BlockMatrix([[A, B], [C, D]])
|
||||
assert trace(X) == trace(A) + trace(D)
|
||||
assert trace(BlockMatrix([ZeroMatrix(n, n)])) == 0
|
||||
|
||||
def test_BlockMatrix_Determinant():
|
||||
A, B, C, D = [MatrixSymbol(s, 3, 3) for s in 'ABCD']
|
||||
X = BlockMatrix([[A, B], [C, D]])
|
||||
from sympy.assumptions.ask import Q
|
||||
from sympy.assumptions.assume import assuming
|
||||
with assuming(Q.invertible(A)):
|
||||
assert det(X) == det(A) * det(X.schur('A'))
|
||||
|
||||
assert isinstance(det(X), Expr)
|
||||
assert det(BlockMatrix([A])) == det(A)
|
||||
assert det(BlockMatrix([ZeroMatrix(n, n)])) == 0
|
||||
|
||||
def test_squareBlockMatrix():
|
||||
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]])
|
||||
Y = BlockMatrix([[A]])
|
||||
|
||||
assert X.is_square
|
||||
|
||||
Q = X + Identity(m + n)
|
||||
assert (block_collapse(Q) ==
|
||||
BlockMatrix([[A + Identity(n), B], [C, D + Identity(m)]]))
|
||||
|
||||
assert (X + MatrixSymbol('Q', n + m, n + m)).is_MatAdd
|
||||
assert (X * MatrixSymbol('Q', n + m, n + m)).is_MatMul
|
||||
|
||||
assert block_collapse(Y.I) == A.I
|
||||
|
||||
assert isinstance(X.inverse(), Inverse)
|
||||
|
||||
assert not X.is_Identity
|
||||
|
||||
Z = BlockMatrix([[Identity(n), B], [C, D]])
|
||||
assert not Z.is_Identity
|
||||
|
||||
|
||||
def test_BlockMatrix_2x2_inverse_symbolic():
|
||||
A = MatrixSymbol('A', n, m)
|
||||
B = MatrixSymbol('B', n, k - m)
|
||||
C = MatrixSymbol('C', k - n, m)
|
||||
D = MatrixSymbol('D', k - n, k - m)
|
||||
X = BlockMatrix([[A, B], [C, D]])
|
||||
assert X.is_square and X.shape == (k, k)
|
||||
assert isinstance(block_collapse(X.I), Inverse) # Can't invert when none of the blocks is square
|
||||
|
||||
# test code path where only A is invertible
|
||||
A = MatrixSymbol('A', n, n)
|
||||
B = MatrixSymbol('B', n, m)
|
||||
C = MatrixSymbol('C', m, n)
|
||||
D = ZeroMatrix(m, m)
|
||||
X = BlockMatrix([[A, B], [C, D]])
|
||||
assert block_collapse(X.inverse()) == BlockMatrix([
|
||||
[A.I + A.I * B * X.schur('A').I * C * A.I, -A.I * B * X.schur('A').I],
|
||||
[-X.schur('A').I * C * A.I, X.schur('A').I],
|
||||
])
|
||||
|
||||
# test code path where only B is invertible
|
||||
A = MatrixSymbol('A', n, m)
|
||||
B = MatrixSymbol('B', n, n)
|
||||
C = ZeroMatrix(m, m)
|
||||
D = MatrixSymbol('D', m, n)
|
||||
X = BlockMatrix([[A, B], [C, D]])
|
||||
assert block_collapse(X.inverse()) == BlockMatrix([
|
||||
[-X.schur('B').I * D * B.I, X.schur('B').I],
|
||||
[B.I + B.I * A * X.schur('B').I * D * B.I, -B.I * A * X.schur('B').I],
|
||||
])
|
||||
|
||||
# test code path where only C is invertible
|
||||
A = MatrixSymbol('A', n, m)
|
||||
B = ZeroMatrix(n, n)
|
||||
C = MatrixSymbol('C', m, m)
|
||||
D = MatrixSymbol('D', m, n)
|
||||
X = BlockMatrix([[A, B], [C, D]])
|
||||
assert block_collapse(X.inverse()) == BlockMatrix([
|
||||
[-C.I * D * X.schur('C').I, C.I + C.I * D * X.schur('C').I * A * C.I],
|
||||
[X.schur('C').I, -X.schur('C').I * A * C.I],
|
||||
])
|
||||
|
||||
# test code path where only D is invertible
|
||||
A = ZeroMatrix(n, n)
|
||||
B = MatrixSymbol('B', n, m)
|
||||
C = MatrixSymbol('C', m, n)
|
||||
D = MatrixSymbol('D', m, m)
|
||||
X = BlockMatrix([[A, B], [C, D]])
|
||||
assert block_collapse(X.inverse()) == BlockMatrix([
|
||||
[X.schur('D').I, -X.schur('D').I * B * D.I],
|
||||
[-D.I * C * X.schur('D').I, D.I + D.I * C * X.schur('D').I * B * D.I],
|
||||
])
|
||||
|
||||
|
||||
def test_BlockMatrix_2x2_inverse_numeric():
|
||||
"""Test 2x2 block matrix inversion numerically for all 4 formulas"""
|
||||
M = Matrix([[1, 2], [3, 4]])
|
||||
# rank deficient matrices that have full rank when two of them combined
|
||||
D1 = Matrix([[1, 2], [2, 4]])
|
||||
D2 = Matrix([[1, 3], [3, 9]])
|
||||
D3 = Matrix([[1, 4], [4, 16]])
|
||||
assert D1.rank() == D2.rank() == D3.rank() == 1
|
||||
assert (D1 + D2).rank() == (D2 + D3).rank() == (D3 + D1).rank() == 2
|
||||
|
||||
# Only A is invertible
|
||||
K = BlockMatrix([[M, D1], [D2, D3]])
|
||||
assert block_collapse(K.inv()).as_explicit() == K.as_explicit().inv()
|
||||
# Only B is invertible
|
||||
K = BlockMatrix([[D1, M], [D2, D3]])
|
||||
assert block_collapse(K.inv()).as_explicit() == K.as_explicit().inv()
|
||||
# Only C is invertible
|
||||
K = BlockMatrix([[D1, D2], [M, D3]])
|
||||
assert block_collapse(K.inv()).as_explicit() == K.as_explicit().inv()
|
||||
# Only D is invertible
|
||||
K = BlockMatrix([[D1, D2], [D3, M]])
|
||||
assert block_collapse(K.inv()).as_explicit() == K.as_explicit().inv()
|
||||
|
||||
|
||||
@slow
|
||||
def test_BlockMatrix_3x3_symbolic():
|
||||
# Only test one of these, instead of all permutations, because it's slow
|
||||
rowblocksizes = (n, m, k)
|
||||
colblocksizes = (m, k, n)
|
||||
K = BlockMatrix([
|
||||
[MatrixSymbol('M%s%s' % (rows, cols), rows, cols) for cols in colblocksizes]
|
||||
for rows in rowblocksizes
|
||||
])
|
||||
collapse = block_collapse(K.I)
|
||||
assert isinstance(collapse, BlockMatrix)
|
||||
|
||||
|
||||
def test_BlockDiagMatrix():
|
||||
A = MatrixSymbol('A', n, n)
|
||||
B = MatrixSymbol('B', m, m)
|
||||
C = MatrixSymbol('C', l, l)
|
||||
M = MatrixSymbol('M', n + m + l, n + m + l)
|
||||
|
||||
X = BlockDiagMatrix(A, B, C)
|
||||
Y = BlockDiagMatrix(A, 2*B, 3*C)
|
||||
|
||||
assert X.blocks[1, 1] == B
|
||||
assert X.shape == (n + m + l, n + m + l)
|
||||
assert all(X.blocks[i, j].is_ZeroMatrix if i != j else X.blocks[i, j] in [A, B, C]
|
||||
for i in range(3) for j in range(3))
|
||||
assert X.__class__(*X.args) == X
|
||||
assert X.get_diag_blocks() == (A, B, C)
|
||||
|
||||
assert isinstance(block_collapse(X.I * X), Identity)
|
||||
|
||||
assert bc_matmul(X*X) == BlockDiagMatrix(A*A, B*B, C*C)
|
||||
assert block_collapse(X*X) == BlockDiagMatrix(A*A, B*B, C*C)
|
||||
#XXX: should be == ??
|
||||
assert block_collapse(X + X).equals(BlockDiagMatrix(2*A, 2*B, 2*C))
|
||||
assert block_collapse(X*Y) == BlockDiagMatrix(A*A, 2*B*B, 3*C*C)
|
||||
assert block_collapse(X + Y) == BlockDiagMatrix(2*A, 3*B, 4*C)
|
||||
|
||||
# Ensure that BlockDiagMatrices can still interact with normal MatrixExprs
|
||||
assert (X*(2*M)).is_MatMul
|
||||
assert (X + (2*M)).is_MatAdd
|
||||
|
||||
assert (X._blockmul(M)).is_MatMul
|
||||
assert (X._blockadd(M)).is_MatAdd
|
||||
|
||||
def test_BlockDiagMatrix_nonsquare():
|
||||
A = MatrixSymbol('A', n, m)
|
||||
B = MatrixSymbol('B', k, l)
|
||||
X = BlockDiagMatrix(A, B)
|
||||
assert X.shape == (n + k, m + l)
|
||||
assert X.shape == (n + k, m + l)
|
||||
assert X.rowblocksizes == [n, k]
|
||||
assert X.colblocksizes == [m, l]
|
||||
C = MatrixSymbol('C', n, m)
|
||||
D = MatrixSymbol('D', k, l)
|
||||
Y = BlockDiagMatrix(C, D)
|
||||
assert block_collapse(X + Y) == BlockDiagMatrix(A + C, B + D)
|
||||
assert block_collapse(X * Y.T) == BlockDiagMatrix(A * C.T, B * D.T)
|
||||
raises(NonInvertibleMatrixError, lambda: BlockDiagMatrix(A, C.T).inverse())
|
||||
|
||||
def test_BlockDiagMatrix_determinant():
|
||||
A = MatrixSymbol('A', n, n)
|
||||
B = MatrixSymbol('B', m, m)
|
||||
assert det(BlockDiagMatrix()) == 1
|
||||
assert det(BlockDiagMatrix(A)) == det(A)
|
||||
assert det(BlockDiagMatrix(A, B)) == det(A) * det(B)
|
||||
|
||||
# non-square blocks
|
||||
C = MatrixSymbol('C', m, n)
|
||||
D = MatrixSymbol('D', n, m)
|
||||
assert det(BlockDiagMatrix(C, D)) == 0
|
||||
|
||||
def test_BlockDiagMatrix_trace():
|
||||
assert trace(BlockDiagMatrix()) == 0
|
||||
assert trace(BlockDiagMatrix(ZeroMatrix(n, n))) == 0
|
||||
A = MatrixSymbol('A', n, n)
|
||||
assert trace(BlockDiagMatrix(A)) == trace(A)
|
||||
B = MatrixSymbol('B', m, m)
|
||||
assert trace(BlockDiagMatrix(A, B)) == trace(A) + trace(B)
|
||||
|
||||
# non-square blocks
|
||||
C = MatrixSymbol('C', m, n)
|
||||
D = MatrixSymbol('D', n, m)
|
||||
assert isinstance(trace(BlockDiagMatrix(C, D)), Trace)
|
||||
|
||||
def test_BlockDiagMatrix_transpose():
|
||||
A = MatrixSymbol('A', n, m)
|
||||
B = MatrixSymbol('B', k, l)
|
||||
assert transpose(BlockDiagMatrix()) == BlockDiagMatrix()
|
||||
assert transpose(BlockDiagMatrix(A)) == BlockDiagMatrix(A.T)
|
||||
assert transpose(BlockDiagMatrix(A, B)) == BlockDiagMatrix(A.T, B.T)
|
||||
|
||||
def test_issue_2460():
|
||||
bdm1 = BlockDiagMatrix(Matrix([i]), Matrix([j]))
|
||||
bdm2 = BlockDiagMatrix(Matrix([k]), Matrix([l]))
|
||||
assert block_collapse(bdm1 + bdm2) == BlockDiagMatrix(Matrix([i + k]), Matrix([j + l]))
|
||||
|
||||
def test_blockcut():
|
||||
A = MatrixSymbol('A', n, m)
|
||||
B = blockcut(A, (n/2, n/2), (m/2, m/2))
|
||||
assert B == BlockMatrix([[A[:n/2, :m/2], A[:n/2, m/2:]],
|
||||
[A[n/2:, :m/2], A[n/2:, m/2:]]])
|
||||
|
||||
M = ImmutableMatrix(4, 4, range(16))
|
||||
B = blockcut(M, (2, 2), (2, 2))
|
||||
assert M == ImmutableMatrix(B)
|
||||
|
||||
B = blockcut(M, (1, 3), (2, 2))
|
||||
assert ImmutableMatrix(B.blocks[0, 1]) == ImmutableMatrix([[2, 3]])
|
||||
|
||||
def test_reblock_2x2():
|
||||
B = BlockMatrix([[MatrixSymbol('A_%d%d'%(i,j), 2, 2)
|
||||
for j in range(3)]
|
||||
for i in range(3)])
|
||||
assert B.blocks.shape == (3, 3)
|
||||
|
||||
BB = reblock_2x2(B)
|
||||
assert BB.blocks.shape == (2, 2)
|
||||
|
||||
assert B.shape == BB.shape
|
||||
assert B.as_explicit() == BB.as_explicit()
|
||||
|
||||
def test_deblock():
|
||||
B = BlockMatrix([[MatrixSymbol('A_%d%d'%(i,j), n, n)
|
||||
for j in range(4)]
|
||||
for i in range(4)])
|
||||
|
||||
assert deblock(reblock_2x2(B)) == B
|
||||
|
||||
def test_block_collapse_type():
|
||||
bm1 = BlockDiagMatrix(ImmutableMatrix([1]), ImmutableMatrix([2]))
|
||||
bm2 = BlockDiagMatrix(ImmutableMatrix([3]), ImmutableMatrix([4]))
|
||||
|
||||
assert bm1.T.__class__ == BlockDiagMatrix
|
||||
assert block_collapse(bm1 - bm2).__class__ == BlockDiagMatrix
|
||||
assert block_collapse(Inverse(bm1)).__class__ == BlockDiagMatrix
|
||||
assert block_collapse(Transpose(bm1)).__class__ == BlockDiagMatrix
|
||||
assert bc_transpose(Transpose(bm1)).__class__ == BlockDiagMatrix
|
||||
assert bc_inverse(Inverse(bm1)).__class__ == BlockDiagMatrix
|
||||
|
||||
def test_invalid_block_matrix():
|
||||
raises(ValueError, lambda: BlockMatrix([
|
||||
[Identity(2), Identity(5)],
|
||||
]))
|
||||
raises(ValueError, lambda: BlockMatrix([
|
||||
[Identity(n), Identity(m)],
|
||||
]))
|
||||
raises(ValueError, lambda: BlockMatrix([
|
||||
[ZeroMatrix(n, n), ZeroMatrix(n, n)],
|
||||
[ZeroMatrix(n, n - 1), ZeroMatrix(n, n + 1)],
|
||||
]))
|
||||
raises(ValueError, lambda: BlockMatrix([
|
||||
[ZeroMatrix(n - 1, n), ZeroMatrix(n, n)],
|
||||
[ZeroMatrix(n + 1, n), ZeroMatrix(n, n)],
|
||||
]))
|
||||
|
||||
def test_block_lu_decomposition():
|
||||
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]])
|
||||
|
||||
#LDU decomposition
|
||||
L, D, U = X.LDUdecomposition()
|
||||
assert block_collapse(L*D*U) == X
|
||||
|
||||
#UDL decomposition
|
||||
U, D, L = X.UDLdecomposition()
|
||||
assert block_collapse(U*D*L) == X
|
||||
|
||||
#LU decomposition
|
||||
L, U = X.LUdecomposition()
|
||||
assert block_collapse(L*U) == X
|
||||
|
||||
def test_issue_21866():
|
||||
n = 10
|
||||
I = Identity(n)
|
||||
O = ZeroMatrix(n, n)
|
||||
A = BlockMatrix([[ I, O, O, O ],
|
||||
[ O, I, O, O ],
|
||||
[ O, O, I, O ],
|
||||
[ I, O, O, I ]])
|
||||
Ainv = block_collapse(A.inv())
|
||||
AinvT = BlockMatrix([[ I, O, O, O ],
|
||||
[ O, I, O, O ],
|
||||
[ O, O, I, O ],
|
||||
[ -I, O, O, I ]])
|
||||
assert Ainv == AinvT
|
||||
|
||||
|
||||
def test_adjoint_and_special_matrices():
|
||||
A = Identity(3)
|
||||
B = OneMatrix(3, 2)
|
||||
C = ZeroMatrix(2, 3)
|
||||
D = Identity(2)
|
||||
X = BlockMatrix([[A, B], [C, D]])
|
||||
X2 = BlockMatrix([[A, S.ImaginaryUnit*B], [C, D]])
|
||||
assert X.adjoint() == BlockMatrix([[A, ZeroMatrix(3, 2)], [OneMatrix(2, 3), D]])
|
||||
assert re(X) == X
|
||||
assert X2.adjoint() == BlockMatrix([[A, ZeroMatrix(3, 2)], [-S.ImaginaryUnit*OneMatrix(2, 3), D]])
|
||||
assert im(X2) == BlockMatrix([[ZeroMatrix(3, 3), OneMatrix(3, 2)], [ZeroMatrix(2, 3), ZeroMatrix(2, 2)]])
|
||||
|
||||
|
||||
def test_block_matrix_derivative():
|
||||
x = symbols('x')
|
||||
A = Matrix(3, 3, [Function(f'a{i}')(x) for i in range(9)])
|
||||
bc = BlockMatrix([[A[:2, :2], A[:2, 2]], [A[2, :2], A[2:, 2]]])
|
||||
assert Matrix(bc.diff(x)) - A.diff(x) == zeros(3, 3)
|
||||
|
||||
|
||||
def test_transpose_inverse_commute():
|
||||
n = Symbol('n')
|
||||
I = Identity(n)
|
||||
Z = ZeroMatrix(n, n)
|
||||
A = BlockMatrix([[I, Z], [Z, I]])
|
||||
|
||||
assert block_collapse(A.transpose().inverse()) == A
|
||||
assert block_collapse(A.inverse().transpose()) == A
|
||||
|
||||
assert block_collapse(MatPow(A.transpose(), -2)) == MatPow(A, -2)
|
||||
assert block_collapse(MatPow(A, -2).transpose()) == MatPow(A, -2)
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
from sympy.core.expr import unchanged
|
||||
from sympy.core.symbol import Symbol, symbols
|
||||
from sympy.matrices.immutable import ImmutableDenseMatrix
|
||||
from sympy.matrices.expressions.companion import CompanionMatrix
|
||||
from sympy.polys.polytools import Poly
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
def test_creation():
|
||||
x = Symbol('x')
|
||||
y = Symbol('y')
|
||||
raises(ValueError, lambda: CompanionMatrix(1))
|
||||
raises(ValueError, lambda: CompanionMatrix(Poly([1], x)))
|
||||
raises(ValueError, lambda: CompanionMatrix(Poly([2, 1], x)))
|
||||
raises(ValueError, lambda: CompanionMatrix(Poly(x*y, [x, y])))
|
||||
assert unchanged(CompanionMatrix, Poly([1, 2, 3], x))
|
||||
|
||||
|
||||
def test_shape():
|
||||
c0, c1, c2 = symbols('c0:3')
|
||||
x = Symbol('x')
|
||||
assert CompanionMatrix(Poly([1, c0], x)).shape == (1, 1)
|
||||
assert CompanionMatrix(Poly([1, c1, c0], x)).shape == (2, 2)
|
||||
assert CompanionMatrix(Poly([1, c2, c1, c0], x)).shape == (3, 3)
|
||||
|
||||
|
||||
def test_entry():
|
||||
c0, c1, c2 = symbols('c0:3')
|
||||
x = Symbol('x')
|
||||
A = CompanionMatrix(Poly([1, c2, c1, c0], x))
|
||||
assert A[0, 0] == 0
|
||||
assert A[1, 0] == 1
|
||||
assert A[1, 1] == 0
|
||||
assert A[2, 1] == 1
|
||||
assert A[0, 2] == -c0
|
||||
assert A[1, 2] == -c1
|
||||
assert A[2, 2] == -c2
|
||||
|
||||
|
||||
def test_as_explicit():
|
||||
c0, c1, c2 = symbols('c0:3')
|
||||
x = Symbol('x')
|
||||
assert CompanionMatrix(Poly([1, c0], x)).as_explicit() == \
|
||||
ImmutableDenseMatrix([-c0])
|
||||
assert CompanionMatrix(Poly([1, c1, c0], x)).as_explicit() == \
|
||||
ImmutableDenseMatrix([[0, -c0], [1, -c1]])
|
||||
assert CompanionMatrix(Poly([1, c2, c1, c0], x)).as_explicit() == \
|
||||
ImmutableDenseMatrix([[0, 0, -c0], [1, 0, -c1], [0, 1, -c2]])
|
||||
|
|
@ -0,0 +1,477 @@
|
|||
"""
|
||||
Some examples have been taken from:
|
||||
|
||||
http://www.math.uwaterloo.ca/~hwolkowi//matrixcookbook.pdf
|
||||
"""
|
||||
from sympy import KroneckerProduct
|
||||
from sympy.combinatorics import Permutation
|
||||
from sympy.concrete.summations import Sum
|
||||
from sympy.core.numbers import Rational
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.functions.elementary.exponential import (exp, log)
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import (cos, sin, tan)
|
||||
from sympy.functions.special.tensor_functions import KroneckerDelta
|
||||
from sympy.matrices.expressions.determinant import Determinant
|
||||
from sympy.matrices.expressions.diagonal import DiagMatrix
|
||||
from sympy.matrices.expressions.hadamard import (HadamardPower, HadamardProduct, hadamard_product)
|
||||
from sympy.matrices.expressions.inverse import Inverse
|
||||
from sympy.matrices.expressions.matexpr import MatrixSymbol
|
||||
from sympy.matrices.expressions.special import OneMatrix
|
||||
from sympy.matrices.expressions.trace import Trace
|
||||
from sympy.matrices.expressions.matadd import MatAdd
|
||||
from sympy.matrices.expressions.matmul import MatMul
|
||||
from sympy.matrices.expressions.special import (Identity, ZeroMatrix)
|
||||
from sympy.tensor.array.array_derivatives import ArrayDerivative
|
||||
from sympy.matrices.expressions import hadamard_power
|
||||
from sympy.tensor.array.expressions.array_expressions import ArrayAdd, ArrayTensorProduct, PermuteDims
|
||||
|
||||
i, j, k = symbols("i j k")
|
||||
m, n = symbols("m n")
|
||||
|
||||
X = MatrixSymbol("X", k, k)
|
||||
x = MatrixSymbol("x", k, 1)
|
||||
y = MatrixSymbol("y", k, 1)
|
||||
|
||||
A = MatrixSymbol("A", k, k)
|
||||
B = MatrixSymbol("B", k, k)
|
||||
C = MatrixSymbol("C", k, k)
|
||||
D = MatrixSymbol("D", k, k)
|
||||
|
||||
a = MatrixSymbol("a", k, 1)
|
||||
b = MatrixSymbol("b", k, 1)
|
||||
c = MatrixSymbol("c", k, 1)
|
||||
d = MatrixSymbol("d", k, 1)
|
||||
|
||||
|
||||
KDelta = lambda i, j: KroneckerDelta(i, j, (0, k-1))
|
||||
|
||||
|
||||
def _check_derivative_with_explicit_matrix(expr, x, diffexpr, dim=2):
|
||||
# TODO: this is commented because it slows down the tests.
|
||||
return
|
||||
|
||||
expr = expr.xreplace({k: dim})
|
||||
x = x.xreplace({k: dim})
|
||||
diffexpr = diffexpr.xreplace({k: dim})
|
||||
|
||||
expr = expr.as_explicit()
|
||||
x = x.as_explicit()
|
||||
diffexpr = diffexpr.as_explicit()
|
||||
|
||||
assert expr.diff(x).reshape(*diffexpr.shape).tomatrix() == diffexpr
|
||||
|
||||
|
||||
def test_matrix_derivative_by_scalar():
|
||||
assert A.diff(i) == ZeroMatrix(k, k)
|
||||
assert (A*(X + B)*c).diff(i) == ZeroMatrix(k, 1)
|
||||
assert x.diff(i) == ZeroMatrix(k, 1)
|
||||
assert (x.T*y).diff(i) == ZeroMatrix(1, 1)
|
||||
assert (x*x.T).diff(i) == ZeroMatrix(k, k)
|
||||
assert (x + y).diff(i) == ZeroMatrix(k, 1)
|
||||
assert hadamard_power(x, 2).diff(i) == ZeroMatrix(k, 1)
|
||||
assert hadamard_power(x, i).diff(i).dummy_eq(
|
||||
HadamardProduct(x.applyfunc(log), HadamardPower(x, i)))
|
||||
assert hadamard_product(x, y).diff(i) == ZeroMatrix(k, 1)
|
||||
assert hadamard_product(i*OneMatrix(k, 1), x, y).diff(i) == hadamard_product(x, y)
|
||||
assert (i*x).diff(i) == x
|
||||
assert (sin(i)*A*B*x).diff(i) == cos(i)*A*B*x
|
||||
assert x.applyfunc(sin).diff(i) == ZeroMatrix(k, 1)
|
||||
assert Trace(i**2*X).diff(i) == 2*i*Trace(X)
|
||||
|
||||
mu = symbols("mu")
|
||||
expr = (2*mu*x)
|
||||
assert expr.diff(x) == 2*mu*Identity(k)
|
||||
|
||||
|
||||
def test_one_matrix():
|
||||
assert MatMul(x.T, OneMatrix(k, 1)).diff(x) == OneMatrix(k, 1)
|
||||
|
||||
|
||||
def test_matrix_derivative_non_matrix_result():
|
||||
# This is a 4-dimensional array:
|
||||
I = Identity(k)
|
||||
AdA = PermuteDims(ArrayTensorProduct(I, I), Permutation(3)(1, 2))
|
||||
assert A.diff(A) == AdA
|
||||
assert A.T.diff(A) == PermuteDims(ArrayTensorProduct(I, I), Permutation(3)(1, 2, 3))
|
||||
assert (2*A).diff(A) == PermuteDims(ArrayTensorProduct(2*I, I), Permutation(3)(1, 2))
|
||||
assert MatAdd(A, A).diff(A) == ArrayAdd(AdA, AdA)
|
||||
assert (A + B).diff(A) == AdA
|
||||
|
||||
|
||||
def test_matrix_derivative_trivial_cases():
|
||||
# Cookbook example 33:
|
||||
# TODO: find a way to represent a four-dimensional zero-array:
|
||||
assert X.diff(A) == ArrayDerivative(X, A)
|
||||
|
||||
|
||||
def test_matrix_derivative_with_inverse():
|
||||
|
||||
# Cookbook example 61:
|
||||
expr = a.T*Inverse(X)*b
|
||||
assert expr.diff(X) == -Inverse(X).T*a*b.T*Inverse(X).T
|
||||
|
||||
# Cookbook example 62:
|
||||
expr = Determinant(Inverse(X))
|
||||
# Not implemented yet:
|
||||
# assert expr.diff(X) == -Determinant(X.inv())*(X.inv()).T
|
||||
|
||||
# Cookbook example 63:
|
||||
expr = Trace(A*Inverse(X)*B)
|
||||
assert expr.diff(X) == -(X**(-1)*B*A*X**(-1)).T
|
||||
|
||||
# Cookbook example 64:
|
||||
expr = Trace(Inverse(X + A))
|
||||
assert expr.diff(X) == -(Inverse(X + A)).T**2
|
||||
|
||||
|
||||
def test_matrix_derivative_vectors_and_scalars():
|
||||
|
||||
assert x.diff(x) == Identity(k)
|
||||
assert x[i, 0].diff(x[m, 0]).doit() == KDelta(m, i)
|
||||
|
||||
assert x.T.diff(x) == Identity(k)
|
||||
|
||||
# Cookbook example 69:
|
||||
expr = x.T*a
|
||||
assert expr.diff(x) == a
|
||||
assert expr[0, 0].diff(x[m, 0]).doit() == a[m, 0]
|
||||
expr = a.T*x
|
||||
assert expr.diff(x) == a
|
||||
|
||||
# Cookbook example 70:
|
||||
expr = a.T*X*b
|
||||
assert expr.diff(X) == a*b.T
|
||||
|
||||
# Cookbook example 71:
|
||||
expr = a.T*X.T*b
|
||||
assert expr.diff(X) == b*a.T
|
||||
|
||||
# Cookbook example 72:
|
||||
expr = a.T*X*a
|
||||
assert expr.diff(X) == a*a.T
|
||||
expr = a.T*X.T*a
|
||||
assert expr.diff(X) == a*a.T
|
||||
|
||||
# Cookbook example 77:
|
||||
expr = b.T*X.T*X*c
|
||||
assert expr.diff(X) == X*b*c.T + X*c*b.T
|
||||
|
||||
# Cookbook example 78:
|
||||
expr = (B*x + b).T*C*(D*x + d)
|
||||
assert expr.diff(x) == B.T*C*(D*x + d) + D.T*C.T*(B*x + b)
|
||||
|
||||
# Cookbook example 81:
|
||||
expr = x.T*B*x
|
||||
assert expr.diff(x) == B*x + B.T*x
|
||||
|
||||
# Cookbook example 82:
|
||||
expr = b.T*X.T*D*X*c
|
||||
assert expr.diff(X) == D.T*X*b*c.T + D*X*c*b.T
|
||||
|
||||
# Cookbook example 83:
|
||||
expr = (X*b + c).T*D*(X*b + c)
|
||||
assert expr.diff(X) == D*(X*b + c)*b.T + D.T*(X*b + c)*b.T
|
||||
assert str(expr[0, 0].diff(X[m, n]).doit()) == \
|
||||
'b[n, 0]*Sum((c[_i_1, 0] + Sum(X[_i_1, _i_3]*b[_i_3, 0], (_i_3, 0, k - 1)))*D[_i_1, m], (_i_1, 0, k - 1)) + Sum((c[_i_2, 0] + Sum(X[_i_2, _i_4]*b[_i_4, 0], (_i_4, 0, k - 1)))*D[m, _i_2]*b[n, 0], (_i_2, 0, k - 1))'
|
||||
|
||||
# See https://github.com/sympy/sympy/issues/16504#issuecomment-1018339957
|
||||
expr = x*x.T*x
|
||||
I = Identity(k)
|
||||
assert expr.diff(x) == KroneckerProduct(I, x.T*x) + 2*x*x.T
|
||||
|
||||
|
||||
def test_matrix_derivatives_of_traces():
|
||||
|
||||
expr = Trace(A)*A
|
||||
I = Identity(k)
|
||||
assert expr.diff(A) == ArrayAdd(ArrayTensorProduct(I, A), PermuteDims(ArrayTensorProduct(Trace(A)*I, I), Permutation(3)(1, 2)))
|
||||
assert expr[i, j].diff(A[m, n]).doit() == (
|
||||
KDelta(i, m)*KDelta(j, n)*Trace(A) +
|
||||
KDelta(m, n)*A[i, j]
|
||||
)
|
||||
|
||||
## First order:
|
||||
|
||||
# Cookbook example 99:
|
||||
expr = Trace(X)
|
||||
assert expr.diff(X) == Identity(k)
|
||||
assert expr.rewrite(Sum).diff(X[m, n]).doit() == KDelta(m, n)
|
||||
|
||||
# Cookbook example 100:
|
||||
expr = Trace(X*A)
|
||||
assert expr.diff(X) == A.T
|
||||
assert expr.rewrite(Sum).diff(X[m, n]).doit() == A[n, m]
|
||||
|
||||
# Cookbook example 101:
|
||||
expr = Trace(A*X*B)
|
||||
assert expr.diff(X) == A.T*B.T
|
||||
assert expr.rewrite(Sum).diff(X[m, n]).doit().dummy_eq((A.T*B.T)[m, n])
|
||||
|
||||
# Cookbook example 102:
|
||||
expr = Trace(A*X.T*B)
|
||||
assert expr.diff(X) == B*A
|
||||
|
||||
# Cookbook example 103:
|
||||
expr = Trace(X.T*A)
|
||||
assert expr.diff(X) == A
|
||||
|
||||
# Cookbook example 104:
|
||||
expr = Trace(A*X.T)
|
||||
assert expr.diff(X) == A
|
||||
|
||||
# Cookbook example 105:
|
||||
# TODO: TensorProduct is not supported
|
||||
#expr = Trace(TensorProduct(A, X))
|
||||
#assert expr.diff(X) == Trace(A)*Identity(k)
|
||||
|
||||
## Second order:
|
||||
|
||||
# Cookbook example 106:
|
||||
expr = Trace(X**2)
|
||||
assert expr.diff(X) == 2*X.T
|
||||
|
||||
# Cookbook example 107:
|
||||
expr = Trace(X**2*B)
|
||||
assert expr.diff(X) == (X*B + B*X).T
|
||||
expr = Trace(MatMul(X, X, B))
|
||||
assert expr.diff(X) == (X*B + B*X).T
|
||||
|
||||
# Cookbook example 108:
|
||||
expr = Trace(X.T*B*X)
|
||||
assert expr.diff(X) == B*X + B.T*X
|
||||
|
||||
# Cookbook example 109:
|
||||
expr = Trace(B*X*X.T)
|
||||
assert expr.diff(X) == B*X + B.T*X
|
||||
|
||||
# Cookbook example 110:
|
||||
expr = Trace(X*X.T*B)
|
||||
assert expr.diff(X) == B*X + B.T*X
|
||||
|
||||
# Cookbook example 111:
|
||||
expr = Trace(X*B*X.T)
|
||||
assert expr.diff(X) == X*B.T + X*B
|
||||
|
||||
# Cookbook example 112:
|
||||
expr = Trace(B*X.T*X)
|
||||
assert expr.diff(X) == X*B.T + X*B
|
||||
|
||||
# Cookbook example 113:
|
||||
expr = Trace(X.T*X*B)
|
||||
assert expr.diff(X) == X*B.T + X*B
|
||||
|
||||
# Cookbook example 114:
|
||||
expr = Trace(A*X*B*X)
|
||||
assert expr.diff(X) == A.T*X.T*B.T + B.T*X.T*A.T
|
||||
|
||||
# Cookbook example 115:
|
||||
expr = Trace(X.T*X)
|
||||
assert expr.diff(X) == 2*X
|
||||
expr = Trace(X*X.T)
|
||||
assert expr.diff(X) == 2*X
|
||||
|
||||
# Cookbook example 116:
|
||||
expr = Trace(B.T*X.T*C*X*B)
|
||||
assert expr.diff(X) == C.T*X*B*B.T + C*X*B*B.T
|
||||
|
||||
# Cookbook example 117:
|
||||
expr = Trace(X.T*B*X*C)
|
||||
assert expr.diff(X) == B*X*C + B.T*X*C.T
|
||||
|
||||
# Cookbook example 118:
|
||||
expr = Trace(A*X*B*X.T*C)
|
||||
assert expr.diff(X) == A.T*C.T*X*B.T + C*A*X*B
|
||||
|
||||
# Cookbook example 119:
|
||||
expr = Trace((A*X*B + C)*(A*X*B + C).T)
|
||||
assert expr.diff(X) == 2*A.T*(A*X*B + C)*B.T
|
||||
|
||||
# Cookbook example 120:
|
||||
# TODO: no support for TensorProduct.
|
||||
# expr = Trace(TensorProduct(X, X))
|
||||
# expr = Trace(X)*Trace(X)
|
||||
# expr.diff(X) == 2*Trace(X)*Identity(k)
|
||||
|
||||
# Higher Order
|
||||
|
||||
# Cookbook example 121:
|
||||
expr = Trace(X**k)
|
||||
#assert expr.diff(X) == k*(X**(k-1)).T
|
||||
|
||||
# Cookbook example 122:
|
||||
expr = Trace(A*X**k)
|
||||
#assert expr.diff(X) == # Needs indices
|
||||
|
||||
# Cookbook example 123:
|
||||
expr = Trace(B.T*X.T*C*X*X.T*C*X*B)
|
||||
assert expr.diff(X) == C*X*X.T*C*X*B*B.T + C.T*X*B*B.T*X.T*C.T*X + C*X*B*B.T*X.T*C*X + C.T*X*X.T*C.T*X*B*B.T
|
||||
|
||||
# Other
|
||||
|
||||
# Cookbook example 124:
|
||||
expr = Trace(A*X**(-1)*B)
|
||||
assert expr.diff(X) == -Inverse(X).T*A.T*B.T*Inverse(X).T
|
||||
|
||||
# Cookbook example 125:
|
||||
expr = Trace(Inverse(X.T*C*X)*A)
|
||||
# Warning: result in the cookbook is equivalent if B and C are symmetric:
|
||||
assert expr.diff(X) == - X.inv().T*A.T*X.inv()*C.inv().T*X.inv().T - X.inv().T*A*X.inv()*C.inv()*X.inv().T
|
||||
|
||||
# Cookbook example 126:
|
||||
expr = Trace((X.T*C*X).inv()*(X.T*B*X))
|
||||
assert expr.diff(X) == -2*C*X*(X.T*C*X).inv()*X.T*B*X*(X.T*C*X).inv() + 2*B*X*(X.T*C*X).inv()
|
||||
|
||||
# Cookbook example 127:
|
||||
expr = Trace((A + X.T*C*X).inv()*(X.T*B*X))
|
||||
# Warning: result in the cookbook is equivalent if B and C are symmetric:
|
||||
assert expr.diff(X) == B*X*Inverse(A + X.T*C*X) - C*X*Inverse(A + X.T*C*X)*X.T*B*X*Inverse(A + X.T*C*X) - C.T*X*Inverse(A.T + (C*X).T*X)*X.T*B.T*X*Inverse(A.T + (C*X).T*X) + B.T*X*Inverse(A.T + (C*X).T*X)
|
||||
|
||||
|
||||
def test_derivatives_of_complicated_matrix_expr():
|
||||
expr = a.T*(A*X*(X.T*B + X*A) + B.T*X.T*(a*b.T*(X*D*X.T + X*(X.T*B + A*X)*D*B - X.T*C.T*A)*B + B*(X*D.T + B*A*X*A.T - 3*X*D))*B + 42*X*B*X.T*A.T*(X + X.T))*b
|
||||
result = (B*(B*A*X*A.T - 3*X*D + X*D.T) + a*b.T*(X*(A*X + X.T*B)*D*B + X*D*X.T - X.T*C.T*A)*B)*B*b*a.T*B.T + B**2*b*a.T*B.T*X.T*a*b.T*X*D + 42*A*X*B.T*X.T*a*b.T + B*D*B**3*b*a.T*B.T*X.T*a*b.T*X + B*b*a.T*A*X + a*b.T*(42*X + 42*X.T)*A*X*B.T + b*a.T*X*B*a*b.T*B.T**2*X*D.T + b*a.T*X*B*a*b.T*B.T**3*D.T*(B.T*X + X.T*A.T) + 42*b*a.T*X*B*X.T*A.T + A.T*(42*X + 42*X.T)*b*a.T*X*B + A.T*B.T**2*X*B*a*b.T*B.T*A + A.T*a*b.T*(A.T*X.T + B.T*X) + A.T*X.T*b*a.T*X*B*a*b.T*B.T**3*D.T + B.T*X*B*a*b.T*B.T*D - 3*B.T*X*B*a*b.T*B.T*D.T - C.T*A*B**2*b*a.T*B.T*X.T*a*b.T + X.T*A.T*a*b.T*A.T
|
||||
assert expr.diff(X) == result
|
||||
|
||||
|
||||
def test_mixed_deriv_mixed_expressions():
|
||||
|
||||
expr = 3*Trace(A)
|
||||
assert expr.diff(A) == 3*Identity(k)
|
||||
|
||||
expr = k
|
||||
deriv = expr.diff(A)
|
||||
assert isinstance(deriv, ZeroMatrix)
|
||||
assert deriv == ZeroMatrix(k, k)
|
||||
|
||||
expr = Trace(A)**2
|
||||
assert expr.diff(A) == (2*Trace(A))*Identity(k)
|
||||
|
||||
expr = Trace(A)*A
|
||||
I = Identity(k)
|
||||
assert expr.diff(A) == ArrayAdd(ArrayTensorProduct(I, A), PermuteDims(ArrayTensorProduct(Trace(A)*I, I), Permutation(3)(1, 2)))
|
||||
|
||||
expr = Trace(Trace(A)*A)
|
||||
assert expr.diff(A) == (2*Trace(A))*Identity(k)
|
||||
|
||||
expr = Trace(Trace(Trace(A)*A)*A)
|
||||
assert expr.diff(A) == (3*Trace(A)**2)*Identity(k)
|
||||
|
||||
|
||||
def test_derivatives_matrix_norms():
|
||||
|
||||
expr = x.T*y
|
||||
assert expr.diff(x) == y
|
||||
assert expr[0, 0].diff(x[m, 0]).doit() == y[m, 0]
|
||||
|
||||
expr = (x.T*y)**S.Half
|
||||
assert expr.diff(x) == y/(2*sqrt(x.T*y))
|
||||
|
||||
expr = (x.T*x)**S.Half
|
||||
assert expr.diff(x) == x*(x.T*x)**Rational(-1, 2)
|
||||
|
||||
expr = (c.T*a*x.T*b)**S.Half
|
||||
assert expr.diff(x) == b*a.T*c/sqrt(c.T*a*x.T*b)/2
|
||||
|
||||
expr = (c.T*a*x.T*b)**Rational(1, 3)
|
||||
assert expr.diff(x) == b*a.T*c*(c.T*a*x.T*b)**Rational(-2, 3)/3
|
||||
|
||||
expr = (a.T*X*b)**S.Half
|
||||
assert expr.diff(X) == a/(2*sqrt(a.T*X*b))*b.T
|
||||
|
||||
expr = d.T*x*(a.T*X*b)**S.Half*y.T*c
|
||||
assert expr.diff(X) == a/(2*sqrt(a.T*X*b))*x.T*d*y.T*c*b.T
|
||||
|
||||
|
||||
def test_derivatives_elementwise_applyfunc():
|
||||
|
||||
expr = x.applyfunc(tan)
|
||||
assert expr.diff(x).dummy_eq(
|
||||
DiagMatrix(x.applyfunc(lambda x: tan(x)**2 + 1)))
|
||||
assert expr[i, 0].diff(x[m, 0]).doit() == (tan(x[i, 0])**2 + 1)*KDelta(i, m)
|
||||
_check_derivative_with_explicit_matrix(expr, x, expr.diff(x))
|
||||
|
||||
expr = (i**2*x).applyfunc(sin)
|
||||
assert expr.diff(i).dummy_eq(
|
||||
HadamardProduct((2*i)*x, (i**2*x).applyfunc(cos)))
|
||||
assert expr[i, 0].diff(i).doit() == 2*i*x[i, 0]*cos(i**2*x[i, 0])
|
||||
_check_derivative_with_explicit_matrix(expr, i, expr.diff(i))
|
||||
|
||||
expr = (log(i)*A*B).applyfunc(sin)
|
||||
assert expr.diff(i).dummy_eq(
|
||||
HadamardProduct(A*B/i, (log(i)*A*B).applyfunc(cos)))
|
||||
_check_derivative_with_explicit_matrix(expr, i, expr.diff(i))
|
||||
|
||||
expr = A*x.applyfunc(exp)
|
||||
# TODO: restore this result (currently returning the transpose):
|
||||
# assert expr.diff(x).dummy_eq(DiagMatrix(x.applyfunc(exp))*A.T)
|
||||
_check_derivative_with_explicit_matrix(expr, x, expr.diff(x))
|
||||
|
||||
expr = x.T*A*x + k*y.applyfunc(sin).T*x
|
||||
assert expr.diff(x).dummy_eq(A.T*x + A*x + k*y.applyfunc(sin))
|
||||
_check_derivative_with_explicit_matrix(expr, x, expr.diff(x))
|
||||
|
||||
expr = x.applyfunc(sin).T*y
|
||||
# TODO: restore (currently returning the transpose):
|
||||
# assert expr.diff(x).dummy_eq(DiagMatrix(x.applyfunc(cos))*y)
|
||||
_check_derivative_with_explicit_matrix(expr, x, expr.diff(x))
|
||||
|
||||
expr = (a.T * X * b).applyfunc(sin)
|
||||
assert expr.diff(X).dummy_eq(a*(a.T*X*b).applyfunc(cos)*b.T)
|
||||
_check_derivative_with_explicit_matrix(expr, X, expr.diff(X))
|
||||
|
||||
expr = a.T * X.applyfunc(sin) * b
|
||||
assert expr.diff(X).dummy_eq(
|
||||
DiagMatrix(a)*X.applyfunc(cos)*DiagMatrix(b))
|
||||
_check_derivative_with_explicit_matrix(expr, X, expr.diff(X))
|
||||
|
||||
expr = a.T * (A*X*B).applyfunc(sin) * b
|
||||
assert expr.diff(X).dummy_eq(
|
||||
A.T*DiagMatrix(a)*(A*X*B).applyfunc(cos)*DiagMatrix(b)*B.T)
|
||||
_check_derivative_with_explicit_matrix(expr, X, expr.diff(X))
|
||||
|
||||
expr = a.T * (A*X*b).applyfunc(sin) * b.T
|
||||
# TODO: not implemented
|
||||
#assert expr.diff(X) == ...
|
||||
#_check_derivative_with_explicit_matrix(expr, X, expr.diff(X))
|
||||
|
||||
expr = a.T*A*X.applyfunc(sin)*B*b
|
||||
assert expr.diff(X).dummy_eq(
|
||||
HadamardProduct(A.T * a * b.T * B.T, X.applyfunc(cos)))
|
||||
|
||||
expr = a.T * (A*X.applyfunc(sin)*B).applyfunc(log) * b
|
||||
# TODO: wrong
|
||||
# assert expr.diff(X) == A.T*DiagMatrix(a)*(A*X.applyfunc(sin)*B).applyfunc(Lambda(k, 1/k))*DiagMatrix(b)*B.T
|
||||
|
||||
expr = a.T * (X.applyfunc(sin)).applyfunc(log) * b
|
||||
# TODO: wrong
|
||||
# assert expr.diff(X) == DiagMatrix(a)*X.applyfunc(sin).applyfunc(Lambda(k, 1/k))*DiagMatrix(b)
|
||||
|
||||
|
||||
def test_derivatives_of_hadamard_expressions():
|
||||
|
||||
# Hadamard Product
|
||||
|
||||
expr = hadamard_product(a, x, b)
|
||||
assert expr.diff(x) == DiagMatrix(hadamard_product(b, a))
|
||||
|
||||
expr = a.T*hadamard_product(A, X, B)*b
|
||||
assert expr.diff(X) == HadamardProduct(a*b.T, A, B)
|
||||
|
||||
# Hadamard Power
|
||||
|
||||
expr = hadamard_power(x, 2)
|
||||
assert expr.diff(x).doit() == 2*DiagMatrix(x)
|
||||
|
||||
expr = hadamard_power(x.T, 2)
|
||||
assert expr.diff(x).doit() == 2*DiagMatrix(x)
|
||||
|
||||
expr = hadamard_power(x, S.Half)
|
||||
assert expr.diff(x) == S.Half*DiagMatrix(hadamard_power(x, Rational(-1, 2)))
|
||||
|
||||
expr = hadamard_power(a.T*X*b, 2)
|
||||
assert expr.diff(X) == 2*a*a.T*X*b*b.T
|
||||
|
||||
expr = hadamard_power(a.T*X*b, S.Half)
|
||||
assert expr.diff(X) == a/(2*sqrt(a.T*X*b))*b.T
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
from sympy.core import S, symbols
|
||||
from sympy.matrices import eye, ones, Matrix, ShapeError
|
||||
from sympy.matrices.expressions import (
|
||||
Identity, MatrixExpr, MatrixSymbol, Determinant,
|
||||
det, per, ZeroMatrix, Transpose,
|
||||
Permanent, MatMul
|
||||
)
|
||||
from sympy.matrices.expressions.special import OneMatrix
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.assumptions.ask import Q
|
||||
from sympy.assumptions.refine import refine
|
||||
|
||||
n = symbols('n', integer=True)
|
||||
A = MatrixSymbol('A', n, n)
|
||||
B = MatrixSymbol('B', n, n)
|
||||
C = MatrixSymbol('C', 3, 4)
|
||||
|
||||
|
||||
def test_det():
|
||||
assert isinstance(Determinant(A), Determinant)
|
||||
assert not isinstance(Determinant(A), MatrixExpr)
|
||||
raises(ShapeError, lambda: Determinant(C))
|
||||
assert det(eye(3)) == 1
|
||||
assert det(Matrix(3, 3, [1, 3, 2, 4, 1, 3, 2, 5, 2])) == 17
|
||||
_ = A / det(A) # Make sure this is possible
|
||||
|
||||
raises(TypeError, lambda: Determinant(S.One))
|
||||
|
||||
assert Determinant(A).arg is A
|
||||
|
||||
|
||||
def test_eval_determinant():
|
||||
assert det(Identity(n)) == 1
|
||||
assert det(ZeroMatrix(n, n)) == 0
|
||||
assert det(OneMatrix(n, n)) == Determinant(OneMatrix(n, n))
|
||||
assert det(OneMatrix(1, 1)) == 1
|
||||
assert det(OneMatrix(2, 2)) == 0
|
||||
assert det(Transpose(A)) == det(A)
|
||||
assert Determinant(MatMul(eye(2), eye(2))).doit(deep=True) == 1
|
||||
|
||||
|
||||
def test_refine():
|
||||
assert refine(det(A), Q.orthogonal(A)) == 1
|
||||
assert refine(det(A), Q.singular(A)) == 0
|
||||
assert refine(det(A), Q.unit_triangular(A)) == 1
|
||||
assert refine(det(A), Q.normal(A)) == det(A)
|
||||
|
||||
|
||||
def test_commutative():
|
||||
det_a = Determinant(A)
|
||||
det_b = Determinant(B)
|
||||
assert det_a.is_commutative
|
||||
assert det_b.is_commutative
|
||||
assert det_a * det_b == det_b * det_a
|
||||
|
||||
|
||||
def test_permanent():
|
||||
assert isinstance(Permanent(A), Permanent)
|
||||
assert not isinstance(Permanent(A), MatrixExpr)
|
||||
assert isinstance(Permanent(C), Permanent)
|
||||
assert Permanent(ones(3, 3)).doit() == 6
|
||||
_ = C / per(C)
|
||||
assert per(Matrix(3, 3, [1, 3, 2, 4, 1, 3, 2, 5, 2])) == 103
|
||||
raises(TypeError, lambda: Permanent(S.One))
|
||||
assert Permanent(A).arg is A
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
from sympy.matrices.expressions import MatrixSymbol
|
||||
from sympy.matrices.expressions.diagonal import DiagonalMatrix, DiagonalOf, DiagMatrix, diagonalize_vector
|
||||
from sympy.assumptions.ask import (Q, ask)
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.functions.special.tensor_functions import KroneckerDelta
|
||||
from sympy.matrices.dense import Matrix
|
||||
from sympy.matrices.expressions.matmul import MatMul
|
||||
from sympy.matrices.expressions.special import Identity
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
n = Symbol('n')
|
||||
m = Symbol('m')
|
||||
|
||||
|
||||
def test_DiagonalMatrix():
|
||||
x = MatrixSymbol('x', n, m)
|
||||
D = DiagonalMatrix(x)
|
||||
assert D.diagonal_length is None
|
||||
assert D.shape == (n, m)
|
||||
|
||||
x = MatrixSymbol('x', n, n)
|
||||
D = DiagonalMatrix(x)
|
||||
assert D.diagonal_length == n
|
||||
assert D.shape == (n, n)
|
||||
assert D[1, 2] == 0
|
||||
assert D[1, 1] == x[1, 1]
|
||||
i = Symbol('i')
|
||||
j = Symbol('j')
|
||||
x = MatrixSymbol('x', 3, 3)
|
||||
ij = DiagonalMatrix(x)[i, j]
|
||||
assert ij != 0
|
||||
assert ij.subs({i:0, j:0}) == x[0, 0]
|
||||
assert ij.subs({i:0, j:1}) == 0
|
||||
assert ij.subs({i:1, j:1}) == x[1, 1]
|
||||
assert ask(Q.diagonal(D)) # affirm that D is diagonal
|
||||
|
||||
x = MatrixSymbol('x', n, 3)
|
||||
D = DiagonalMatrix(x)
|
||||
assert D.diagonal_length == 3
|
||||
assert D.shape == (n, 3)
|
||||
assert D[2, m] == KroneckerDelta(2, m)*x[2, m]
|
||||
assert D[3, m] == 0
|
||||
raises(IndexError, lambda: D[m, 3])
|
||||
|
||||
x = MatrixSymbol('x', 3, n)
|
||||
D = DiagonalMatrix(x)
|
||||
assert D.diagonal_length == 3
|
||||
assert D.shape == (3, n)
|
||||
assert D[m, 2] == KroneckerDelta(m, 2)*x[m, 2]
|
||||
assert D[m, 3] == 0
|
||||
raises(IndexError, lambda: D[3, m])
|
||||
|
||||
x = MatrixSymbol('x', n, m)
|
||||
D = DiagonalMatrix(x)
|
||||
assert D.diagonal_length is None
|
||||
assert D.shape == (n, m)
|
||||
assert D[m, 4] != 0
|
||||
|
||||
x = MatrixSymbol('x', 3, 4)
|
||||
assert [DiagonalMatrix(x)[i] for i in range(12)] == [
|
||||
x[0, 0], 0, 0, 0, 0, x[1, 1], 0, 0, 0, 0, x[2, 2], 0]
|
||||
|
||||
# shape is retained, issue 12427
|
||||
assert (
|
||||
DiagonalMatrix(MatrixSymbol('x', 3, 4))*
|
||||
DiagonalMatrix(MatrixSymbol('x', 4, 2))).shape == (3, 2)
|
||||
|
||||
|
||||
def test_DiagonalOf():
|
||||
x = MatrixSymbol('x', n, n)
|
||||
d = DiagonalOf(x)
|
||||
assert d.shape == (n, 1)
|
||||
assert d.diagonal_length == n
|
||||
assert d[2, 0] == d[2] == x[2, 2]
|
||||
|
||||
x = MatrixSymbol('x', n, m)
|
||||
d = DiagonalOf(x)
|
||||
assert d.shape == (None, 1)
|
||||
assert d.diagonal_length is None
|
||||
assert d[2, 0] == d[2] == x[2, 2]
|
||||
|
||||
d = DiagonalOf(MatrixSymbol('x', 4, 3))
|
||||
assert d.shape == (3, 1)
|
||||
d = DiagonalOf(MatrixSymbol('x', n, 3))
|
||||
assert d.shape == (3, 1)
|
||||
d = DiagonalOf(MatrixSymbol('x', 3, n))
|
||||
assert d.shape == (3, 1)
|
||||
x = MatrixSymbol('x', n, m)
|
||||
assert [DiagonalOf(x)[i] for i in range(4)] ==[
|
||||
x[0, 0], x[1, 1], x[2, 2], x[3, 3]]
|
||||
|
||||
|
||||
def test_DiagMatrix():
|
||||
x = MatrixSymbol('x', n, 1)
|
||||
d = DiagMatrix(x)
|
||||
assert d.shape == (n, n)
|
||||
assert d[0, 1] == 0
|
||||
assert d[0, 0] == x[0, 0]
|
||||
|
||||
a = MatrixSymbol('a', 1, 1)
|
||||
d = diagonalize_vector(a)
|
||||
assert isinstance(d, MatrixSymbol)
|
||||
assert a == d
|
||||
assert diagonalize_vector(Identity(3)) == Identity(3)
|
||||
assert DiagMatrix(Identity(3)).doit() == Identity(3)
|
||||
assert isinstance(DiagMatrix(Identity(3)), DiagMatrix)
|
||||
|
||||
# A diagonal matrix is equal to its transpose:
|
||||
assert DiagMatrix(x).T == DiagMatrix(x)
|
||||
assert diagonalize_vector(x.T) == DiagMatrix(x)
|
||||
|
||||
dx = DiagMatrix(x)
|
||||
assert dx[0, 0] == x[0, 0]
|
||||
assert dx[1, 1] == x[1, 0]
|
||||
assert dx[0, 1] == 0
|
||||
assert dx[0, m] == x[0, 0]*KroneckerDelta(0, m)
|
||||
|
||||
z = MatrixSymbol('z', 1, n)
|
||||
dz = DiagMatrix(z)
|
||||
assert dz[0, 0] == z[0, 0]
|
||||
assert dz[1, 1] == z[0, 1]
|
||||
assert dz[0, 1] == 0
|
||||
assert dz[0, m] == z[0, m]*KroneckerDelta(0, m)
|
||||
|
||||
v = MatrixSymbol('v', 3, 1)
|
||||
dv = DiagMatrix(v)
|
||||
assert dv.as_explicit() == Matrix([
|
||||
[v[0, 0], 0, 0],
|
||||
[0, v[1, 0], 0],
|
||||
[0, 0, v[2, 0]],
|
||||
])
|
||||
|
||||
v = MatrixSymbol('v', 1, 3)
|
||||
dv = DiagMatrix(v)
|
||||
assert dv.as_explicit() == Matrix([
|
||||
[v[0, 0], 0, 0],
|
||||
[0, v[0, 1], 0],
|
||||
[0, 0, v[0, 2]],
|
||||
])
|
||||
|
||||
dv = DiagMatrix(3*v)
|
||||
assert dv.args == (3*v,)
|
||||
assert dv.doit() == 3*DiagMatrix(v)
|
||||
assert isinstance(dv.doit(), MatMul)
|
||||
|
||||
a = MatrixSymbol("a", 3, 1).as_explicit()
|
||||
expr = DiagMatrix(a)
|
||||
result = Matrix([
|
||||
[a[0, 0], 0, 0],
|
||||
[0, a[1, 0], 0],
|
||||
[0, 0, a[2, 0]],
|
||||
])
|
||||
assert expr.doit() == result
|
||||
expr = DiagMatrix(a.T)
|
||||
assert expr.doit() == result
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
from sympy.core.expr import unchanged
|
||||
from sympy.core.mul import Mul
|
||||
from sympy.matrices import Matrix
|
||||
from sympy.matrices.expressions.matexpr import MatrixSymbol
|
||||
from sympy.matrices.expressions.dotproduct import DotProduct
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
A = Matrix(3, 1, [1, 2, 3])
|
||||
B = Matrix(3, 1, [1, 3, 5])
|
||||
C = Matrix(4, 1, [1, 2, 4, 5])
|
||||
D = Matrix(2, 2, [1, 2, 3, 4])
|
||||
|
||||
def test_docproduct():
|
||||
assert DotProduct(A, B).doit() == 22
|
||||
assert DotProduct(A.T, B).doit() == 22
|
||||
assert DotProduct(A, B.T).doit() == 22
|
||||
assert DotProduct(A.T, B.T).doit() == 22
|
||||
|
||||
raises(TypeError, lambda: DotProduct(1, A))
|
||||
raises(TypeError, lambda: DotProduct(A, 1))
|
||||
raises(TypeError, lambda: DotProduct(A, D))
|
||||
raises(TypeError, lambda: DotProduct(D, A))
|
||||
|
||||
raises(TypeError, lambda: DotProduct(B, C).doit())
|
||||
|
||||
def test_dotproduct_symbolic():
|
||||
A = MatrixSymbol('A', 3, 1)
|
||||
B = MatrixSymbol('B', 3, 1)
|
||||
|
||||
dot = DotProduct(A, B)
|
||||
assert dot.is_scalar == True
|
||||
assert unchanged(Mul, 2, dot)
|
||||
# XXX Fix forced evaluation for arithmetics with matrix expressions
|
||||
assert dot * A == (A[0, 0]*B[0, 0] + A[1, 0]*B[1, 0] + A[2, 0]*B[2, 0])*A
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
from sympy.matrices.expressions.factorizations import lu, LofCholesky, qr, svd
|
||||
from sympy.assumptions.ask import (Q, ask)
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.matrices.expressions.matexpr import MatrixSymbol
|
||||
|
||||
n = Symbol('n')
|
||||
X = MatrixSymbol('X', n, n)
|
||||
|
||||
def test_LU():
|
||||
L, U = lu(X)
|
||||
assert L.shape == U.shape == X.shape
|
||||
assert ask(Q.lower_triangular(L))
|
||||
assert ask(Q.upper_triangular(U))
|
||||
|
||||
def test_Cholesky():
|
||||
LofCholesky(X)
|
||||
|
||||
def test_QR():
|
||||
Q_, R = qr(X)
|
||||
assert Q_.shape == R.shape == X.shape
|
||||
assert ask(Q.orthogonal(Q_))
|
||||
assert ask(Q.upper_triangular(R))
|
||||
|
||||
def test_svd():
|
||||
U, S, V = svd(X)
|
||||
assert U.shape == S.shape == V.shape == X.shape
|
||||
assert ask(Q.orthogonal(U))
|
||||
assert ask(Q.orthogonal(V))
|
||||
assert ask(Q.diagonal(S))
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
from sympy.assumptions.ask import (Q, ask)
|
||||
from sympy.core.numbers import (I, Rational)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.functions.elementary.complexes import Abs
|
||||
from sympy.functions.elementary.exponential import exp
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.simplify.simplify import simplify
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.matrices.expressions.fourier import DFT, IDFT
|
||||
from sympy.matrices import det, Matrix, Identity
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
def test_dft_creation():
|
||||
assert DFT(2)
|
||||
assert DFT(0)
|
||||
raises(ValueError, lambda: DFT(-1))
|
||||
raises(ValueError, lambda: DFT(2.0))
|
||||
raises(ValueError, lambda: DFT(2 + 1j))
|
||||
|
||||
n = symbols('n')
|
||||
assert DFT(n)
|
||||
n = symbols('n', integer=False)
|
||||
raises(ValueError, lambda: DFT(n))
|
||||
n = symbols('n', negative=True)
|
||||
raises(ValueError, lambda: DFT(n))
|
||||
|
||||
|
||||
def test_dft():
|
||||
n, i, j = symbols('n i j')
|
||||
assert DFT(4).shape == (4, 4)
|
||||
assert ask(Q.unitary(DFT(4)))
|
||||
assert Abs(simplify(det(Matrix(DFT(4))))) == 1
|
||||
assert DFT(n)*IDFT(n) == Identity(n)
|
||||
assert DFT(n)[i, j] == exp(-2*S.Pi*I/n)**(i*j) / sqrt(n)
|
||||
|
||||
|
||||
def test_dft2():
|
||||
assert DFT(1).as_explicit() == Matrix([[1]])
|
||||
assert DFT(2).as_explicit() == 1/sqrt(2)*Matrix([[1,1],[1,-1]])
|
||||
assert DFT(4).as_explicit() == Matrix([[S.Half, S.Half, S.Half, S.Half],
|
||||
[S.Half, -I/2, Rational(-1,2), I/2],
|
||||
[S.Half, Rational(-1,2), S.Half, Rational(-1,2)],
|
||||
[S.Half, I/2, Rational(-1,2), -I/2]])
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
from sympy.core import symbols, Lambda
|
||||
from sympy.core.sympify import SympifyError
|
||||
from sympy.functions import KroneckerDelta
|
||||
from sympy.matrices import Matrix
|
||||
from sympy.matrices.expressions import FunctionMatrix, MatrixExpr, Identity
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
def test_funcmatrix_creation():
|
||||
i, j, k = symbols('i j k')
|
||||
assert FunctionMatrix(2, 2, Lambda((i, j), 0))
|
||||
assert FunctionMatrix(0, 0, Lambda((i, j), 0))
|
||||
|
||||
raises(ValueError, lambda: FunctionMatrix(-1, 0, Lambda((i, j), 0)))
|
||||
raises(ValueError, lambda: FunctionMatrix(2.0, 0, Lambda((i, j), 0)))
|
||||
raises(ValueError, lambda: FunctionMatrix(2j, 0, Lambda((i, j), 0)))
|
||||
raises(ValueError, lambda: FunctionMatrix(0, -1, Lambda((i, j), 0)))
|
||||
raises(ValueError, lambda: FunctionMatrix(0, 2.0, Lambda((i, j), 0)))
|
||||
raises(ValueError, lambda: FunctionMatrix(0, 2j, Lambda((i, j), 0)))
|
||||
|
||||
raises(ValueError, lambda: FunctionMatrix(2, 2, Lambda(i, 0)))
|
||||
raises(SympifyError, lambda: FunctionMatrix(2, 2, lambda i, j: 0))
|
||||
raises(ValueError, lambda: FunctionMatrix(2, 2, Lambda((i,), 0)))
|
||||
raises(ValueError, lambda: FunctionMatrix(2, 2, Lambda((i, j, k), 0)))
|
||||
raises(ValueError, lambda: FunctionMatrix(2, 2, i+j))
|
||||
assert FunctionMatrix(2, 2, "lambda i, j: 0") == \
|
||||
FunctionMatrix(2, 2, Lambda((i, j), 0))
|
||||
|
||||
m = FunctionMatrix(2, 2, KroneckerDelta)
|
||||
assert m.as_explicit() == Identity(2).as_explicit()
|
||||
assert m.args[2].dummy_eq(Lambda((i, j), KroneckerDelta(i, j)))
|
||||
|
||||
n = symbols('n')
|
||||
assert FunctionMatrix(n, n, Lambda((i, j), 0))
|
||||
n = symbols('n', integer=False)
|
||||
raises(ValueError, lambda: FunctionMatrix(n, n, Lambda((i, j), 0)))
|
||||
n = symbols('n', negative=True)
|
||||
raises(ValueError, lambda: FunctionMatrix(n, n, Lambda((i, j), 0)))
|
||||
|
||||
|
||||
def test_funcmatrix():
|
||||
i, j = symbols('i,j')
|
||||
X = FunctionMatrix(3, 3, Lambda((i, j), i - j))
|
||||
assert X[1, 1] == 0
|
||||
assert X[1, 2] == -1
|
||||
assert X.shape == (3, 3)
|
||||
assert X.rows == X.cols == 3
|
||||
assert Matrix(X) == Matrix(3, 3, lambda i, j: i - j)
|
||||
assert isinstance(X*X + X, MatrixExpr)
|
||||
|
||||
|
||||
def test_replace_issue():
|
||||
X = FunctionMatrix(3, 3, KroneckerDelta)
|
||||
assert X.replace(lambda x: True, lambda x: x) == X
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
from sympy.matrices.dense import Matrix, eye
|
||||
from sympy.matrices.exceptions import ShapeError
|
||||
from sympy.matrices.expressions.matadd import MatAdd
|
||||
from sympy.matrices.expressions.special import Identity, OneMatrix, ZeroMatrix
|
||||
from sympy.core import symbols
|
||||
from sympy.testing.pytest import raises, warns_deprecated_sympy
|
||||
|
||||
from sympy.matrices import MatrixSymbol
|
||||
from sympy.matrices.expressions import (HadamardProduct, hadamard_product, HadamardPower, hadamard_power)
|
||||
|
||||
n, m, k = symbols('n,m,k')
|
||||
Z = MatrixSymbol('Z', n, n)
|
||||
A = MatrixSymbol('A', n, m)
|
||||
B = MatrixSymbol('B', n, m)
|
||||
C = MatrixSymbol('C', m, k)
|
||||
|
||||
|
||||
def test_HadamardProduct():
|
||||
assert HadamardProduct(A, B, A).shape == A.shape
|
||||
|
||||
raises(TypeError, lambda: HadamardProduct(A, n))
|
||||
raises(TypeError, lambda: HadamardProduct(A, 1))
|
||||
|
||||
assert HadamardProduct(A, 2*B, -A)[1, 1] == \
|
||||
-2 * A[1, 1] * B[1, 1] * A[1, 1]
|
||||
|
||||
mix = HadamardProduct(Z*A, B)*C
|
||||
assert mix.shape == (n, k)
|
||||
|
||||
assert set(HadamardProduct(A, B, A).T.args) == {A.T, A.T, B.T}
|
||||
|
||||
|
||||
def test_HadamardProduct_isnt_commutative():
|
||||
assert HadamardProduct(A, B) != HadamardProduct(B, A)
|
||||
|
||||
|
||||
def test_mixed_indexing():
|
||||
X = MatrixSymbol('X', 2, 2)
|
||||
Y = MatrixSymbol('Y', 2, 2)
|
||||
Z = MatrixSymbol('Z', 2, 2)
|
||||
|
||||
assert (X*HadamardProduct(Y, Z))[0, 0] == \
|
||||
X[0, 0]*Y[0, 0]*Z[0, 0] + X[0, 1]*Y[1, 0]*Z[1, 0]
|
||||
|
||||
|
||||
def test_canonicalize():
|
||||
X = MatrixSymbol('X', 2, 2)
|
||||
Y = MatrixSymbol('Y', 2, 2)
|
||||
with warns_deprecated_sympy():
|
||||
expr = HadamardProduct(X, check=False)
|
||||
assert isinstance(expr, HadamardProduct)
|
||||
expr2 = expr.doit() # unpack is called
|
||||
assert isinstance(expr2, MatrixSymbol)
|
||||
Z = ZeroMatrix(2, 2)
|
||||
U = OneMatrix(2, 2)
|
||||
assert HadamardProduct(Z, X).doit() == Z
|
||||
assert HadamardProduct(U, X, X, U).doit() == HadamardPower(X, 2)
|
||||
assert HadamardProduct(X, U, Y).doit() == HadamardProduct(X, Y)
|
||||
assert HadamardProduct(X, Z, U, Y).doit() == Z
|
||||
|
||||
|
||||
def test_hadamard():
|
||||
m, n, p = symbols('m, n, p', integer=True)
|
||||
A = MatrixSymbol('A', m, n)
|
||||
B = MatrixSymbol('B', m, n)
|
||||
X = MatrixSymbol('X', m, m)
|
||||
I = Identity(m)
|
||||
|
||||
raises(TypeError, lambda: hadamard_product())
|
||||
assert hadamard_product(A) == A
|
||||
assert isinstance(hadamard_product(A, B), HadamardProduct)
|
||||
assert hadamard_product(A, B).doit() == hadamard_product(A, B)
|
||||
assert hadamard_product(X, I) == HadamardProduct(I, X)
|
||||
assert isinstance(hadamard_product(X, I), HadamardProduct)
|
||||
|
||||
a = MatrixSymbol("a", k, 1)
|
||||
expr = MatAdd(ZeroMatrix(k, 1), OneMatrix(k, 1))
|
||||
expr = HadamardProduct(expr, a)
|
||||
assert expr.doit() == a
|
||||
|
||||
raises(ValueError, lambda: HadamardProduct())
|
||||
|
||||
|
||||
def test_hadamard_product_with_explicit_mat():
|
||||
A = MatrixSymbol("A", 3, 3).as_explicit()
|
||||
B = MatrixSymbol("B", 3, 3).as_explicit()
|
||||
X = MatrixSymbol("X", 3, 3)
|
||||
expr = hadamard_product(A, B)
|
||||
ret = Matrix([i*j for i, j in zip(A, B)]).reshape(3, 3)
|
||||
assert expr == ret
|
||||
expr = hadamard_product(A, X, B)
|
||||
assert expr == HadamardProduct(ret, X)
|
||||
expr = hadamard_product(eye(3), A)
|
||||
assert expr == Matrix([[A[0, 0], 0, 0], [0, A[1, 1], 0], [0, 0, A[2, 2]]])
|
||||
expr = hadamard_product(eye(3), eye(3))
|
||||
assert expr == eye(3)
|
||||
|
||||
|
||||
def test_hadamard_power():
|
||||
m, n, p = symbols('m, n, p', integer=True)
|
||||
A = MatrixSymbol('A', m, n)
|
||||
|
||||
assert hadamard_power(A, 1) == A
|
||||
assert isinstance(hadamard_power(A, 2), HadamardPower)
|
||||
assert hadamard_power(A, n).T == hadamard_power(A.T, n)
|
||||
assert hadamard_power(A, n)[0, 0] == A[0, 0]**n
|
||||
assert hadamard_power(m, n) == m**n
|
||||
raises(ValueError, lambda: hadamard_power(A, A))
|
||||
|
||||
|
||||
def test_hadamard_power_explicit():
|
||||
A = MatrixSymbol('A', 2, 2)
|
||||
B = MatrixSymbol('B', 2, 2)
|
||||
a, b = symbols('a b')
|
||||
|
||||
assert HadamardPower(a, b) == a**b
|
||||
|
||||
assert HadamardPower(a, B).as_explicit() == \
|
||||
Matrix([
|
||||
[a**B[0, 0], a**B[0, 1]],
|
||||
[a**B[1, 0], a**B[1, 1]]])
|
||||
|
||||
assert HadamardPower(A, b).as_explicit() == \
|
||||
Matrix([
|
||||
[A[0, 0]**b, A[0, 1]**b],
|
||||
[A[1, 0]**b, A[1, 1]**b]])
|
||||
|
||||
assert HadamardPower(A, B).as_explicit() == \
|
||||
Matrix([
|
||||
[A[0, 0]**B[0, 0], A[0, 1]**B[0, 1]],
|
||||
[A[1, 0]**B[1, 0], A[1, 1]**B[1, 1]]])
|
||||
|
||||
|
||||
def test_shape_error():
|
||||
A = MatrixSymbol('A', 2, 3)
|
||||
B = MatrixSymbol('B', 3, 3)
|
||||
raises(ShapeError, lambda: HadamardProduct(A, B))
|
||||
raises(ShapeError, lambda: HadamardPower(A, B))
|
||||
A = MatrixSymbol('A', 3, 2)
|
||||
raises(ShapeError, lambda: HadamardProduct(A, B))
|
||||
raises(ShapeError, lambda: HadamardPower(A, B))
|
||||
|
|
@ -0,0 +1,299 @@
|
|||
from sympy.concrete.summations import Sum
|
||||
from sympy.core.symbol import symbols, Symbol, Dummy
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.special.tensor_functions import KroneckerDelta
|
||||
from sympy.matrices.dense import eye
|
||||
from sympy.matrices.expressions.blockmatrix import BlockMatrix
|
||||
from sympy.matrices.expressions.hadamard import HadamardPower
|
||||
from sympy.matrices.expressions.matexpr import (MatrixSymbol,
|
||||
MatrixExpr, MatrixElement)
|
||||
from sympy.matrices.expressions.matpow import MatPow
|
||||
from sympy.matrices.expressions.special import (ZeroMatrix, Identity,
|
||||
OneMatrix)
|
||||
from sympy.matrices.expressions.trace import Trace, trace
|
||||
from sympy.matrices.immutable import ImmutableMatrix
|
||||
from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct
|
||||
from sympy.testing.pytest import XFAIL, raises
|
||||
|
||||
k, l, m, n = symbols('k l m n', integer=True)
|
||||
i, j = symbols('i j', integer=True)
|
||||
|
||||
W = MatrixSymbol('W', k, l)
|
||||
X = MatrixSymbol('X', l, m)
|
||||
Y = MatrixSymbol('Y', l, m)
|
||||
Z = MatrixSymbol('Z', m, n)
|
||||
|
||||
X1 = MatrixSymbol('X1', m, m)
|
||||
X2 = MatrixSymbol('X2', m, m)
|
||||
X3 = MatrixSymbol('X3', m, m)
|
||||
X4 = MatrixSymbol('X4', m, m)
|
||||
|
||||
A = MatrixSymbol('A', 2, 2)
|
||||
B = MatrixSymbol('B', 2, 2)
|
||||
x = MatrixSymbol('x', 1, 2)
|
||||
y = MatrixSymbol('x', 2, 1)
|
||||
|
||||
|
||||
def test_symbolic_indexing():
|
||||
x12 = X[1, 2]
|
||||
assert all(s in str(x12) for s in ['1', '2', X.name])
|
||||
# We don't care about the exact form of this. We do want to make sure
|
||||
# that all of these features are present
|
||||
|
||||
|
||||
def test_add_index():
|
||||
assert (X + Y)[i, j] == X[i, j] + Y[i, j]
|
||||
|
||||
|
||||
def test_mul_index():
|
||||
assert (A*y)[0, 0] == A[0, 0]*y[0, 0] + A[0, 1]*y[1, 0]
|
||||
assert (A*B).as_mutable() == (A.as_mutable() * B.as_mutable())
|
||||
X = MatrixSymbol('X', n, m)
|
||||
Y = MatrixSymbol('Y', m, k)
|
||||
|
||||
result = (X*Y)[4,2]
|
||||
expected = Sum(X[4, i]*Y[i, 2], (i, 0, m - 1))
|
||||
assert result.args[0].dummy_eq(expected.args[0], i)
|
||||
assert result.args[1][1:] == expected.args[1][1:]
|
||||
|
||||
|
||||
def test_pow_index():
|
||||
Q = MatPow(A, 2)
|
||||
assert Q[0, 0] == A[0, 0]**2 + A[0, 1]*A[1, 0]
|
||||
n = symbols("n")
|
||||
Q2 = A**n
|
||||
assert Q2[0, 0] == 2*(
|
||||
-sqrt((A[0, 0] + A[1, 1])**2 - 4*A[0, 0]*A[1, 1] +
|
||||
4*A[0, 1]*A[1, 0])/2 + A[0, 0]/2 + A[1, 1]/2
|
||||
)**n * \
|
||||
A[0, 1]*A[1, 0]/(
|
||||
(sqrt(A[0, 0]**2 - 2*A[0, 0]*A[1, 1] + 4*A[0, 1]*A[1, 0] +
|
||||
A[1, 1]**2) + A[0, 0] - A[1, 1])*
|
||||
sqrt(A[0, 0]**2 - 2*A[0, 0]*A[1, 1] + 4*A[0, 1]*A[1, 0] + A[1, 1]**2)
|
||||
) - 2*(
|
||||
sqrt((A[0, 0] + A[1, 1])**2 - 4*A[0, 0]*A[1, 1] +
|
||||
4*A[0, 1]*A[1, 0])/2 + A[0, 0]/2 + A[1, 1]/2
|
||||
)**n * A[0, 1]*A[1, 0]/(
|
||||
(-sqrt(A[0, 0]**2 - 2*A[0, 0]*A[1, 1] + 4*A[0, 1]*A[1, 0] +
|
||||
A[1, 1]**2) + A[0, 0] - A[1, 1])*
|
||||
sqrt(A[0, 0]**2 - 2*A[0, 0]*A[1, 1] + 4*A[0, 1]*A[1, 0] + A[1, 1]**2)
|
||||
)
|
||||
|
||||
|
||||
def test_transpose_index():
|
||||
assert X.T[i, j] == X[j, i]
|
||||
|
||||
|
||||
def test_Identity_index():
|
||||
I = Identity(3)
|
||||
assert I[0, 0] == I[1, 1] == I[2, 2] == 1
|
||||
assert I[1, 0] == I[0, 1] == I[2, 1] == 0
|
||||
assert I[i, 0].delta_range == (0, 2)
|
||||
raises(IndexError, lambda: I[3, 3])
|
||||
|
||||
|
||||
def test_block_index():
|
||||
I = Identity(3)
|
||||
Z = ZeroMatrix(3, 3)
|
||||
B = BlockMatrix([[I, I], [I, I]])
|
||||
e3 = ImmutableMatrix(eye(3))
|
||||
BB = BlockMatrix([[e3, e3], [e3, e3]])
|
||||
assert B[0, 0] == B[3, 0] == B[0, 3] == B[3, 3] == 1
|
||||
assert B[4, 3] == B[5, 1] == 0
|
||||
|
||||
BB = BlockMatrix([[e3, e3], [e3, e3]])
|
||||
assert B.as_explicit() == BB.as_explicit()
|
||||
|
||||
BI = BlockMatrix([[I, Z], [Z, I]])
|
||||
|
||||
assert BI.as_explicit().equals(eye(6))
|
||||
|
||||
|
||||
def test_block_index_symbolic():
|
||||
# Note that these matrices may be zero-sized and indices may be negative, which causes
|
||||
# all naive simplifications given in the comments to be invalid
|
||||
A1 = MatrixSymbol('A1', n, k)
|
||||
A2 = MatrixSymbol('A2', n, l)
|
||||
A3 = MatrixSymbol('A3', m, k)
|
||||
A4 = MatrixSymbol('A4', m, l)
|
||||
A = BlockMatrix([[A1, A2], [A3, A4]])
|
||||
assert A[0, 0] == MatrixElement(A, 0, 0) # Cannot be A1[0, 0]
|
||||
assert A[n - 1, k - 1] == A1[n - 1, k - 1]
|
||||
assert A[n, k] == A4[0, 0]
|
||||
assert A[n + m - 1, 0] == MatrixElement(A, n + m - 1, 0) # Cannot be A3[m - 1, 0]
|
||||
assert A[0, k + l - 1] == MatrixElement(A, 0, k + l - 1) # Cannot be A2[0, l - 1]
|
||||
assert A[n + m - 1, k + l - 1] == MatrixElement(A, n + m - 1, k + l - 1) # Cannot be A4[m - 1, l - 1]
|
||||
assert A[i, j] == MatrixElement(A, i, j)
|
||||
assert A[n + i, k + j] == MatrixElement(A, n + i, k + j) # Cannot be A4[i, j]
|
||||
assert A[n - i - 1, k - j - 1] == MatrixElement(A, n - i - 1, k - j - 1) # Cannot be A1[n - i - 1, k - j - 1]
|
||||
|
||||
|
||||
def test_block_index_symbolic_nonzero():
|
||||
# All invalid simplifications from test_block_index_symbolic() that become valid if all
|
||||
# matrices have nonzero size and all indices are nonnegative
|
||||
k, l, m, n = symbols('k l m n', integer=True, positive=True)
|
||||
i, j = symbols('i j', integer=True, nonnegative=True)
|
||||
A1 = MatrixSymbol('A1', n, k)
|
||||
A2 = MatrixSymbol('A2', n, l)
|
||||
A3 = MatrixSymbol('A3', m, k)
|
||||
A4 = MatrixSymbol('A4', m, l)
|
||||
A = BlockMatrix([[A1, A2], [A3, A4]])
|
||||
assert A[0, 0] == A1[0, 0]
|
||||
assert A[n + m - 1, 0] == A3[m - 1, 0]
|
||||
assert A[0, k + l - 1] == A2[0, l - 1]
|
||||
assert A[n + m - 1, k + l - 1] == A4[m - 1, l - 1]
|
||||
assert A[i, j] == MatrixElement(A, i, j)
|
||||
assert A[n + i, k + j] == A4[i, j]
|
||||
assert A[n - i - 1, k - j - 1] == A1[n - i - 1, k - j - 1]
|
||||
assert A[2 * n, 2 * k] == A4[n, k]
|
||||
|
||||
|
||||
def test_block_index_large():
|
||||
n, m, k = symbols('n m k', integer=True, positive=True)
|
||||
i = symbols('i', integer=True, nonnegative=True)
|
||||
A1 = MatrixSymbol('A1', n, n)
|
||||
A2 = MatrixSymbol('A2', n, m)
|
||||
A3 = MatrixSymbol('A3', n, k)
|
||||
A4 = MatrixSymbol('A4', m, n)
|
||||
A5 = MatrixSymbol('A5', m, m)
|
||||
A6 = MatrixSymbol('A6', m, k)
|
||||
A7 = MatrixSymbol('A7', k, n)
|
||||
A8 = MatrixSymbol('A8', k, m)
|
||||
A9 = MatrixSymbol('A9', k, k)
|
||||
A = BlockMatrix([[A1, A2, A3], [A4, A5, A6], [A7, A8, A9]])
|
||||
assert A[n + i, n + i] == MatrixElement(A, n + i, n + i)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_block_index_symbolic_fail():
|
||||
# To make this work, symbolic matrix dimensions would need to be somehow assumed nonnegative
|
||||
# even if the symbols aren't specified as such. Then 2 * n < n would correctly evaluate to
|
||||
# False in BlockMatrix._entry()
|
||||
A1 = MatrixSymbol('A1', n, 1)
|
||||
A2 = MatrixSymbol('A2', m, 1)
|
||||
A = BlockMatrix([[A1], [A2]])
|
||||
assert A[2 * n, 0] == A2[n, 0]
|
||||
|
||||
|
||||
def test_slicing():
|
||||
A.as_explicit()[0, :] # does not raise an error
|
||||
|
||||
|
||||
def test_errors():
|
||||
raises(IndexError, lambda: Identity(2)[1, 2, 3, 4, 5])
|
||||
raises(IndexError, lambda: Identity(2)[[1, 2, 3, 4, 5]])
|
||||
|
||||
|
||||
def test_matrix_expression_to_indices():
|
||||
i, j = symbols("i, j")
|
||||
i1, i2, i3 = symbols("i_1:4")
|
||||
|
||||
def replace_dummies(expr):
|
||||
repl = {i: Symbol(i.name) for i in expr.atoms(Dummy)}
|
||||
return expr.xreplace(repl)
|
||||
|
||||
expr = W*X*Z
|
||||
assert replace_dummies(expr._entry(i, j)) == \
|
||||
Sum(W[i, i1]*X[i1, i2]*Z[i2, j], (i1, 0, l-1), (i2, 0, m-1))
|
||||
assert MatrixExpr.from_index_summation(expr._entry(i, j)) == expr
|
||||
|
||||
expr = Z.T*X.T*W.T
|
||||
assert replace_dummies(expr._entry(i, j)) == \
|
||||
Sum(W[j, i2]*X[i2, i1]*Z[i1, i], (i1, 0, m-1), (i2, 0, l-1))
|
||||
assert MatrixExpr.from_index_summation(expr._entry(i, j), i) == expr
|
||||
|
||||
expr = W*X*Z + W*Y*Z
|
||||
assert replace_dummies(expr._entry(i, j)) == \
|
||||
Sum(W[i, i1]*X[i1, i2]*Z[i2, j], (i1, 0, l-1), (i2, 0, m-1)) +\
|
||||
Sum(W[i, i1]*Y[i1, i2]*Z[i2, j], (i1, 0, l-1), (i2, 0, m-1))
|
||||
assert MatrixExpr.from_index_summation(expr._entry(i, j)) == expr
|
||||
|
||||
expr = 2*W*X*Z + 3*W*Y*Z
|
||||
assert replace_dummies(expr._entry(i, j)) == \
|
||||
2*Sum(W[i, i1]*X[i1, i2]*Z[i2, j], (i1, 0, l-1), (i2, 0, m-1)) +\
|
||||
3*Sum(W[i, i1]*Y[i1, i2]*Z[i2, j], (i1, 0, l-1), (i2, 0, m-1))
|
||||
assert MatrixExpr.from_index_summation(expr._entry(i, j)) == expr
|
||||
|
||||
expr = W*(X + Y)*Z
|
||||
assert replace_dummies(expr._entry(i, j)) == \
|
||||
Sum(W[i, i1]*(X[i1, i2] + Y[i1, i2])*Z[i2, j], (i1, 0, l-1), (i2, 0, m-1))
|
||||
assert MatrixExpr.from_index_summation(expr._entry(i, j)) == expr
|
||||
|
||||
expr = A*B**2*A
|
||||
#assert replace_dummies(expr._entry(i, j)) == \
|
||||
# Sum(A[i, i1]*B[i1, i2]*B[i2, i3]*A[i3, j], (i1, 0, 1), (i2, 0, 1), (i3, 0, 1))
|
||||
|
||||
# Check that different dummies are used in sub-multiplications:
|
||||
expr = (X1*X2 + X2*X1)*X3
|
||||
assert replace_dummies(expr._entry(i, j)) == \
|
||||
Sum((Sum(X1[i, i2] * X2[i2, i1], (i2, 0, m - 1)) + Sum(X1[i3, i1] * X2[i, i3], (i3, 0, m - 1))) * X3[
|
||||
i1, j], (i1, 0, m - 1))
|
||||
|
||||
|
||||
def test_matrix_expression_from_index_summation():
|
||||
from sympy.abc import a,b,c,d
|
||||
A = MatrixSymbol("A", k, k)
|
||||
B = MatrixSymbol("B", k, k)
|
||||
C = MatrixSymbol("C", k, k)
|
||||
w1 = MatrixSymbol("w1", k, 1)
|
||||
|
||||
i0, i1, i2, i3, i4 = symbols("i0:5", cls=Dummy)
|
||||
|
||||
expr = Sum(W[a,b]*X[b,c]*Z[c,d], (b, 0, l-1), (c, 0, m-1))
|
||||
assert MatrixExpr.from_index_summation(expr, a) == W*X*Z
|
||||
expr = Sum(W.T[b,a]*X[b,c]*Z[c,d], (b, 0, l-1), (c, 0, m-1))
|
||||
assert MatrixExpr.from_index_summation(expr, a) == W*X*Z
|
||||
expr = Sum(A[b, a]*B[b, c]*C[c, d], (b, 0, k-1), (c, 0, k-1))
|
||||
assert MatrixSymbol.from_index_summation(expr, a) == A.T*B*C
|
||||
expr = Sum(A[b, a]*B[c, b]*C[c, d], (b, 0, k-1), (c, 0, k-1))
|
||||
assert MatrixSymbol.from_index_summation(expr, a) == A.T*B.T*C
|
||||
expr = Sum(C[c, d]*A[b, a]*B[c, b], (b, 0, k-1), (c, 0, k-1))
|
||||
assert MatrixSymbol.from_index_summation(expr, a) == A.T*B.T*C
|
||||
expr = Sum(A[a, b] + B[a, b], (a, 0, k-1), (b, 0, k-1))
|
||||
assert MatrixExpr.from_index_summation(expr, a) == OneMatrix(1, k)*A*OneMatrix(k, 1) + OneMatrix(1, k)*B*OneMatrix(k, 1)
|
||||
expr = Sum(A[a, b]**2, (a, 0, k - 1), (b, 0, k - 1))
|
||||
assert MatrixExpr.from_index_summation(expr, a) == Trace(A * A.T)
|
||||
expr = Sum(A[a, b]**3, (a, 0, k - 1), (b, 0, k - 1))
|
||||
assert MatrixExpr.from_index_summation(expr, a) == Trace(HadamardPower(A.T, 2) * A)
|
||||
expr = Sum((A[a, b] + B[a, b])*C[b, c], (b, 0, k-1))
|
||||
assert MatrixExpr.from_index_summation(expr, a) == (A+B)*C
|
||||
expr = Sum((A[a, b] + B[b, a])*C[b, c], (b, 0, k-1))
|
||||
assert MatrixExpr.from_index_summation(expr, a) == (A+B.T)*C
|
||||
expr = Sum(A[a, b]*A[b, c]*A[c, d], (b, 0, k-1), (c, 0, k-1))
|
||||
assert MatrixExpr.from_index_summation(expr, a) == A**3
|
||||
expr = Sum(A[a, b]*A[b, c]*B[c, d], (b, 0, k-1), (c, 0, k-1))
|
||||
assert MatrixExpr.from_index_summation(expr, a) == A**2*B
|
||||
|
||||
# Parse the trace of a matrix:
|
||||
|
||||
expr = Sum(A[a, a], (a, 0, k-1))
|
||||
assert MatrixExpr.from_index_summation(expr, None) == trace(A)
|
||||
expr = Sum(A[a, a]*B[b, c]*C[c, d], (a, 0, k-1), (c, 0, k-1))
|
||||
assert MatrixExpr.from_index_summation(expr, b) == trace(A)*B*C
|
||||
|
||||
# Check wrong sum ranges (should raise an exception):
|
||||
|
||||
## Case 1: 0 to m instead of 0 to m-1
|
||||
expr = Sum(W[a,b]*X[b,c]*Z[c,d], (b, 0, l-1), (c, 0, m))
|
||||
raises(ValueError, lambda: MatrixExpr.from_index_summation(expr, a))
|
||||
## Case 2: 1 to m-1 instead of 0 to m-1
|
||||
expr = Sum(W[a,b]*X[b,c]*Z[c,d], (b, 0, l-1), (c, 1, m-1))
|
||||
raises(ValueError, lambda: MatrixExpr.from_index_summation(expr, a))
|
||||
|
||||
# Parse nested sums:
|
||||
expr = Sum(A[a, b]*Sum(B[b, c]*C[c, d], (c, 0, k-1)), (b, 0, k-1))
|
||||
assert MatrixExpr.from_index_summation(expr, a) == A*B*C
|
||||
|
||||
# Test Kronecker delta:
|
||||
expr = Sum(A[a, b]*KroneckerDelta(b, c)*B[c, d], (b, 0, k-1), (c, 0, k-1))
|
||||
assert MatrixExpr.from_index_summation(expr, a) == A*B
|
||||
|
||||
expr = Sum(KroneckerDelta(i1, m)*KroneckerDelta(i2, n)*A[i, i1]*A[j, i2], (i1, 0, k-1), (i2, 0, k-1))
|
||||
assert MatrixExpr.from_index_summation(expr, m) == ArrayTensorProduct(A.T, A)
|
||||
|
||||
# Test numbered indices:
|
||||
expr = Sum(A[i1, i2]*w1[i2, 0], (i2, 0, k-1))
|
||||
assert MatrixExpr.from_index_summation(expr, i1) == MatrixElement(A*w1, i1, 0)
|
||||
|
||||
expr = Sum(A[i1, i2]*B[i2, 0], (i2, 0, k-1))
|
||||
assert MatrixExpr.from_index_summation(expr, i1) == MatrixElement(A*B, i1, 0)
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
from sympy.core import symbols, S
|
||||
from sympy.matrices.expressions import MatrixSymbol, Inverse, MatPow, ZeroMatrix, OneMatrix
|
||||
from sympy.matrices.exceptions import NonInvertibleMatrixError, NonSquareMatrixError
|
||||
from sympy.matrices import eye, Identity
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.assumptions.ask import Q
|
||||
from sympy.assumptions.refine import refine
|
||||
|
||||
n, m, l = symbols('n m l', integer=True)
|
||||
A = MatrixSymbol('A', n, m)
|
||||
B = MatrixSymbol('B', m, l)
|
||||
C = MatrixSymbol('C', n, n)
|
||||
D = MatrixSymbol('D', n, n)
|
||||
E = MatrixSymbol('E', m, n)
|
||||
|
||||
|
||||
def test_inverse():
|
||||
assert Inverse(C).args == (C, S.NegativeOne)
|
||||
assert Inverse(C).shape == (n, n)
|
||||
assert Inverse(A*E).shape == (n, n)
|
||||
assert Inverse(E*A).shape == (m, m)
|
||||
assert Inverse(C).inverse() == C
|
||||
assert Inverse(Inverse(C)).doit() == C
|
||||
assert isinstance(Inverse(Inverse(C)), Inverse)
|
||||
|
||||
assert Inverse(*Inverse(E*A).args) == Inverse(E*A)
|
||||
|
||||
assert C.inverse().inverse() == C
|
||||
|
||||
assert C.inverse()*C == Identity(C.rows)
|
||||
|
||||
assert Identity(n).inverse() == Identity(n)
|
||||
assert (3*Identity(n)).inverse() == Identity(n)/3
|
||||
|
||||
# Simplifies Muls if possible (i.e. submatrices are square)
|
||||
assert (C*D).inverse() == D.I*C.I
|
||||
# But still works when not possible
|
||||
assert isinstance((A*E).inverse(), Inverse)
|
||||
assert Inverse(C*D).doit(inv_expand=False) == Inverse(C*D)
|
||||
|
||||
assert Inverse(eye(3)).doit() == eye(3)
|
||||
assert Inverse(eye(3)).doit(deep=False) == eye(3)
|
||||
|
||||
assert OneMatrix(1, 1).I == Identity(1)
|
||||
assert isinstance(OneMatrix(n, n).I, Inverse)
|
||||
|
||||
def test_inverse_non_invertible():
|
||||
raises(NonInvertibleMatrixError, lambda: ZeroMatrix(n, n).I)
|
||||
raises(NonInvertibleMatrixError, lambda: OneMatrix(2, 2).I)
|
||||
|
||||
def test_refine():
|
||||
assert refine(C.I, Q.orthogonal(C)) == C.T
|
||||
|
||||
|
||||
def test_inverse_matpow_canonicalization():
|
||||
A = MatrixSymbol('A', 3, 3)
|
||||
assert Inverse(MatPow(A, 3)).doit() == MatPow(Inverse(A), 3).doit()
|
||||
|
||||
|
||||
def test_nonsquare_error():
|
||||
A = MatrixSymbol('A', 3, 4)
|
||||
raises(NonSquareMatrixError, lambda: Inverse(A))
|
||||
|
||||
|
||||
def test_adjoint_trnaspose_conjugate():
|
||||
A = MatrixSymbol('A', n, n)
|
||||
assert A.transpose().inverse() == A.inverse().transpose()
|
||||
assert A.conjugate().inverse() == A.inverse().conjugate()
|
||||
assert A.adjoint().inverse() == A.inverse().adjoint()
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
from sympy.core.mod import Mod
|
||||
from sympy.core.numbers import I
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.functions.elementary.integers import floor
|
||||
from sympy.matrices.dense import (Matrix, eye)
|
||||
from sympy.matrices import MatrixSymbol, Identity
|
||||
from sympy.matrices.expressions import det, trace
|
||||
|
||||
from sympy.matrices.expressions.kronecker import (KroneckerProduct,
|
||||
kronecker_product,
|
||||
combine_kronecker)
|
||||
|
||||
|
||||
mat1 = Matrix([[1, 2 * I], [1 + I, 3]])
|
||||
mat2 = Matrix([[2 * I, 3], [4 * I, 2]])
|
||||
|
||||
i, j, k, n, m, o, p, x = symbols('i,j,k,n,m,o,p,x')
|
||||
Z = MatrixSymbol('Z', n, n)
|
||||
W = MatrixSymbol('W', m, m)
|
||||
A = MatrixSymbol('A', n, m)
|
||||
B = MatrixSymbol('B', n, m)
|
||||
C = MatrixSymbol('C', m, k)
|
||||
|
||||
|
||||
def test_KroneckerProduct():
|
||||
assert isinstance(KroneckerProduct(A, B), KroneckerProduct)
|
||||
assert KroneckerProduct(A, B).subs(A, C) == KroneckerProduct(C, B)
|
||||
assert KroneckerProduct(A, C).shape == (n*m, m*k)
|
||||
assert (KroneckerProduct(A, C) + KroneckerProduct(-A, C)).is_ZeroMatrix
|
||||
assert (KroneckerProduct(W, Z) * KroneckerProduct(W.I, Z.I)).is_Identity
|
||||
|
||||
|
||||
def test_KroneckerProduct_identity():
|
||||
assert KroneckerProduct(Identity(m), Identity(n)) == Identity(m*n)
|
||||
assert KroneckerProduct(eye(2), eye(3)) == eye(6)
|
||||
|
||||
|
||||
def test_KroneckerProduct_explicit():
|
||||
X = MatrixSymbol('X', 2, 2)
|
||||
Y = MatrixSymbol('Y', 2, 2)
|
||||
kp = KroneckerProduct(X, Y)
|
||||
assert kp.shape == (4, 4)
|
||||
assert kp.as_explicit() == Matrix(
|
||||
[
|
||||
[X[0, 0]*Y[0, 0], X[0, 0]*Y[0, 1], X[0, 1]*Y[0, 0], X[0, 1]*Y[0, 1]],
|
||||
[X[0, 0]*Y[1, 0], X[0, 0]*Y[1, 1], X[0, 1]*Y[1, 0], X[0, 1]*Y[1, 1]],
|
||||
[X[1, 0]*Y[0, 0], X[1, 0]*Y[0, 1], X[1, 1]*Y[0, 0], X[1, 1]*Y[0, 1]],
|
||||
[X[1, 0]*Y[1, 0], X[1, 0]*Y[1, 1], X[1, 1]*Y[1, 0], X[1, 1]*Y[1, 1]]
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def test_tensor_product_adjoint():
|
||||
assert KroneckerProduct(I*A, B).adjoint() == \
|
||||
-I*KroneckerProduct(A.adjoint(), B.adjoint())
|
||||
assert KroneckerProduct(mat1, mat2).adjoint() == \
|
||||
kronecker_product(mat1.adjoint(), mat2.adjoint())
|
||||
|
||||
|
||||
def test_tensor_product_conjugate():
|
||||
assert KroneckerProduct(I*A, B).conjugate() == \
|
||||
-I*KroneckerProduct(A.conjugate(), B.conjugate())
|
||||
assert KroneckerProduct(mat1, mat2).conjugate() == \
|
||||
kronecker_product(mat1.conjugate(), mat2.conjugate())
|
||||
|
||||
|
||||
def test_tensor_product_transpose():
|
||||
assert KroneckerProduct(I*A, B).transpose() == \
|
||||
I*KroneckerProduct(A.transpose(), B.transpose())
|
||||
assert KroneckerProduct(mat1, mat2).transpose() == \
|
||||
kronecker_product(mat1.transpose(), mat2.transpose())
|
||||
|
||||
|
||||
def test_KroneckerProduct_is_associative():
|
||||
assert kronecker_product(A, kronecker_product(
|
||||
B, C)) == kronecker_product(kronecker_product(A, B), C)
|
||||
assert kronecker_product(A, kronecker_product(
|
||||
B, C)) == KroneckerProduct(A, B, C)
|
||||
|
||||
|
||||
def test_KroneckerProduct_is_bilinear():
|
||||
assert kronecker_product(x*A, B) == x*kronecker_product(A, B)
|
||||
assert kronecker_product(A, x*B) == x*kronecker_product(A, B)
|
||||
|
||||
|
||||
def test_KroneckerProduct_determinant():
|
||||
kp = kronecker_product(W, Z)
|
||||
assert det(kp) == det(W)**n * det(Z)**m
|
||||
|
||||
|
||||
def test_KroneckerProduct_trace():
|
||||
kp = kronecker_product(W, Z)
|
||||
assert trace(kp) == trace(W)*trace(Z)
|
||||
|
||||
|
||||
def test_KroneckerProduct_isnt_commutative():
|
||||
assert KroneckerProduct(A, B) != KroneckerProduct(B, A)
|
||||
assert KroneckerProduct(A, B).is_commutative is False
|
||||
|
||||
|
||||
def test_KroneckerProduct_extracts_commutative_part():
|
||||
assert kronecker_product(x * A, 2 * B) == x * \
|
||||
2 * KroneckerProduct(A, B)
|
||||
|
||||
|
||||
def test_KroneckerProduct_inverse():
|
||||
kp = kronecker_product(W, Z)
|
||||
assert kp.inverse() == kronecker_product(W.inverse(), Z.inverse())
|
||||
|
||||
|
||||
def test_KroneckerProduct_combine_add():
|
||||
kp1 = kronecker_product(A, B)
|
||||
kp2 = kronecker_product(C, W)
|
||||
assert combine_kronecker(kp1*kp2) == kronecker_product(A*C, B*W)
|
||||
|
||||
|
||||
def test_KroneckerProduct_combine_mul():
|
||||
X = MatrixSymbol('X', m, n)
|
||||
Y = MatrixSymbol('Y', m, n)
|
||||
kp1 = kronecker_product(A, X)
|
||||
kp2 = kronecker_product(B, Y)
|
||||
assert combine_kronecker(kp1+kp2) == kronecker_product(A+B, X+Y)
|
||||
|
||||
|
||||
def test_KroneckerProduct_combine_pow():
|
||||
X = MatrixSymbol('X', n, n)
|
||||
Y = MatrixSymbol('Y', n, n)
|
||||
assert combine_kronecker(KroneckerProduct(
|
||||
X, Y)**x) == KroneckerProduct(X**x, Y**x)
|
||||
assert combine_kronecker(x * KroneckerProduct(X, Y)
|
||||
** 2) == x * KroneckerProduct(X**2, Y**2)
|
||||
assert combine_kronecker(
|
||||
x * (KroneckerProduct(X, Y)**2) * KroneckerProduct(A, B)) == x * KroneckerProduct(X**2 * A, Y**2 * B)
|
||||
# cannot simplify because of non-square arguments to kronecker product:
|
||||
assert combine_kronecker(KroneckerProduct(A, B.T) ** m) == KroneckerProduct(A, B.T) ** m
|
||||
|
||||
|
||||
def test_KroneckerProduct_expand():
|
||||
X = MatrixSymbol('X', n, n)
|
||||
Y = MatrixSymbol('Y', n, n)
|
||||
|
||||
assert KroneckerProduct(X + Y, Y + Z).expand(kroneckerproduct=True) == \
|
||||
KroneckerProduct(X, Y) + KroneckerProduct(X, Z) + \
|
||||
KroneckerProduct(Y, Y) + KroneckerProduct(Y, Z)
|
||||
|
||||
def test_KroneckerProduct_entry():
|
||||
A = MatrixSymbol('A', n, m)
|
||||
B = MatrixSymbol('B', o, p)
|
||||
|
||||
assert KroneckerProduct(A, B)._entry(i, j) == A[Mod(floor(i/o), n), Mod(floor(j/p), m)]*B[Mod(i, o), Mod(j, p)]
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
from sympy.matrices.expressions import MatrixSymbol, MatAdd, MatPow, MatMul
|
||||
from sympy.matrices.expressions.special import GenericZeroMatrix, ZeroMatrix
|
||||
from sympy.matrices.exceptions import ShapeError
|
||||
from sympy.matrices import eye, ImmutableMatrix
|
||||
from sympy.core import Add, Basic, S
|
||||
from sympy.core.add import add
|
||||
from sympy.testing.pytest import XFAIL, raises
|
||||
|
||||
X = MatrixSymbol('X', 2, 2)
|
||||
Y = MatrixSymbol('Y', 2, 2)
|
||||
|
||||
def test_evaluate():
|
||||
assert MatAdd(X, X, evaluate=True) == add(X, X, evaluate=True) == MatAdd(X, X).doit()
|
||||
|
||||
def test_sort_key():
|
||||
assert MatAdd(Y, X).doit().args == add(Y, X).doit().args == (X, Y)
|
||||
|
||||
|
||||
def test_matadd_sympify():
|
||||
assert isinstance(MatAdd(eye(1), eye(1)).args[0], Basic)
|
||||
assert isinstance(add(eye(1), eye(1)).args[0], Basic)
|
||||
|
||||
|
||||
def test_matadd_of_matrices():
|
||||
assert MatAdd(eye(2), 4*eye(2), eye(2)).doit() == ImmutableMatrix(6*eye(2))
|
||||
assert add(eye(2), 4*eye(2), eye(2)).doit() == ImmutableMatrix(6*eye(2))
|
||||
|
||||
|
||||
def test_doit_args():
|
||||
A = ImmutableMatrix([[1, 2], [3, 4]])
|
||||
B = ImmutableMatrix([[2, 3], [4, 5]])
|
||||
assert MatAdd(A, MatPow(B, 2)).doit() == A + B**2
|
||||
assert MatAdd(A, MatMul(A, B)).doit() == A + A*B
|
||||
assert (MatAdd(A, X, MatMul(A, B), Y, MatAdd(2*A, B)).doit() ==
|
||||
add(A, X, MatMul(A, B), Y, add(2*A, B)).doit() ==
|
||||
MatAdd(3*A + A*B + B, X, Y))
|
||||
|
||||
|
||||
def test_generic_identity():
|
||||
assert MatAdd.identity == GenericZeroMatrix()
|
||||
assert MatAdd.identity != S.Zero
|
||||
|
||||
|
||||
def test_zero_matrix_add():
|
||||
assert Add(ZeroMatrix(2, 2), ZeroMatrix(2, 2)) == ZeroMatrix(2, 2)
|
||||
|
||||
@XFAIL
|
||||
def test_matrix_Add_with_scalar():
|
||||
raises(TypeError, lambda: Add(0, ZeroMatrix(2, 2)))
|
||||
|
||||
|
||||
def test_shape_error():
|
||||
A = MatrixSymbol('A', 2, 3)
|
||||
B = MatrixSymbol('B', 3, 3)
|
||||
raises(ShapeError, lambda: MatAdd(A, B))
|
||||
|
||||
A = MatrixSymbol('A', 3, 2)
|
||||
raises(ShapeError, lambda: MatAdd(A, B))
|
||||
|
|
@ -0,0 +1,592 @@
|
|||
from sympy.concrete.summations import Sum
|
||||
from sympy.core.exprtools import gcd_terms
|
||||
from sympy.core.function import (diff, expand)
|
||||
from sympy.core.relational import Eq
|
||||
from sympy.core.symbol import (Dummy, Symbol, Str)
|
||||
from sympy.functions.special.tensor_functions import KroneckerDelta
|
||||
from sympy.matrices.dense import zeros
|
||||
from sympy.polys.polytools import factor
|
||||
|
||||
from sympy.core import (S, symbols, Add, Mul, SympifyError, Rational,
|
||||
Function)
|
||||
from sympy.functions import sin, cos, tan, sqrt, cbrt, exp
|
||||
from sympy.simplify import simplify
|
||||
from sympy.matrices import (ImmutableMatrix, Inverse, MatAdd, MatMul,
|
||||
MatPow, Matrix, MatrixExpr, MatrixSymbol,
|
||||
SparseMatrix, Transpose, Adjoint, MatrixSet)
|
||||
from sympy.matrices.exceptions import NonSquareMatrixError
|
||||
from sympy.matrices.expressions.determinant import Determinant, det
|
||||
from sympy.matrices.expressions.matexpr import MatrixElement
|
||||
from sympy.matrices.expressions.special import ZeroMatrix, Identity
|
||||
from sympy.testing.pytest import raises, XFAIL, skip
|
||||
from importlib.metadata import version
|
||||
|
||||
n, m, l, k, p = symbols('n m l k p', integer=True)
|
||||
x = symbols('x')
|
||||
A = MatrixSymbol('A', n, m)
|
||||
B = MatrixSymbol('B', m, l)
|
||||
C = MatrixSymbol('C', n, n)
|
||||
D = MatrixSymbol('D', n, n)
|
||||
E = MatrixSymbol('E', m, n)
|
||||
w = MatrixSymbol('w', n, 1)
|
||||
|
||||
|
||||
def test_matrix_symbol_creation():
|
||||
assert MatrixSymbol('A', 2, 2)
|
||||
assert MatrixSymbol('A', 0, 0)
|
||||
raises(ValueError, lambda: MatrixSymbol('A', -1, 2))
|
||||
raises(ValueError, lambda: MatrixSymbol('A', 2.0, 2))
|
||||
raises(ValueError, lambda: MatrixSymbol('A', 2j, 2))
|
||||
raises(ValueError, lambda: MatrixSymbol('A', 2, -1))
|
||||
raises(ValueError, lambda: MatrixSymbol('A', 2, 2.0))
|
||||
raises(ValueError, lambda: MatrixSymbol('A', 2, 2j))
|
||||
|
||||
n = symbols('n')
|
||||
assert MatrixSymbol('A', n, n)
|
||||
n = symbols('n', integer=False)
|
||||
raises(ValueError, lambda: MatrixSymbol('A', n, n))
|
||||
n = symbols('n', negative=True)
|
||||
raises(ValueError, lambda: MatrixSymbol('A', n, n))
|
||||
|
||||
|
||||
def test_matexpr_properties():
|
||||
assert A.shape == (n, m)
|
||||
assert (A * B).shape == (n, l)
|
||||
assert A[0, 1].indices == (0, 1)
|
||||
assert A[0, 0].symbol == A
|
||||
assert A[0, 0].symbol.name == 'A'
|
||||
|
||||
|
||||
def test_matexpr():
|
||||
assert (x*A).shape == A.shape
|
||||
assert (x*A).__class__ == MatMul
|
||||
assert 2*A - A - A == ZeroMatrix(*A.shape)
|
||||
assert (A*B).shape == (n, l)
|
||||
|
||||
|
||||
def test_matexpr_subs():
|
||||
A = MatrixSymbol('A', n, m)
|
||||
B = MatrixSymbol('B', m, l)
|
||||
C = MatrixSymbol('C', m, l)
|
||||
|
||||
assert A.subs(n, m).shape == (m, m)
|
||||
assert (A*B).subs(B, C) == A*C
|
||||
assert (A*B).subs(l, n).is_square
|
||||
|
||||
W = MatrixSymbol("W", 3, 3)
|
||||
X = MatrixSymbol("X", 2, 2)
|
||||
Y = MatrixSymbol("Y", 1, 2)
|
||||
Z = MatrixSymbol("Z", n, 2)
|
||||
# no restrictions on Symbol replacement
|
||||
assert X.subs(X, Y) == Y
|
||||
# it might be better to just change the name
|
||||
y = Str('y')
|
||||
assert X.subs(Str("X"), y).args == (y, 2, 2)
|
||||
# it's ok to introduce a wider matrix
|
||||
assert X[1, 1].subs(X, W) == W[1, 1]
|
||||
# but for a given MatrixExpression, only change
|
||||
# name if indexing on the new shape is valid.
|
||||
# Here, X is 2,2; Y is 1,2 and Y[1, 1] is out
|
||||
# of range so an error is raised
|
||||
raises(IndexError, lambda: X[1, 1].subs(X, Y))
|
||||
# here, [0, 1] is in range so the subs succeeds
|
||||
assert X[0, 1].subs(X, Y) == Y[0, 1]
|
||||
# and here the size of n will accept any index
|
||||
# in the first position
|
||||
assert W[2, 1].subs(W, Z) == Z[2, 1]
|
||||
# but not in the second position
|
||||
raises(IndexError, lambda: W[2, 2].subs(W, Z))
|
||||
# any matrix should raise if invalid
|
||||
raises(IndexError, lambda: W[2, 2].subs(W, zeros(2)))
|
||||
|
||||
A = SparseMatrix([[1, 2], [3, 4]])
|
||||
B = Matrix([[1, 2], [3, 4]])
|
||||
C, D = MatrixSymbol('C', 2, 2), MatrixSymbol('D', 2, 2)
|
||||
|
||||
assert (C*D).subs({C: A, D: B}) == MatMul(A, B)
|
||||
|
||||
|
||||
def test_addition():
|
||||
A = MatrixSymbol('A', n, m)
|
||||
B = MatrixSymbol('B', n, m)
|
||||
|
||||
assert isinstance(A + B, MatAdd)
|
||||
assert (A + B).shape == A.shape
|
||||
assert isinstance(A - A + 2*B, MatMul)
|
||||
|
||||
raises(TypeError, lambda: A + 1)
|
||||
raises(TypeError, lambda: 5 + A)
|
||||
raises(TypeError, lambda: 5 - A)
|
||||
|
||||
assert A + ZeroMatrix(n, m) - A == ZeroMatrix(n, m)
|
||||
raises(TypeError, lambda: ZeroMatrix(n, m) + S.Zero)
|
||||
|
||||
|
||||
def test_multiplication():
|
||||
A = MatrixSymbol('A', n, m)
|
||||
B = MatrixSymbol('B', m, l)
|
||||
C = MatrixSymbol('C', n, n)
|
||||
|
||||
assert (2*A*B).shape == (n, l)
|
||||
assert (A*0*B) == ZeroMatrix(n, l)
|
||||
assert (2*A).shape == A.shape
|
||||
|
||||
assert A * ZeroMatrix(m, m) * B == ZeroMatrix(n, l)
|
||||
|
||||
assert C * Identity(n) * C.I == Identity(n)
|
||||
|
||||
assert B/2 == S.Half*B
|
||||
raises(NotImplementedError, lambda: 2/B)
|
||||
|
||||
A = MatrixSymbol('A', n, n)
|
||||
B = MatrixSymbol('B', n, n)
|
||||
assert Identity(n) * (A + B) == A + B
|
||||
|
||||
assert A**2*A == A**3
|
||||
assert A**2*(A.I)**3 == A.I
|
||||
assert A**3*(A.I)**2 == A
|
||||
|
||||
|
||||
def test_MatPow():
|
||||
A = MatrixSymbol('A', n, n)
|
||||
|
||||
AA = MatPow(A, 2)
|
||||
assert AA.exp == 2
|
||||
assert AA.base == A
|
||||
assert (A**n).exp == n
|
||||
|
||||
assert A**0 == Identity(n)
|
||||
assert A**1 == A
|
||||
assert A**2 == AA
|
||||
assert A**-1 == Inverse(A)
|
||||
assert (A**-1)**-1 == A
|
||||
assert (A**2)**3 == A**6
|
||||
assert A**S.Half == sqrt(A)
|
||||
assert A**Rational(1, 3) == cbrt(A)
|
||||
raises(NonSquareMatrixError, lambda: MatrixSymbol('B', 3, 2)**2)
|
||||
|
||||
|
||||
def test_MatrixSymbol():
|
||||
n, m, t = symbols('n,m,t')
|
||||
X = MatrixSymbol('X', n, m)
|
||||
assert X.shape == (n, m)
|
||||
raises(TypeError, lambda: MatrixSymbol('X', n, m)(t)) # issue 5855
|
||||
assert X.doit() == X
|
||||
|
||||
|
||||
def test_dense_conversion():
|
||||
X = MatrixSymbol('X', 2, 2)
|
||||
assert ImmutableMatrix(X) == ImmutableMatrix(2, 2, lambda i, j: X[i, j])
|
||||
assert Matrix(X) == Matrix(2, 2, lambda i, j: X[i, j])
|
||||
|
||||
|
||||
def test_free_symbols():
|
||||
assert (C*D).free_symbols == {C, D}
|
||||
|
||||
|
||||
def test_zero_matmul():
|
||||
assert isinstance(S.Zero * MatrixSymbol('X', 2, 2), MatrixExpr)
|
||||
|
||||
|
||||
def test_matadd_simplify():
|
||||
A = MatrixSymbol('A', 1, 1)
|
||||
assert simplify(MatAdd(A, ImmutableMatrix([[sin(x)**2 + cos(x)**2]]))) == \
|
||||
MatAdd(A, Matrix([[1]]))
|
||||
|
||||
|
||||
def test_matmul_simplify():
|
||||
A = MatrixSymbol('A', 1, 1)
|
||||
assert simplify(MatMul(A, ImmutableMatrix([[sin(x)**2 + cos(x)**2]]))) == \
|
||||
MatMul(A, Matrix([[1]]))
|
||||
|
||||
|
||||
def test_invariants():
|
||||
A = MatrixSymbol('A', n, m)
|
||||
B = MatrixSymbol('B', m, l)
|
||||
X = MatrixSymbol('X', n, n)
|
||||
objs = [Identity(n), ZeroMatrix(m, n), A, MatMul(A, B), MatAdd(A, A),
|
||||
Transpose(A), Adjoint(A), Inverse(X), MatPow(X, 2), MatPow(X, -1),
|
||||
MatPow(X, 0)]
|
||||
for obj in objs:
|
||||
assert obj == obj.__class__(*obj.args)
|
||||
|
||||
|
||||
def test_matexpr_indexing():
|
||||
A = MatrixSymbol('A', n, m)
|
||||
A[1, 2]
|
||||
A[l, k]
|
||||
A[l + 1, k + 1]
|
||||
A = MatrixSymbol('A', 2, 1)
|
||||
for i in range(-2, 2):
|
||||
for j in range(-1, 1):
|
||||
A[i, j]
|
||||
|
||||
|
||||
def test_single_indexing():
|
||||
A = MatrixSymbol('A', 2, 3)
|
||||
assert A[1] == A[0, 1]
|
||||
assert A[int(1)] == A[0, 1]
|
||||
assert A[3] == A[1, 0]
|
||||
assert list(A[:2, :2]) == [A[0, 0], A[0, 1], A[1, 0], A[1, 1]]
|
||||
raises(IndexError, lambda: A[6])
|
||||
raises(IndexError, lambda: A[n])
|
||||
B = MatrixSymbol('B', n, m)
|
||||
raises(IndexError, lambda: B[1])
|
||||
B = MatrixSymbol('B', n, 3)
|
||||
assert B[3] == B[1, 0]
|
||||
|
||||
|
||||
def test_MatrixElement_commutative():
|
||||
assert A[0, 1]*A[1, 0] == A[1, 0]*A[0, 1]
|
||||
|
||||
|
||||
def test_MatrixSymbol_determinant():
|
||||
A = MatrixSymbol('A', 4, 4)
|
||||
assert A.as_explicit().det() == A[0, 0]*A[1, 1]*A[2, 2]*A[3, 3] - \
|
||||
A[0, 0]*A[1, 1]*A[2, 3]*A[3, 2] - A[0, 0]*A[1, 2]*A[2, 1]*A[3, 3] + \
|
||||
A[0, 0]*A[1, 2]*A[2, 3]*A[3, 1] + A[0, 0]*A[1, 3]*A[2, 1]*A[3, 2] - \
|
||||
A[0, 0]*A[1, 3]*A[2, 2]*A[3, 1] - A[0, 1]*A[1, 0]*A[2, 2]*A[3, 3] + \
|
||||
A[0, 1]*A[1, 0]*A[2, 3]*A[3, 2] + A[0, 1]*A[1, 2]*A[2, 0]*A[3, 3] - \
|
||||
A[0, 1]*A[1, 2]*A[2, 3]*A[3, 0] - A[0, 1]*A[1, 3]*A[2, 0]*A[3, 2] + \
|
||||
A[0, 1]*A[1, 3]*A[2, 2]*A[3, 0] + A[0, 2]*A[1, 0]*A[2, 1]*A[3, 3] - \
|
||||
A[0, 2]*A[1, 0]*A[2, 3]*A[3, 1] - A[0, 2]*A[1, 1]*A[2, 0]*A[3, 3] + \
|
||||
A[0, 2]*A[1, 1]*A[2, 3]*A[3, 0] + A[0, 2]*A[1, 3]*A[2, 0]*A[3, 1] - \
|
||||
A[0, 2]*A[1, 3]*A[2, 1]*A[3, 0] - A[0, 3]*A[1, 0]*A[2, 1]*A[3, 2] + \
|
||||
A[0, 3]*A[1, 0]*A[2, 2]*A[3, 1] + A[0, 3]*A[1, 1]*A[2, 0]*A[3, 2] - \
|
||||
A[0, 3]*A[1, 1]*A[2, 2]*A[3, 0] - A[0, 3]*A[1, 2]*A[2, 0]*A[3, 1] + \
|
||||
A[0, 3]*A[1, 2]*A[2, 1]*A[3, 0]
|
||||
|
||||
B = MatrixSymbol('B', 4, 4)
|
||||
assert Determinant(A + B).doit() == det(A + B) == (A + B).det()
|
||||
|
||||
|
||||
def test_MatrixElement_diff():
|
||||
assert (A[3, 0]*A[0, 0]).diff(A[0, 0]) == A[3, 0]
|
||||
|
||||
|
||||
def test_MatrixElement_doit():
|
||||
u = MatrixSymbol('u', 2, 1)
|
||||
v = ImmutableMatrix([3, 5])
|
||||
assert u[0, 0].subs(u, v).doit() == v[0, 0]
|
||||
|
||||
|
||||
def test_identity_powers():
|
||||
M = Identity(n)
|
||||
assert MatPow(M, 3).doit() == M**3
|
||||
assert M**n == M
|
||||
assert MatPow(M, 0).doit() == M**2
|
||||
assert M**-2 == M
|
||||
assert MatPow(M, -2).doit() == M**0
|
||||
N = Identity(3)
|
||||
assert MatPow(N, 2).doit() == N**n
|
||||
assert MatPow(N, 3).doit() == N
|
||||
assert MatPow(N, -2).doit() == N**4
|
||||
assert MatPow(N, 2).doit() == N**0
|
||||
|
||||
|
||||
def test_Zero_power():
|
||||
z1 = ZeroMatrix(n, n)
|
||||
assert z1**4 == z1
|
||||
raises(ValueError, lambda:z1**-2)
|
||||
assert z1**0 == Identity(n)
|
||||
assert MatPow(z1, 2).doit() == z1**2
|
||||
raises(ValueError, lambda:MatPow(z1, -2).doit())
|
||||
z2 = ZeroMatrix(3, 3)
|
||||
assert MatPow(z2, 4).doit() == z2**4
|
||||
raises(ValueError, lambda:z2**-3)
|
||||
assert z2**3 == MatPow(z2, 3).doit()
|
||||
assert z2**0 == Identity(3)
|
||||
raises(ValueError, lambda:MatPow(z2, -1).doit())
|
||||
|
||||
|
||||
def test_matrixelement_diff():
|
||||
dexpr = diff((D*w)[k,0], w[p,0])
|
||||
|
||||
assert w[k, p].diff(w[k, p]) == 1
|
||||
assert w[k, p].diff(w[0, 0]) == KroneckerDelta(0, k, (0, n-1))*KroneckerDelta(0, p, (0, 0))
|
||||
_i_1 = Dummy("_i_1")
|
||||
assert dexpr.dummy_eq(Sum(KroneckerDelta(_i_1, p, (0, n-1))*D[k, _i_1], (_i_1, 0, n - 1)))
|
||||
assert dexpr.doit() == D[k, p]
|
||||
|
||||
|
||||
def test_MatrixElement_with_values():
|
||||
x, y, z, w = symbols("x y z w")
|
||||
M = Matrix([[x, y], [z, w]])
|
||||
i, j = symbols("i, j")
|
||||
Mij = M[i, j]
|
||||
assert isinstance(Mij, MatrixElement)
|
||||
Ms = SparseMatrix([[2, 3], [4, 5]])
|
||||
msij = Ms[i, j]
|
||||
assert isinstance(msij, MatrixElement)
|
||||
for oi, oj in [(0, 0), (0, 1), (1, 0), (1, 1)]:
|
||||
assert Mij.subs({i: oi, j: oj}) == M[oi, oj]
|
||||
assert msij.subs({i: oi, j: oj}) == Ms[oi, oj]
|
||||
A = MatrixSymbol("A", 2, 2)
|
||||
assert A[0, 0].subs(A, M) == x
|
||||
assert A[i, j].subs(A, M) == M[i, j]
|
||||
assert M[i, j].subs(M, A) == A[i, j]
|
||||
|
||||
assert isinstance(M[3*i - 2, j], MatrixElement)
|
||||
assert M[3*i - 2, j].subs({i: 1, j: 0}) == M[1, 0]
|
||||
assert isinstance(M[i, 0], MatrixElement)
|
||||
assert M[i, 0].subs(i, 0) == M[0, 0]
|
||||
assert M[0, i].subs(i, 1) == M[0, 1]
|
||||
|
||||
assert M[i, j].diff(x) == Matrix([[1, 0], [0, 0]])[i, j]
|
||||
|
||||
raises(ValueError, lambda: M[i, 2])
|
||||
raises(ValueError, lambda: M[i, -1])
|
||||
raises(ValueError, lambda: M[2, i])
|
||||
raises(ValueError, lambda: M[-1, i])
|
||||
|
||||
|
||||
def test_inv():
|
||||
B = MatrixSymbol('B', 3, 3)
|
||||
assert B.inv() == B**-1
|
||||
|
||||
# https://github.com/sympy/sympy/issues/19162
|
||||
X = MatrixSymbol('X', 1, 1).as_explicit()
|
||||
assert X.inv() == Matrix([[1/X[0, 0]]])
|
||||
|
||||
X = MatrixSymbol('X', 2, 2).as_explicit()
|
||||
detX = X[0, 0]*X[1, 1] - X[0, 1]*X[1, 0]
|
||||
invX = Matrix([[ X[1, 1], -X[0, 1]],
|
||||
[-X[1, 0], X[0, 0]]]) / detX
|
||||
assert X.inv() == invX
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_factor_expand():
|
||||
A = MatrixSymbol("A", n, n)
|
||||
B = MatrixSymbol("B", n, n)
|
||||
expr1 = (A + B)*(C + D)
|
||||
expr2 = A*C + B*C + A*D + B*D
|
||||
assert expr1 != expr2
|
||||
assert expand(expr1) == expr2
|
||||
assert factor(expr2) == expr1
|
||||
|
||||
expr = B**(-1)*(A**(-1)*B**(-1) - A**(-1)*C*B**(-1))**(-1)*A**(-1)
|
||||
I = Identity(n)
|
||||
# Ideally we get the first, but we at least don't want a wrong answer
|
||||
assert factor(expr) in [I - C, B**-1*(A**-1*(I - C)*B**-1)**-1*A**-1]
|
||||
|
||||
def test_numpy_conversion():
|
||||
try:
|
||||
from numpy import array, array_equal
|
||||
except ImportError:
|
||||
skip('NumPy must be available to test creating matrices from ndarrays')
|
||||
A = MatrixSymbol('A', 2, 2)
|
||||
np_array = array([[MatrixElement(A, 0, 0), MatrixElement(A, 0, 1)],
|
||||
[MatrixElement(A, 1, 0), MatrixElement(A, 1, 1)]])
|
||||
assert array_equal(array(A), np_array)
|
||||
assert array_equal(array(A, copy=True), np_array)
|
||||
if(int(version('numpy').split('.')[0]) >= 2): #run this test only if numpy is new enough that copy variable is passed properly.
|
||||
raises(TypeError, lambda: array(A, copy=False))
|
||||
|
||||
def test_issue_2749():
|
||||
A = MatrixSymbol("A", 5, 2)
|
||||
assert (A.T * A).I.as_explicit() == Matrix([[(A.T * A).I[0, 0], (A.T * A).I[0, 1]], \
|
||||
[(A.T * A).I[1, 0], (A.T * A).I[1, 1]]])
|
||||
|
||||
|
||||
def test_issue_2750():
|
||||
x = MatrixSymbol('x', 1, 1)
|
||||
assert (x.T*x).as_explicit()**-1 == Matrix([[x[0, 0]**(-2)]])
|
||||
|
||||
|
||||
def test_issue_7842():
|
||||
A = MatrixSymbol('A', 3, 1)
|
||||
B = MatrixSymbol('B', 2, 1)
|
||||
assert Eq(A, B) == False
|
||||
assert Eq(A[1,0], B[1, 0]).func is Eq
|
||||
A = ZeroMatrix(2, 3)
|
||||
B = ZeroMatrix(2, 3)
|
||||
assert Eq(A, B) == True
|
||||
|
||||
|
||||
def test_issue_21195():
|
||||
t = symbols('t')
|
||||
x = Function('x')(t)
|
||||
dx = x.diff(t)
|
||||
exp1 = cos(x) + cos(x)*dx
|
||||
exp2 = sin(x) + tan(x)*(dx.diff(t))
|
||||
exp3 = sin(x)*sin(t)*(dx.diff(t)).diff(t)
|
||||
A = Matrix([[exp1], [exp2], [exp3]])
|
||||
B = Matrix([[exp1.diff(x)], [exp2.diff(x)], [exp3.diff(x)]])
|
||||
assert A.diff(x) == B
|
||||
|
||||
|
||||
def test_issue_24859():
|
||||
A = MatrixSymbol('A', 2, 3)
|
||||
B = MatrixSymbol('B', 3, 2)
|
||||
J = A*B
|
||||
Jinv = Matrix(J).adjugate()
|
||||
u = MatrixSymbol('u', 2, 3)
|
||||
Jk = Jinv.subs(A, A + x*u)
|
||||
|
||||
expected = B[0, 1]*u[1, 0] + B[1, 1]*u[1, 1] + B[2, 1]*u[1, 2]
|
||||
assert Jk[0, 0].diff(x) == expected
|
||||
assert diff(Jk[0, 0], x).doit() == expected
|
||||
|
||||
|
||||
def test_MatMul_postprocessor():
|
||||
z = zeros(2)
|
||||
z1 = ZeroMatrix(2, 2)
|
||||
assert Mul(0, z) == Mul(z, 0) in [z, z1]
|
||||
|
||||
M = Matrix([[1, 2], [3, 4]])
|
||||
Mx = Matrix([[x, 2*x], [3*x, 4*x]])
|
||||
assert Mul(x, M) == Mul(M, x) == Mx
|
||||
|
||||
A = MatrixSymbol("A", 2, 2)
|
||||
assert Mul(A, M) == MatMul(A, M)
|
||||
assert Mul(M, A) == MatMul(M, A)
|
||||
# Scalars should be absorbed into constant matrices
|
||||
a = Mul(x, M, A)
|
||||
b = Mul(M, x, A)
|
||||
c = Mul(M, A, x)
|
||||
assert a == b == c == MatMul(Mx, A)
|
||||
a = Mul(x, A, M)
|
||||
b = Mul(A, x, M)
|
||||
c = Mul(A, M, x)
|
||||
assert a == b == c == MatMul(A, Mx)
|
||||
assert Mul(M, M) == M**2
|
||||
assert Mul(A, M, M) == MatMul(A, M**2)
|
||||
assert Mul(M, M, A) == MatMul(M**2, A)
|
||||
assert Mul(M, A, M) == MatMul(M, A, M)
|
||||
|
||||
assert Mul(A, x, M, M, x) == MatMul(A, Mx**2)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_MatAdd_postprocessor_xfail():
|
||||
# This is difficult to get working because of the way that Add processes
|
||||
# its args.
|
||||
z = zeros(2)
|
||||
assert Add(z, S.NaN) == Add(S.NaN, z)
|
||||
|
||||
|
||||
def test_MatAdd_postprocessor():
|
||||
# Some of these are nonsensical, but we do not raise errors for Add
|
||||
# because that breaks algorithms that want to replace matrices with dummy
|
||||
# symbols.
|
||||
|
||||
z = zeros(2)
|
||||
|
||||
assert Add(0, z) == Add(z, 0) == z
|
||||
|
||||
a = Add(S.Infinity, z)
|
||||
assert a == Add(z, S.Infinity)
|
||||
assert isinstance(a, Add)
|
||||
assert a.args == (S.Infinity, z)
|
||||
|
||||
a = Add(S.ComplexInfinity, z)
|
||||
assert a == Add(z, S.ComplexInfinity)
|
||||
assert isinstance(a, Add)
|
||||
assert a.args == (S.ComplexInfinity, z)
|
||||
|
||||
a = Add(z, S.NaN)
|
||||
# assert a == Add(S.NaN, z) # See the XFAIL above
|
||||
assert isinstance(a, Add)
|
||||
assert a.args == (S.NaN, z)
|
||||
|
||||
M = Matrix([[1, 2], [3, 4]])
|
||||
a = Add(x, M)
|
||||
assert a == Add(M, x)
|
||||
assert isinstance(a, Add)
|
||||
assert a.args == (x, M)
|
||||
|
||||
A = MatrixSymbol("A", 2, 2)
|
||||
assert Add(A, M) == Add(M, A) == A + M
|
||||
|
||||
# Scalars should be absorbed into constant matrices (producing an error)
|
||||
a = Add(x, M, A)
|
||||
assert a == Add(M, x, A) == Add(M, A, x) == Add(x, A, M) == Add(A, x, M) == Add(A, M, x)
|
||||
assert isinstance(a, Add)
|
||||
assert a.args == (x, A + M)
|
||||
|
||||
assert Add(M, M) == 2*M
|
||||
assert Add(M, A, M) == Add(M, M, A) == Add(A, M, M) == A + 2*M
|
||||
|
||||
a = Add(A, x, M, M, x)
|
||||
assert isinstance(a, Add)
|
||||
assert a.args == (2*x, A + 2*M)
|
||||
|
||||
|
||||
def test_simplify_matrix_expressions():
|
||||
# Various simplification functions
|
||||
assert type(gcd_terms(C*D + D*C)) == MatAdd
|
||||
a = gcd_terms(2*C*D + 4*D*C)
|
||||
assert type(a) == MatAdd
|
||||
assert a.args == (2*C*D, 4*D*C)
|
||||
|
||||
|
||||
def test_exp():
|
||||
A = MatrixSymbol('A', 2, 2)
|
||||
B = MatrixSymbol('B', 2, 2)
|
||||
expr1 = exp(A)*exp(B)
|
||||
expr2 = exp(B)*exp(A)
|
||||
assert expr1 != expr2
|
||||
assert expr1 - expr2 != 0
|
||||
assert not isinstance(expr1, exp)
|
||||
assert not isinstance(expr2, exp)
|
||||
|
||||
|
||||
def test_invalid_args():
|
||||
raises(SympifyError, lambda: MatrixSymbol(1, 2, 'A'))
|
||||
|
||||
|
||||
def test_matrixsymbol_from_symbol():
|
||||
# The label should be preserved during doit and subs
|
||||
A_label = Symbol('A', complex=True)
|
||||
A = MatrixSymbol(A_label, 2, 2)
|
||||
|
||||
A_1 = A.doit()
|
||||
A_2 = A.subs(2, 3)
|
||||
assert A_1.args == A.args
|
||||
assert A_2.args[0] == A.args[0]
|
||||
|
||||
|
||||
def test_as_explicit():
|
||||
Z = MatrixSymbol('Z', 2, 3)
|
||||
assert Z.as_explicit() == ImmutableMatrix([
|
||||
[Z[0, 0], Z[0, 1], Z[0, 2]],
|
||||
[Z[1, 0], Z[1, 1], Z[1, 2]],
|
||||
])
|
||||
raises(ValueError, lambda: A.as_explicit())
|
||||
|
||||
|
||||
def test_MatrixSet():
|
||||
M = MatrixSet(2, 2, set=S.Reals)
|
||||
assert M.shape == (2, 2)
|
||||
assert M.set == S.Reals
|
||||
X = Matrix([[1, 2], [3, 4]])
|
||||
assert X in M
|
||||
X = ZeroMatrix(2, 2)
|
||||
assert X in M
|
||||
raises(TypeError, lambda: A in M)
|
||||
raises(TypeError, lambda: 1 in M)
|
||||
M = MatrixSet(n, m, set=S.Reals)
|
||||
assert A in M
|
||||
raises(TypeError, lambda: C in M)
|
||||
raises(TypeError, lambda: X in M)
|
||||
M = MatrixSet(2, 2, set={1, 2, 3})
|
||||
X = Matrix([[1, 2], [3, 4]])
|
||||
Y = Matrix([[1, 2]])
|
||||
assert (X in M) == S.false
|
||||
assert (Y in M) == S.false
|
||||
raises(ValueError, lambda: MatrixSet(2, -2, S.Reals))
|
||||
raises(ValueError, lambda: MatrixSet(2.4, -1, S.Reals))
|
||||
raises(TypeError, lambda: MatrixSet(2, 2, (1, 2, 3)))
|
||||
|
||||
|
||||
def test_matrixsymbol_solving():
|
||||
A = MatrixSymbol('A', 2, 2)
|
||||
B = MatrixSymbol('B', 2, 2)
|
||||
Z = ZeroMatrix(2, 2)
|
||||
assert -(-A + B) - A + B == Z
|
||||
assert (-(-A + B) - A + B).simplify() == Z
|
||||
assert (-(-A + B) - A + B).expand() == Z
|
||||
assert (-(-A + B) - A + B - Z).simplify() == Z
|
||||
assert (-(-A + B) - A + B - Z).expand() == Z
|
||||
assert (A*(A + B) + B*(A.T + B.T)).expand() == A**2 + A*B + B*A.T + B*B.T
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
from sympy.core import I, symbols, Basic, Mul, S
|
||||
from sympy.core.mul import mul
|
||||
from sympy.functions import adjoint, transpose
|
||||
from sympy.matrices.exceptions import ShapeError
|
||||
from sympy.matrices import (Identity, Inverse, Matrix, MatrixSymbol, ZeroMatrix,
|
||||
eye, ImmutableMatrix)
|
||||
from sympy.matrices.expressions import Adjoint, Transpose, det, MatPow
|
||||
from sympy.matrices.expressions.special import GenericIdentity
|
||||
from sympy.matrices.expressions.matmul import (factor_in_front, remove_ids,
|
||||
MatMul, combine_powers, any_zeros, unpack, only_squares)
|
||||
from sympy.strategies import null_safe
|
||||
from sympy.assumptions.ask import Q
|
||||
from sympy.assumptions.refine import refine
|
||||
from sympy.core.symbol import Symbol
|
||||
|
||||
from sympy.testing.pytest import XFAIL, raises
|
||||
|
||||
n, m, l, k = symbols('n m l k', integer=True)
|
||||
x = symbols('x')
|
||||
A = MatrixSymbol('A', n, m)
|
||||
B = MatrixSymbol('B', m, l)
|
||||
C = MatrixSymbol('C', n, n)
|
||||
D = MatrixSymbol('D', n, n)
|
||||
E = MatrixSymbol('E', m, n)
|
||||
|
||||
def test_evaluate():
|
||||
assert MatMul(C, C, evaluate=True) == MatMul(C, C).doit()
|
||||
|
||||
def test_adjoint():
|
||||
assert adjoint(A*B) == Adjoint(B)*Adjoint(A)
|
||||
assert adjoint(2*A*B) == 2*Adjoint(B)*Adjoint(A)
|
||||
assert adjoint(2*I*C) == -2*I*Adjoint(C)
|
||||
|
||||
M = Matrix(2, 2, [1, 2 + I, 3, 4])
|
||||
MA = Matrix(2, 2, [1, 3, 2 - I, 4])
|
||||
assert adjoint(M) == MA
|
||||
assert adjoint(2*M) == 2*MA
|
||||
assert adjoint(MatMul(2, M)) == MatMul(2, MA).doit()
|
||||
|
||||
|
||||
def test_transpose():
|
||||
assert transpose(A*B) == Transpose(B)*Transpose(A)
|
||||
assert transpose(2*A*B) == 2*Transpose(B)*Transpose(A)
|
||||
assert transpose(2*I*C) == 2*I*Transpose(C)
|
||||
|
||||
M = Matrix(2, 2, [1, 2 + I, 3, 4])
|
||||
MT = Matrix(2, 2, [1, 3, 2 + I, 4])
|
||||
assert transpose(M) == MT
|
||||
assert transpose(2*M) == 2*MT
|
||||
assert transpose(x*M) == x*MT
|
||||
assert transpose(MatMul(2, M)) == MatMul(2, MT).doit()
|
||||
|
||||
|
||||
def test_factor_in_front():
|
||||
assert factor_in_front(MatMul(A, 2, B, evaluate=False)) ==\
|
||||
MatMul(2, A, B, evaluate=False)
|
||||
|
||||
|
||||
def test_remove_ids():
|
||||
assert remove_ids(MatMul(A, Identity(m), B, evaluate=False)) == \
|
||||
MatMul(A, B, evaluate=False)
|
||||
assert null_safe(remove_ids)(MatMul(Identity(n), evaluate=False)) == \
|
||||
MatMul(Identity(n), evaluate=False)
|
||||
|
||||
|
||||
def test_combine_powers():
|
||||
assert combine_powers(MatMul(D, Inverse(D), D, evaluate=False)) == \
|
||||
MatMul(Identity(n), D, evaluate=False)
|
||||
assert combine_powers(MatMul(B.T, Inverse(E*A), E, A, B, evaluate=False)) == \
|
||||
MatMul(B.T, Identity(m), B, evaluate=False)
|
||||
assert combine_powers(MatMul(A, E, Inverse(A*E), D, evaluate=False)) == \
|
||||
MatMul(Identity(n), D, evaluate=False)
|
||||
|
||||
|
||||
def test_any_zeros():
|
||||
assert any_zeros(MatMul(A, ZeroMatrix(m, k), evaluate=False)) == \
|
||||
ZeroMatrix(n, k)
|
||||
|
||||
|
||||
def test_unpack():
|
||||
assert unpack(MatMul(A, evaluate=False)) == A
|
||||
x = MatMul(A, B)
|
||||
assert unpack(x) == x
|
||||
|
||||
|
||||
def test_only_squares():
|
||||
assert only_squares(C) == [C]
|
||||
assert only_squares(C, D) == [C, D]
|
||||
assert only_squares(C, A, A.T, D) == [C, A*A.T, D]
|
||||
|
||||
|
||||
def test_determinant():
|
||||
assert det(2*C) == 2**n*det(C)
|
||||
assert det(2*C*D) == 2**n*det(C)*det(D)
|
||||
assert det(3*C*A*A.T*D) == 3**n*det(C)*det(A*A.T)*det(D)
|
||||
|
||||
|
||||
def test_doit():
|
||||
assert MatMul(C, 2, D).args == (C, 2, D)
|
||||
assert MatMul(C, 2, D).doit().args == (2, C, D)
|
||||
assert MatMul(C, Transpose(D*C)).args == (C, Transpose(D*C))
|
||||
assert MatMul(C, Transpose(D*C)).doit(deep=True).args == (C, C.T, D.T)
|
||||
|
||||
|
||||
def test_doit_drills_down():
|
||||
X = ImmutableMatrix([[1, 2], [3, 4]])
|
||||
Y = ImmutableMatrix([[2, 3], [4, 5]])
|
||||
assert MatMul(X, MatPow(Y, 2)).doit() == X*Y**2
|
||||
assert MatMul(C, Transpose(D*C)).doit().args == (C, C.T, D.T)
|
||||
|
||||
|
||||
def test_doit_deep_false_still_canonical():
|
||||
assert (MatMul(C, Transpose(D*C), 2).doit(deep=False).args ==
|
||||
(2, C, Transpose(D*C)))
|
||||
|
||||
|
||||
def test_matmul_scalar_Matrix_doit():
|
||||
# Issue 9053
|
||||
X = Matrix([[1, 2], [3, 4]])
|
||||
assert MatMul(2, X).doit() == 2*X
|
||||
|
||||
|
||||
def test_matmul_sympify():
|
||||
assert isinstance(MatMul(eye(1), eye(1)).args[0], Basic)
|
||||
|
||||
|
||||
def test_collapse_MatrixBase():
|
||||
A = Matrix([[1, 1], [1, 1]])
|
||||
B = Matrix([[1, 2], [3, 4]])
|
||||
assert MatMul(A, B).doit() == ImmutableMatrix([[4, 6], [4, 6]])
|
||||
|
||||
|
||||
def test_refine():
|
||||
assert refine(C*C.T*D, Q.orthogonal(C)).doit() == D
|
||||
|
||||
kC = k*C
|
||||
assert refine(kC*C.T, Q.orthogonal(C)).doit() == k*Identity(n)
|
||||
assert refine(kC* kC.T, Q.orthogonal(C)).doit() == (k**2)*Identity(n)
|
||||
|
||||
def test_matmul_no_matrices():
|
||||
assert MatMul(1) == 1
|
||||
assert MatMul(n, m) == n*m
|
||||
assert not isinstance(MatMul(n, m), MatMul)
|
||||
|
||||
def test_matmul_args_cnc():
|
||||
assert MatMul(n, A, A.T).args_cnc() == [[n], [A, A.T]]
|
||||
assert MatMul(A, A.T).args_cnc() == [[], [A, A.T]]
|
||||
|
||||
@XFAIL
|
||||
def test_matmul_args_cnc_symbols():
|
||||
# Not currently supported
|
||||
a, b = symbols('a b', commutative=False)
|
||||
assert MatMul(n, a, b, A, A.T).args_cnc() == [[n], [a, b, A, A.T]]
|
||||
assert MatMul(n, a, A, b, A.T).args_cnc() == [[n], [a, A, b, A.T]]
|
||||
|
||||
def test_issue_12950():
|
||||
M = Matrix([[Symbol("x")]]) * MatrixSymbol("A", 1, 1)
|
||||
assert MatrixSymbol("A", 1, 1).as_explicit()[0]*Symbol('x') == M.as_explicit()[0]
|
||||
|
||||
def test_construction_with_Mul():
|
||||
assert Mul(C, D) == MatMul(C, D)
|
||||
assert Mul(D, C) == MatMul(D, C)
|
||||
|
||||
def test_construction_with_mul():
|
||||
assert mul(C, D) == MatMul(C, D)
|
||||
assert mul(D, C) == MatMul(D, C)
|
||||
assert mul(C, D) != MatMul(D, C)
|
||||
|
||||
def test_generic_identity():
|
||||
assert MatMul.identity == GenericIdentity()
|
||||
assert MatMul.identity != S.One
|
||||
|
||||
|
||||
def test_issue_23519():
|
||||
N = Symbol("N", integer=True)
|
||||
M1 = MatrixSymbol("M1", N, N)
|
||||
M2 = MatrixSymbol("M2", N, N)
|
||||
I = Identity(N)
|
||||
z = (M2 + 2 * (M2 + I) * M1 + I)
|
||||
assert z.coeff(M1) == 2*I + 2*M2
|
||||
|
||||
|
||||
def test_shape_error():
|
||||
A = MatrixSymbol('A', 2, 2)
|
||||
B = MatrixSymbol('B', 3, 3)
|
||||
raises(ShapeError, lambda: MatMul(A, B))
|
||||
|
||||
|
||||
def test_matmul_transpose():
|
||||
# https://github.com/sympy/sympy/issues/9503
|
||||
M = Matrix(2, 2, [1, 2 + I, 3, 4])
|
||||
a = Symbol('a')
|
||||
assert (MatMul(a, M).T).expand() == (a*Matrix([[1, 3],[2 + I, 4]])).expand()
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.simplify.powsimp import powsimp
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.core.expr import unchanged
|
||||
from sympy.core import symbols, S
|
||||
from sympy.matrices import Identity, MatrixSymbol, ImmutableMatrix, ZeroMatrix, OneMatrix, Matrix
|
||||
from sympy.matrices.exceptions import NonSquareMatrixError
|
||||
from sympy.matrices.expressions import MatPow, MatAdd, MatMul
|
||||
from sympy.matrices.expressions.inverse import Inverse
|
||||
from sympy.matrices.expressions.matexpr import MatrixElement
|
||||
|
||||
n, m, l, k = symbols('n m l k', integer=True)
|
||||
A = MatrixSymbol('A', n, m)
|
||||
B = MatrixSymbol('B', m, l)
|
||||
C = MatrixSymbol('C', n, n)
|
||||
D = MatrixSymbol('D', n, n)
|
||||
E = MatrixSymbol('E', m, n)
|
||||
|
||||
|
||||
def test_entry_matrix():
|
||||
X = ImmutableMatrix([[1, 2], [3, 4]])
|
||||
assert MatPow(X, 0)[0, 0] == 1
|
||||
assert MatPow(X, 0)[0, 1] == 0
|
||||
assert MatPow(X, 1)[0, 0] == 1
|
||||
assert MatPow(X, 1)[0, 1] == 2
|
||||
assert MatPow(X, 2)[0, 0] == 7
|
||||
|
||||
|
||||
def test_entry_symbol():
|
||||
from sympy.concrete import Sum
|
||||
assert MatPow(C, 0)[0, 0] == 1
|
||||
assert MatPow(C, 0)[0, 1] == 0
|
||||
assert MatPow(C, 1)[0, 0] == C[0, 0]
|
||||
assert isinstance(MatPow(C, 2)[0, 0], Sum)
|
||||
assert isinstance(MatPow(C, n)[0, 0], MatrixElement)
|
||||
|
||||
|
||||
def test_as_explicit_symbol():
|
||||
X = MatrixSymbol('X', 2, 2)
|
||||
assert MatPow(X, 0).as_explicit() == ImmutableMatrix(Identity(2))
|
||||
assert MatPow(X, 1).as_explicit() == X.as_explicit()
|
||||
assert MatPow(X, 2).as_explicit() == (X.as_explicit())**2
|
||||
assert MatPow(X, n).as_explicit() == ImmutableMatrix([
|
||||
[(X ** n)[0, 0], (X ** n)[0, 1]],
|
||||
[(X ** n)[1, 0], (X ** n)[1, 1]],
|
||||
])
|
||||
|
||||
a = MatrixSymbol("a", 3, 1)
|
||||
b = MatrixSymbol("b", 3, 1)
|
||||
c = MatrixSymbol("c", 3, 1)
|
||||
|
||||
expr = (a.T*b)**S.Half
|
||||
assert expr.as_explicit() == Matrix([[sqrt(a[0, 0]*b[0, 0] + a[1, 0]*b[1, 0] + a[2, 0]*b[2, 0])]])
|
||||
|
||||
expr = c*(a.T*b)**S.Half
|
||||
m = sqrt(a[0, 0]*b[0, 0] + a[1, 0]*b[1, 0] + a[2, 0]*b[2, 0])
|
||||
assert expr.as_explicit() == Matrix([[c[0, 0]*m], [c[1, 0]*m], [c[2, 0]*m]])
|
||||
|
||||
expr = (a*b.T)**S.Half
|
||||
denom = sqrt(a[0, 0]*b[0, 0] + a[1, 0]*b[1, 0] + a[2, 0]*b[2, 0])
|
||||
expected = (a*b.T).as_explicit()/denom
|
||||
assert expr.as_explicit() == expected
|
||||
|
||||
expr = X**-1
|
||||
det = X[0, 0]*X[1, 1] - X[1, 0]*X[0, 1]
|
||||
expected = Matrix([[X[1, 1], -X[0, 1]], [-X[1, 0], X[0, 0]]])/det
|
||||
assert expr.as_explicit() == expected
|
||||
|
||||
expr = X**m
|
||||
assert expr.as_explicit() == X.as_explicit()**m
|
||||
|
||||
|
||||
def test_as_explicit_matrix():
|
||||
A = ImmutableMatrix([[1, 2], [3, 4]])
|
||||
assert MatPow(A, 0).as_explicit() == ImmutableMatrix(Identity(2))
|
||||
assert MatPow(A, 1).as_explicit() == A
|
||||
assert MatPow(A, 2).as_explicit() == A**2
|
||||
assert MatPow(A, -1).as_explicit() == A.inv()
|
||||
assert MatPow(A, -2).as_explicit() == (A.inv())**2
|
||||
# less expensive than testing on a 2x2
|
||||
A = ImmutableMatrix([4])
|
||||
assert MatPow(A, S.Half).as_explicit() == A**S.Half
|
||||
|
||||
|
||||
def test_doit_symbol():
|
||||
assert MatPow(C, 0).doit() == Identity(n)
|
||||
assert MatPow(C, 1).doit() == C
|
||||
assert MatPow(C, -1).doit() == C.I
|
||||
for r in [2, S.Half, S.Pi, n]:
|
||||
assert MatPow(C, r).doit() == MatPow(C, r)
|
||||
|
||||
|
||||
def test_doit_matrix():
|
||||
X = ImmutableMatrix([[1, 2], [3, 4]])
|
||||
assert MatPow(X, 0).doit() == ImmutableMatrix(Identity(2))
|
||||
assert MatPow(X, 1).doit() == X
|
||||
assert MatPow(X, 2).doit() == X**2
|
||||
assert MatPow(X, -1).doit() == X.inv()
|
||||
assert MatPow(X, -2).doit() == (X.inv())**2
|
||||
# less expensive than testing on a 2x2
|
||||
assert MatPow(ImmutableMatrix([4]), S.Half).doit() == ImmutableMatrix([2])
|
||||
X = ImmutableMatrix([[0, 2], [0, 4]]) # det() == 0
|
||||
raises(ValueError, lambda: MatPow(X,-1).doit())
|
||||
raises(ValueError, lambda: MatPow(X,-2).doit())
|
||||
|
||||
|
||||
def test_nonsquare():
|
||||
A = MatrixSymbol('A', 2, 3)
|
||||
B = ImmutableMatrix([[1, 2, 3], [4, 5, 6]])
|
||||
for r in [-1, 0, 1, 2, S.Half, S.Pi, n]:
|
||||
raises(NonSquareMatrixError, lambda: MatPow(A, r))
|
||||
raises(NonSquareMatrixError, lambda: MatPow(B, r))
|
||||
|
||||
|
||||
def test_doit_equals_pow(): #17179
|
||||
X = ImmutableMatrix ([[1,0],[0,1]])
|
||||
assert MatPow(X, n).doit() == X**n == X
|
||||
|
||||
|
||||
def test_doit_nested_MatrixExpr():
|
||||
X = ImmutableMatrix([[1, 2], [3, 4]])
|
||||
Y = ImmutableMatrix([[2, 3], [4, 5]])
|
||||
assert MatPow(MatMul(X, Y), 2).doit() == (X*Y)**2
|
||||
assert MatPow(MatAdd(X, Y), 2).doit() == (X + Y)**2
|
||||
|
||||
|
||||
def test_identity_power():
|
||||
k = Identity(n)
|
||||
assert MatPow(k, 4).doit() == k
|
||||
assert MatPow(k, n).doit() == k
|
||||
assert MatPow(k, -3).doit() == k
|
||||
assert MatPow(k, 0).doit() == k
|
||||
l = Identity(3)
|
||||
assert MatPow(l, n).doit() == l
|
||||
assert MatPow(l, -1).doit() == l
|
||||
assert MatPow(l, 0).doit() == l
|
||||
|
||||
|
||||
def test_zero_power():
|
||||
z1 = ZeroMatrix(n, n)
|
||||
assert MatPow(z1, 3).doit() == z1
|
||||
raises(ValueError, lambda:MatPow(z1, -1).doit())
|
||||
assert MatPow(z1, 0).doit() == Identity(n)
|
||||
assert MatPow(z1, n).doit() == z1
|
||||
raises(ValueError, lambda:MatPow(z1, -2).doit())
|
||||
z2 = ZeroMatrix(4, 4)
|
||||
assert MatPow(z2, n).doit() == z2
|
||||
raises(ValueError, lambda:MatPow(z2, -3).doit())
|
||||
assert MatPow(z2, 2).doit() == z2
|
||||
assert MatPow(z2, 0).doit() == Identity(4)
|
||||
raises(ValueError, lambda:MatPow(z2, -1).doit())
|
||||
|
||||
|
||||
def test_OneMatrix_power():
|
||||
o = OneMatrix(3, 3)
|
||||
assert o ** 0 == Identity(3)
|
||||
assert o ** 1 == o
|
||||
assert o * o == o ** 2 == 3 * o
|
||||
assert o * o * o == o ** 3 == 9 * o
|
||||
|
||||
o = OneMatrix(n, n)
|
||||
assert o * o == o ** 2 == n * o
|
||||
# powsimp necessary as n ** (n - 2) * n does not produce n ** (n - 1)
|
||||
assert powsimp(o ** (n - 1) * o) == o ** n == n ** (n - 1) * o
|
||||
|
||||
|
||||
def test_transpose_power():
|
||||
from sympy.matrices.expressions.transpose import Transpose as TP
|
||||
|
||||
assert (C*D).T**5 == ((C*D)**5).T == (D.T * C.T)**5
|
||||
assert ((C*D).T**5).T == (C*D)**5
|
||||
|
||||
assert (C.T.I.T)**7 == C**-7
|
||||
assert (C.T**l).T**k == C**(l*k)
|
||||
|
||||
assert ((E.T * A.T)**5).T == (A*E)**5
|
||||
assert ((A*E).T**5).T**7 == (A*E)**35
|
||||
assert TP(TP(C**2 * D**3)**5).doit() == (C**2 * D**3)**5
|
||||
|
||||
assert ((D*C)**-5).T**-5 == ((D*C)**25).T
|
||||
assert (((D*C)**l).T**k).T == (D*C)**(l*k)
|
||||
|
||||
|
||||
def test_Inverse():
|
||||
assert Inverse(MatPow(C, 0)).doit() == Identity(n)
|
||||
assert Inverse(MatPow(C, 1)).doit() == Inverse(C)
|
||||
assert Inverse(MatPow(C, 2)).doit() == MatPow(C, -2)
|
||||
assert Inverse(MatPow(C, -1)).doit() == C
|
||||
|
||||
assert MatPow(Inverse(C), 0).doit() == Identity(n)
|
||||
assert MatPow(Inverse(C), 1).doit() == Inverse(C)
|
||||
assert MatPow(Inverse(C), 2).doit() == MatPow(C, -2)
|
||||
assert MatPow(Inverse(C), -1).doit() == C
|
||||
|
||||
|
||||
def test_combine_powers():
|
||||
assert (C ** 1) ** 1 == C
|
||||
assert (C ** 2) ** 3 == MatPow(C, 6)
|
||||
assert (C ** -2) ** -3 == MatPow(C, 6)
|
||||
assert (C ** -1) ** -1 == C
|
||||
assert (((C ** 2) ** 3) ** 4) ** 5 == MatPow(C, 120)
|
||||
assert (C ** n) ** n == C ** (n ** 2)
|
||||
|
||||
|
||||
def test_unchanged():
|
||||
assert unchanged(MatPow, C, 0)
|
||||
assert unchanged(MatPow, C, 1)
|
||||
assert unchanged(MatPow, Inverse(C), -1)
|
||||
assert unchanged(Inverse, MatPow(C, -1), -1)
|
||||
assert unchanged(MatPow, MatPow(C, -1), -1)
|
||||
assert unchanged(MatPow, MatPow(C, 1), 1)
|
||||
|
||||
|
||||
def test_no_exponentiation():
|
||||
# if this passes, Pow.as_numer_denom should recognize
|
||||
# MatAdd as exponent
|
||||
raises(NotImplementedError, lambda: 3**(-2*C))
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
from sympy.combinatorics import Permutation
|
||||
from sympy.core.expr import unchanged
|
||||
from sympy.matrices import Matrix
|
||||
from sympy.matrices.expressions import \
|
||||
MatMul, BlockDiagMatrix, Determinant, Inverse
|
||||
from sympy.matrices.expressions.matexpr import MatrixSymbol
|
||||
from sympy.matrices.expressions.special import ZeroMatrix, OneMatrix, Identity
|
||||
from sympy.matrices.expressions.permutation import \
|
||||
MatrixPermute, PermutationMatrix
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.core.symbol import Symbol
|
||||
|
||||
|
||||
def test_PermutationMatrix_basic():
|
||||
p = Permutation([1, 0])
|
||||
assert unchanged(PermutationMatrix, p)
|
||||
raises(ValueError, lambda: PermutationMatrix((0, 1, 2)))
|
||||
assert PermutationMatrix(p).as_explicit() == Matrix([[0, 1], [1, 0]])
|
||||
assert isinstance(PermutationMatrix(p)*MatrixSymbol('A', 2, 2), MatMul)
|
||||
|
||||
|
||||
def test_PermutationMatrix_matmul():
|
||||
p = Permutation([1, 2, 0])
|
||||
P = PermutationMatrix(p)
|
||||
M = Matrix([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
|
||||
assert (P*M).as_explicit() == P.as_explicit()*M
|
||||
assert (M*P).as_explicit() == M*P.as_explicit()
|
||||
|
||||
P1 = PermutationMatrix(Permutation([1, 2, 0]))
|
||||
P2 = PermutationMatrix(Permutation([2, 1, 0]))
|
||||
P3 = PermutationMatrix(Permutation([1, 0, 2]))
|
||||
assert P1*P2 == P3
|
||||
|
||||
|
||||
def test_PermutationMatrix_matpow():
|
||||
p1 = Permutation([1, 2, 0])
|
||||
P1 = PermutationMatrix(p1)
|
||||
p2 = Permutation([2, 0, 1])
|
||||
P2 = PermutationMatrix(p2)
|
||||
assert P1**2 == P2
|
||||
assert P1**3 == Identity(3)
|
||||
|
||||
|
||||
def test_PermutationMatrix_identity():
|
||||
p = Permutation([0, 1])
|
||||
assert PermutationMatrix(p).is_Identity
|
||||
|
||||
p = Permutation([1, 0])
|
||||
assert not PermutationMatrix(p).is_Identity
|
||||
|
||||
|
||||
def test_PermutationMatrix_determinant():
|
||||
P = PermutationMatrix(Permutation([0, 1, 2]))
|
||||
assert Determinant(P).doit() == 1
|
||||
P = PermutationMatrix(Permutation([0, 2, 1]))
|
||||
assert Determinant(P).doit() == -1
|
||||
P = PermutationMatrix(Permutation([2, 0, 1]))
|
||||
assert Determinant(P).doit() == 1
|
||||
|
||||
|
||||
def test_PermutationMatrix_inverse():
|
||||
P = PermutationMatrix(Permutation(0, 1, 2))
|
||||
assert Inverse(P).doit() == PermutationMatrix(Permutation(0, 2, 1))
|
||||
|
||||
|
||||
def test_PermutationMatrix_rewrite_BlockDiagMatrix():
|
||||
P = PermutationMatrix(Permutation([0, 1, 2, 3, 4, 5]))
|
||||
P0 = PermutationMatrix(Permutation([0]))
|
||||
assert P.rewrite(BlockDiagMatrix) == \
|
||||
BlockDiagMatrix(P0, P0, P0, P0, P0, P0)
|
||||
|
||||
P = PermutationMatrix(Permutation([0, 1, 3, 2, 4, 5]))
|
||||
P10 = PermutationMatrix(Permutation(0, 1))
|
||||
assert P.rewrite(BlockDiagMatrix) == \
|
||||
BlockDiagMatrix(P0, P0, P10, P0, P0)
|
||||
|
||||
P = PermutationMatrix(Permutation([1, 0, 3, 2, 5, 4]))
|
||||
assert P.rewrite(BlockDiagMatrix) == \
|
||||
BlockDiagMatrix(P10, P10, P10)
|
||||
|
||||
P = PermutationMatrix(Permutation([0, 4, 3, 2, 1, 5]))
|
||||
P3210 = PermutationMatrix(Permutation([3, 2, 1, 0]))
|
||||
assert P.rewrite(BlockDiagMatrix) == \
|
||||
BlockDiagMatrix(P0, P3210, P0)
|
||||
|
||||
P = PermutationMatrix(Permutation([0, 4, 2, 3, 1, 5]))
|
||||
P3120 = PermutationMatrix(Permutation([3, 1, 2, 0]))
|
||||
assert P.rewrite(BlockDiagMatrix) == \
|
||||
BlockDiagMatrix(P0, P3120, P0)
|
||||
|
||||
P = PermutationMatrix(Permutation(0, 3)(1, 4)(2, 5))
|
||||
assert P.rewrite(BlockDiagMatrix) == BlockDiagMatrix(P)
|
||||
|
||||
|
||||
def test_MartrixPermute_basic():
|
||||
p = Permutation(0, 1)
|
||||
P = PermutationMatrix(p)
|
||||
A = MatrixSymbol('A', 2, 2)
|
||||
|
||||
raises(ValueError, lambda: MatrixPermute(Symbol('x'), p))
|
||||
raises(ValueError, lambda: MatrixPermute(A, Symbol('x')))
|
||||
|
||||
assert MatrixPermute(A, P) == MatrixPermute(A, p)
|
||||
raises(ValueError, lambda: MatrixPermute(A, p, 2))
|
||||
|
||||
pp = Permutation(0, 1, size=3)
|
||||
assert MatrixPermute(A, pp) == MatrixPermute(A, p)
|
||||
pp = Permutation(0, 1, 2)
|
||||
raises(ValueError, lambda: MatrixPermute(A, pp))
|
||||
|
||||
|
||||
def test_MatrixPermute_shape():
|
||||
p = Permutation(0, 1)
|
||||
A = MatrixSymbol('A', 2, 3)
|
||||
assert MatrixPermute(A, p).shape == (2, 3)
|
||||
|
||||
|
||||
def test_MatrixPermute_explicit():
|
||||
p = Permutation(0, 1, 2)
|
||||
A = MatrixSymbol('A', 3, 3)
|
||||
AA = A.as_explicit()
|
||||
assert MatrixPermute(A, p, 0).as_explicit() == \
|
||||
AA.permute(p, orientation='rows')
|
||||
assert MatrixPermute(A, p, 1).as_explicit() == \
|
||||
AA.permute(p, orientation='cols')
|
||||
|
||||
|
||||
def test_MatrixPermute_rewrite_MatMul():
|
||||
p = Permutation(0, 1, 2)
|
||||
A = MatrixSymbol('A', 3, 3)
|
||||
|
||||
assert MatrixPermute(A, p, 0).rewrite(MatMul).as_explicit() == \
|
||||
MatrixPermute(A, p, 0).as_explicit()
|
||||
assert MatrixPermute(A, p, 1).rewrite(MatMul).as_explicit() == \
|
||||
MatrixPermute(A, p, 1).as_explicit()
|
||||
|
||||
|
||||
def test_MatrixPermute_doit():
|
||||
p = Permutation(0, 1, 2)
|
||||
A = MatrixSymbol('A', 3, 3)
|
||||
assert MatrixPermute(A, p).doit() == MatrixPermute(A, p)
|
||||
|
||||
p = Permutation(0, size=3)
|
||||
A = MatrixSymbol('A', 3, 3)
|
||||
assert MatrixPermute(A, p).doit().as_explicit() == \
|
||||
MatrixPermute(A, p).as_explicit()
|
||||
|
||||
p = Permutation(0, 1, 2)
|
||||
A = Identity(3)
|
||||
assert MatrixPermute(A, p, 0).doit().as_explicit() == \
|
||||
MatrixPermute(A, p, 0).as_explicit()
|
||||
assert MatrixPermute(A, p, 1).doit().as_explicit() == \
|
||||
MatrixPermute(A, p, 1).as_explicit()
|
||||
|
||||
A = ZeroMatrix(3, 3)
|
||||
assert MatrixPermute(A, p).doit() == A
|
||||
A = OneMatrix(3, 3)
|
||||
assert MatrixPermute(A, p).doit() == A
|
||||
|
||||
A = MatrixSymbol('A', 4, 4)
|
||||
p1 = Permutation(0, 1, 2, 3)
|
||||
p2 = Permutation(0, 2, 3, 1)
|
||||
expr = MatrixPermute(MatrixPermute(A, p1, 0), p2, 0)
|
||||
assert expr.as_explicit() == expr.doit().as_explicit()
|
||||
expr = MatrixPermute(MatrixPermute(A, p1, 1), p2, 1)
|
||||
assert expr.as_explicit() == expr.doit().as_explicit()
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.matrices import Matrix
|
||||
from sympy.matrices.expressions.matexpr import MatrixSymbol
|
||||
from sympy.matrices.expressions.sets import MatrixSet
|
||||
from sympy.matrices.expressions.special import ZeroMatrix
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.sets.sets import SetKind
|
||||
from sympy.matrices.kind import MatrixKind
|
||||
from sympy.core.kind import NumberKind
|
||||
|
||||
|
||||
def test_MatrixSet():
|
||||
n, m = symbols('n m', integer=True)
|
||||
A = MatrixSymbol('A', n, m)
|
||||
C = MatrixSymbol('C', n, n)
|
||||
|
||||
M = MatrixSet(2, 2, set=S.Reals)
|
||||
assert M.shape == (2, 2)
|
||||
assert M.set == S.Reals
|
||||
X = Matrix([[1, 2], [3, 4]])
|
||||
assert X in M
|
||||
X = ZeroMatrix(2, 2)
|
||||
assert X in M
|
||||
raises(TypeError, lambda: A in M)
|
||||
raises(TypeError, lambda: 1 in M)
|
||||
M = MatrixSet(n, m, set=S.Reals)
|
||||
assert A in M
|
||||
raises(TypeError, lambda: C in M)
|
||||
raises(TypeError, lambda: X in M)
|
||||
M = MatrixSet(2, 2, set={1, 2, 3})
|
||||
X = Matrix([[1, 2], [3, 4]])
|
||||
Y = Matrix([[1, 2]])
|
||||
assert (X in M) == S.false
|
||||
assert (Y in M) == S.false
|
||||
raises(ValueError, lambda: MatrixSet(2, -2, S.Reals))
|
||||
raises(ValueError, lambda: MatrixSet(2.4, -1, S.Reals))
|
||||
raises(TypeError, lambda: MatrixSet(2, 2, (1, 2, 3)))
|
||||
|
||||
|
||||
def test_SetKind_MatrixSet():
|
||||
assert MatrixSet(2, 2, set=S.Reals).kind is SetKind(MatrixKind(NumberKind))
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
from sympy.matrices.expressions.slice import MatrixSlice
|
||||
from sympy.matrices.expressions import MatrixSymbol
|
||||
from sympy.abc import a, b, c, d, k, l, m, n
|
||||
from sympy.testing.pytest import raises, XFAIL
|
||||
from sympy.functions.elementary.integers import floor
|
||||
from sympy.assumptions import assuming, Q
|
||||
|
||||
|
||||
X = MatrixSymbol('X', n, m)
|
||||
Y = MatrixSymbol('Y', m, k)
|
||||
|
||||
def test_shape():
|
||||
B = MatrixSlice(X, (a, b), (c, d))
|
||||
assert B.shape == (b - a, d - c)
|
||||
|
||||
def test_entry():
|
||||
B = MatrixSlice(X, (a, b), (c, d))
|
||||
assert B[0,0] == X[a, c]
|
||||
assert B[k,l] == X[a+k, c+l]
|
||||
raises(IndexError, lambda : MatrixSlice(X, 1, (2, 5))[1, 0])
|
||||
|
||||
assert X[1::2, :][1, 3] == X[1+2, 3]
|
||||
assert X[:, 1::2][3, 1] == X[3, 1+2]
|
||||
|
||||
def test_on_diag():
|
||||
assert not MatrixSlice(X, (a, b), (c, d)).on_diag
|
||||
assert MatrixSlice(X, (a, b), (a, b)).on_diag
|
||||
|
||||
def test_inputs():
|
||||
assert MatrixSlice(X, 1, (2, 5)) == MatrixSlice(X, (1, 2), (2, 5))
|
||||
assert MatrixSlice(X, 1, (2, 5)).shape == (1, 3)
|
||||
|
||||
def test_slicing():
|
||||
assert X[1:5, 2:4] == MatrixSlice(X, (1, 5), (2, 4))
|
||||
assert X[1, 2:4] == MatrixSlice(X, 1, (2, 4))
|
||||
assert X[1:5, :].shape == (4, X.shape[1])
|
||||
assert X[:, 1:5].shape == (X.shape[0], 4)
|
||||
|
||||
assert X[::2, ::2].shape == (floor(n/2), floor(m/2))
|
||||
assert X[2, :] == MatrixSlice(X, 2, (0, m))
|
||||
assert X[k, :] == MatrixSlice(X, k, (0, m))
|
||||
|
||||
def test_exceptions():
|
||||
X = MatrixSymbol('x', 10, 20)
|
||||
raises(IndexError, lambda: X[0:12, 2])
|
||||
raises(IndexError, lambda: X[0:9, 22])
|
||||
raises(IndexError, lambda: X[-1:5, 2])
|
||||
|
||||
@XFAIL
|
||||
def test_symmetry():
|
||||
X = MatrixSymbol('x', 10, 10)
|
||||
Y = X[:5, 5:]
|
||||
with assuming(Q.symmetric(X)):
|
||||
assert Y.T == X[5:, :5]
|
||||
|
||||
def test_slice_of_slice():
|
||||
X = MatrixSymbol('x', 10, 10)
|
||||
assert X[2, :][:, 3][0, 0] == X[2, 3]
|
||||
assert X[:5, :5][:4, :4] == X[:4, :4]
|
||||
assert X[1:5, 2:6][1:3, 2] == X[2:4, 4]
|
||||
assert X[1:9:2, 2:6][1:3, 2] == X[3:7:2, 4]
|
||||
|
||||
def test_negative_index():
|
||||
X = MatrixSymbol('x', 10, 10)
|
||||
assert X[-1, :] == X[9, :]
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
from sympy.core.add import Add
|
||||
from sympy.core.expr import unchanged
|
||||
from sympy.core.mul import Mul
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.core.relational import Eq
|
||||
from sympy.concrete.summations import Sum
|
||||
from sympy.functions.elementary.complexes import im, re
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.matrices.immutable import ImmutableDenseMatrix
|
||||
from sympy.matrices.expressions.matexpr import MatrixSymbol
|
||||
from sympy.matrices.expressions.matadd import MatAdd
|
||||
from sympy.matrices.expressions.special import (
|
||||
ZeroMatrix, GenericZeroMatrix, Identity, GenericIdentity, OneMatrix)
|
||||
from sympy.matrices.expressions.matmul import MatMul
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
def test_zero_matrix_creation():
|
||||
assert unchanged(ZeroMatrix, 2, 2)
|
||||
assert unchanged(ZeroMatrix, 0, 0)
|
||||
raises(ValueError, lambda: ZeroMatrix(-1, 2))
|
||||
raises(ValueError, lambda: ZeroMatrix(2.0, 2))
|
||||
raises(ValueError, lambda: ZeroMatrix(2j, 2))
|
||||
raises(ValueError, lambda: ZeroMatrix(2, -1))
|
||||
raises(ValueError, lambda: ZeroMatrix(2, 2.0))
|
||||
raises(ValueError, lambda: ZeroMatrix(2, 2j))
|
||||
|
||||
n = symbols('n')
|
||||
assert unchanged(ZeroMatrix, n, n)
|
||||
n = symbols('n', integer=False)
|
||||
raises(ValueError, lambda: ZeroMatrix(n, n))
|
||||
n = symbols('n', negative=True)
|
||||
raises(ValueError, lambda: ZeroMatrix(n, n))
|
||||
|
||||
|
||||
def test_generic_zero_matrix():
|
||||
z = GenericZeroMatrix()
|
||||
n = symbols('n', integer=True)
|
||||
A = MatrixSymbol("A", n, n)
|
||||
|
||||
assert z == z
|
||||
assert z != A
|
||||
assert A != z
|
||||
|
||||
assert z.is_ZeroMatrix
|
||||
|
||||
raises(TypeError, lambda: z.shape)
|
||||
raises(TypeError, lambda: z.rows)
|
||||
raises(TypeError, lambda: z.cols)
|
||||
|
||||
assert MatAdd() == z
|
||||
assert MatAdd(z, A) == MatAdd(A)
|
||||
# Make sure it is hashable
|
||||
hash(z)
|
||||
|
||||
|
||||
def test_identity_matrix_creation():
|
||||
assert Identity(2)
|
||||
assert Identity(0)
|
||||
raises(ValueError, lambda: Identity(-1))
|
||||
raises(ValueError, lambda: Identity(2.0))
|
||||
raises(ValueError, lambda: Identity(2j))
|
||||
|
||||
n = symbols('n')
|
||||
assert Identity(n)
|
||||
n = symbols('n', integer=False)
|
||||
raises(ValueError, lambda: Identity(n))
|
||||
n = symbols('n', negative=True)
|
||||
raises(ValueError, lambda: Identity(n))
|
||||
|
||||
|
||||
def test_generic_identity():
|
||||
I = GenericIdentity()
|
||||
n = symbols('n', integer=True)
|
||||
A = MatrixSymbol("A", n, n)
|
||||
|
||||
assert I == I
|
||||
assert I != A
|
||||
assert A != I
|
||||
|
||||
assert I.is_Identity
|
||||
assert I**-1 == I
|
||||
|
||||
raises(TypeError, lambda: I.shape)
|
||||
raises(TypeError, lambda: I.rows)
|
||||
raises(TypeError, lambda: I.cols)
|
||||
|
||||
assert MatMul() == I
|
||||
assert MatMul(I, A) == MatMul(A)
|
||||
# Make sure it is hashable
|
||||
hash(I)
|
||||
|
||||
|
||||
def test_one_matrix_creation():
|
||||
assert OneMatrix(2, 2)
|
||||
assert OneMatrix(0, 0)
|
||||
assert Eq(OneMatrix(1, 1), Identity(1))
|
||||
raises(ValueError, lambda: OneMatrix(-1, 2))
|
||||
raises(ValueError, lambda: OneMatrix(2.0, 2))
|
||||
raises(ValueError, lambda: OneMatrix(2j, 2))
|
||||
raises(ValueError, lambda: OneMatrix(2, -1))
|
||||
raises(ValueError, lambda: OneMatrix(2, 2.0))
|
||||
raises(ValueError, lambda: OneMatrix(2, 2j))
|
||||
|
||||
n = symbols('n')
|
||||
assert OneMatrix(n, n)
|
||||
n = symbols('n', integer=False)
|
||||
raises(ValueError, lambda: OneMatrix(n, n))
|
||||
n = symbols('n', negative=True)
|
||||
raises(ValueError, lambda: OneMatrix(n, n))
|
||||
|
||||
|
||||
def test_ZeroMatrix():
|
||||
n, m = symbols('n m', integer=True)
|
||||
A = MatrixSymbol('A', n, m)
|
||||
Z = ZeroMatrix(n, m)
|
||||
|
||||
assert A + Z == A
|
||||
assert A*Z.T == ZeroMatrix(n, n)
|
||||
assert Z*A.T == ZeroMatrix(n, n)
|
||||
assert A - A == ZeroMatrix(*A.shape)
|
||||
|
||||
assert Z
|
||||
|
||||
assert Z.transpose() == ZeroMatrix(m, n)
|
||||
assert Z.conjugate() == Z
|
||||
assert Z.adjoint() == ZeroMatrix(m, n)
|
||||
assert re(Z) == Z
|
||||
assert im(Z) == Z
|
||||
|
||||
assert ZeroMatrix(n, n)**0 == Identity(n)
|
||||
assert ZeroMatrix(3, 3).as_explicit() == ImmutableDenseMatrix.zeros(3, 3)
|
||||
|
||||
|
||||
def test_ZeroMatrix_doit():
|
||||
n = symbols('n', integer=True)
|
||||
Znn = ZeroMatrix(Add(n, n, evaluate=False), n)
|
||||
assert isinstance(Znn.rows, Add)
|
||||
assert Znn.doit() == ZeroMatrix(2*n, n)
|
||||
assert isinstance(Znn.doit().rows, Mul)
|
||||
|
||||
|
||||
def test_OneMatrix():
|
||||
n, m = symbols('n m', integer=True)
|
||||
A = MatrixSymbol('A', n, m)
|
||||
U = OneMatrix(n, m)
|
||||
|
||||
assert U.shape == (n, m)
|
||||
assert isinstance(A + U, Add)
|
||||
assert U.transpose() == OneMatrix(m, n)
|
||||
assert U.conjugate() == U
|
||||
assert U.adjoint() == OneMatrix(m, n)
|
||||
assert re(U) == U
|
||||
assert im(U) == ZeroMatrix(n, m)
|
||||
|
||||
assert OneMatrix(n, n) ** 0 == Identity(n)
|
||||
|
||||
U = OneMatrix(n, n)
|
||||
assert U[1, 2] == 1
|
||||
|
||||
U = OneMatrix(2, 3)
|
||||
assert U.as_explicit() == ImmutableDenseMatrix.ones(2, 3)
|
||||
|
||||
|
||||
def test_OneMatrix_doit():
|
||||
n = symbols('n', integer=True)
|
||||
Unn = OneMatrix(Add(n, n, evaluate=False), n)
|
||||
assert isinstance(Unn.rows, Add)
|
||||
assert Unn.doit() == OneMatrix(2 * n, n)
|
||||
assert isinstance(Unn.doit().rows, Mul)
|
||||
|
||||
|
||||
def test_OneMatrix_mul():
|
||||
n, m, k = symbols('n m k', integer=True)
|
||||
w = MatrixSymbol('w', n, 1)
|
||||
assert OneMatrix(n, m) * OneMatrix(m, k) == OneMatrix(n, k) * m
|
||||
assert w * OneMatrix(1, 1) == w
|
||||
assert OneMatrix(1, 1) * w.T == w.T
|
||||
|
||||
|
||||
def test_Identity():
|
||||
n, m = symbols('n m', integer=True)
|
||||
A = MatrixSymbol('A', n, m)
|
||||
i, j = symbols('i j')
|
||||
|
||||
In = Identity(n)
|
||||
Im = Identity(m)
|
||||
|
||||
assert A*Im == A
|
||||
assert In*A == A
|
||||
|
||||
assert In.transpose() == In
|
||||
assert In.inverse() == In
|
||||
assert In.conjugate() == In
|
||||
assert In.adjoint() == In
|
||||
assert re(In) == In
|
||||
assert im(In) == ZeroMatrix(n, n)
|
||||
|
||||
assert In[i, j] != 0
|
||||
assert Sum(In[i, j], (i, 0, n-1), (j, 0, n-1)).subs(n,3).doit() == 3
|
||||
assert Sum(Sum(In[i, j], (i, 0, n-1)), (j, 0, n-1)).subs(n,3).doit() == 3
|
||||
|
||||
# If range exceeds the limit `(0, n-1)`, do not remove `Piecewise`:
|
||||
expr = Sum(In[i, j], (i, 0, n-1))
|
||||
assert expr.doit() == 1
|
||||
expr = Sum(In[i, j], (i, 0, n-2))
|
||||
assert expr.doit().dummy_eq(
|
||||
Piecewise(
|
||||
(1, (j >= 0) & (j <= n-2)),
|
||||
(0, True)
|
||||
)
|
||||
)
|
||||
expr = Sum(In[i, j], (i, 1, n-1))
|
||||
assert expr.doit().dummy_eq(
|
||||
Piecewise(
|
||||
(1, (j >= 1) & (j <= n-1)),
|
||||
(0, True)
|
||||
)
|
||||
)
|
||||
assert Identity(3).as_explicit() == ImmutableDenseMatrix.eye(3)
|
||||
|
||||
|
||||
def test_Identity_doit():
|
||||
n = symbols('n', integer=True)
|
||||
Inn = Identity(Add(n, n, evaluate=False))
|
||||
assert isinstance(Inn.rows, Add)
|
||||
assert Inn.doit() == Identity(2*n)
|
||||
assert isinstance(Inn.doit().rows, Mul)
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
from sympy.core import Lambda, S, symbols
|
||||
from sympy.concrete import Sum
|
||||
from sympy.functions import adjoint, conjugate, transpose
|
||||
from sympy.matrices import eye, Matrix, ShapeError, ImmutableMatrix
|
||||
from sympy.matrices.expressions import (
|
||||
Adjoint, Identity, FunctionMatrix, MatrixExpr, MatrixSymbol, Trace,
|
||||
ZeroMatrix, trace, MatPow, MatAdd, MatMul
|
||||
)
|
||||
from sympy.matrices.expressions.special import OneMatrix
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.abc import i
|
||||
|
||||
|
||||
n = symbols('n', integer=True)
|
||||
A = MatrixSymbol('A', n, n)
|
||||
B = MatrixSymbol('B', n, n)
|
||||
C = MatrixSymbol('C', 3, 4)
|
||||
|
||||
|
||||
def test_Trace():
|
||||
assert isinstance(Trace(A), Trace)
|
||||
assert not isinstance(Trace(A), MatrixExpr)
|
||||
raises(ShapeError, lambda: Trace(C))
|
||||
assert trace(eye(3)) == 3
|
||||
assert trace(Matrix(3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9])) == 15
|
||||
|
||||
assert adjoint(Trace(A)) == trace(Adjoint(A))
|
||||
assert conjugate(Trace(A)) == trace(Adjoint(A))
|
||||
assert transpose(Trace(A)) == Trace(A)
|
||||
|
||||
_ = A / Trace(A) # Make sure this is possible
|
||||
|
||||
# Some easy simplifications
|
||||
assert trace(Identity(5)) == 5
|
||||
assert trace(ZeroMatrix(5, 5)) == 0
|
||||
assert trace(OneMatrix(1, 1)) == 1
|
||||
assert trace(OneMatrix(2, 2)) == 2
|
||||
assert trace(OneMatrix(n, n)) == n
|
||||
assert trace(2*A*B) == 2*Trace(A*B)
|
||||
assert trace(A.T) == trace(A)
|
||||
|
||||
i, j = symbols('i j')
|
||||
F = FunctionMatrix(3, 3, Lambda((i, j), i + j))
|
||||
assert trace(F) == (0 + 0) + (1 + 1) + (2 + 2)
|
||||
|
||||
raises(TypeError, lambda: Trace(S.One))
|
||||
|
||||
assert Trace(A).arg is A
|
||||
|
||||
assert str(trace(A)) == str(Trace(A).doit())
|
||||
|
||||
assert Trace(A).is_commutative is True
|
||||
|
||||
def test_Trace_A_plus_B():
|
||||
assert trace(A + B) == Trace(A) + Trace(B)
|
||||
assert Trace(A + B).arg == MatAdd(A, B)
|
||||
assert Trace(A + B).doit() == Trace(A) + Trace(B)
|
||||
|
||||
|
||||
def test_Trace_MatAdd_doit():
|
||||
# See issue #9028
|
||||
X = ImmutableMatrix([[1, 2, 3]]*3)
|
||||
Y = MatrixSymbol('Y', 3, 3)
|
||||
q = MatAdd(X, 2*X, Y, -3*Y)
|
||||
assert Trace(q).arg == q
|
||||
assert Trace(q).doit() == 18 - 2*Trace(Y)
|
||||
|
||||
|
||||
def test_Trace_MatPow_doit():
|
||||
X = Matrix([[1, 2], [3, 4]])
|
||||
assert Trace(X).doit() == 5
|
||||
q = MatPow(X, 2)
|
||||
assert Trace(q).arg == q
|
||||
assert Trace(q).doit() == 29
|
||||
|
||||
|
||||
def test_Trace_MutableMatrix_plus():
|
||||
# See issue #9043
|
||||
X = Matrix([[1, 2], [3, 4]])
|
||||
assert Trace(X) + Trace(X) == 2*Trace(X)
|
||||
|
||||
|
||||
def test_Trace_doit_deep_False():
|
||||
X = Matrix([[1, 2], [3, 4]])
|
||||
q = MatPow(X, 2)
|
||||
assert Trace(q).doit(deep=False).arg == q
|
||||
q = MatAdd(X, 2*X)
|
||||
assert Trace(q).doit(deep=False).arg == q
|
||||
q = MatMul(X, 2*X)
|
||||
assert Trace(q).doit(deep=False).arg == q
|
||||
|
||||
|
||||
def test_trace_constant_factor():
|
||||
# Issue 9052: gave 2*Trace(MatMul(A)) instead of 2*Trace(A)
|
||||
assert trace(2*A) == 2*Trace(A)
|
||||
X = ImmutableMatrix([[1, 2], [3, 4]])
|
||||
assert trace(MatMul(2, X)) == 10
|
||||
|
||||
|
||||
def test_trace_rewrite():
|
||||
assert trace(A).rewrite(Sum) == Sum(A[i, i], (i, 0, n - 1))
|
||||
assert trace(eye(3)).rewrite(Sum) == 3
|
||||
|
||||
|
||||
def test_trace_normalize():
|
||||
assert Trace(B*A) != Trace(A*B)
|
||||
assert Trace(B*A)._normalize() == Trace(A*B)
|
||||
assert Trace(B*A.T)._normalize() == Trace(A*B.T)
|
||||
|
||||
|
||||
def test_trace_as_explicit():
|
||||
raises(ValueError, lambda: Trace(A).as_explicit())
|
||||
|
||||
X = MatrixSymbol("X", 3, 3)
|
||||
assert Trace(X).as_explicit() == X[0, 0] + X[1, 1] + X[2, 2]
|
||||
assert Trace(eye(3)).as_explicit() == 3
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
from sympy.functions import adjoint, conjugate, transpose
|
||||
from sympy.matrices.expressions import MatrixSymbol, Adjoint, trace, Transpose
|
||||
from sympy.matrices import eye, Matrix
|
||||
from sympy.assumptions.ask import Q
|
||||
from sympy.assumptions.refine import refine
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import symbols
|
||||
|
||||
n, m, l, k, p = symbols('n m l k p', integer=True)
|
||||
A = MatrixSymbol('A', n, m)
|
||||
B = MatrixSymbol('B', m, l)
|
||||
C = MatrixSymbol('C', n, n)
|
||||
|
||||
|
||||
def test_transpose():
|
||||
Sq = MatrixSymbol('Sq', n, n)
|
||||
|
||||
assert transpose(A) == Transpose(A)
|
||||
assert Transpose(A).shape == (m, n)
|
||||
assert Transpose(A*B).shape == (l, n)
|
||||
assert transpose(Transpose(A)) == A
|
||||
assert isinstance(Transpose(Transpose(A)), Transpose)
|
||||
|
||||
assert adjoint(Transpose(A)) == Adjoint(Transpose(A))
|
||||
assert conjugate(Transpose(A)) == Adjoint(A)
|
||||
|
||||
assert Transpose(eye(3)).doit() == eye(3)
|
||||
|
||||
assert Transpose(S(5)).doit() == S(5)
|
||||
|
||||
assert Transpose(Matrix([[1, 2], [3, 4]])).doit() == Matrix([[1, 3], [2, 4]])
|
||||
|
||||
assert transpose(trace(Sq)) == trace(Sq)
|
||||
assert trace(Transpose(Sq)) == trace(Sq)
|
||||
|
||||
assert Transpose(Sq)[0, 1] == Sq[1, 0]
|
||||
|
||||
assert Transpose(A*B).doit() == Transpose(B) * Transpose(A)
|
||||
|
||||
|
||||
def test_transpose_MatAdd_MatMul():
|
||||
# Issue 16807
|
||||
from sympy.functions.elementary.trigonometric import cos
|
||||
|
||||
x = symbols('x')
|
||||
M = MatrixSymbol('M', 3, 3)
|
||||
N = MatrixSymbol('N', 3, 3)
|
||||
|
||||
assert (N + (cos(x) * M)).T == cos(x)*M.T + N.T
|
||||
|
||||
|
||||
def test_refine():
|
||||
assert refine(C.T, Q.symmetric(C)) == C
|
||||
|
||||
|
||||
def test_transpose1x1():
|
||||
m = MatrixSymbol('m', 1, 1)
|
||||
assert m == refine(m.T)
|
||||
assert m == refine(m.T.T)
|
||||
|
||||
def test_issue_9817():
|
||||
from sympy.matrices.expressions import Identity
|
||||
v = MatrixSymbol('v', 3, 1)
|
||||
A = MatrixSymbol('A', 3, 3)
|
||||
x = Matrix([i + 1 for i in range(3)])
|
||||
X = Identity(3)
|
||||
quadratic = v.T * A * v
|
||||
subbed = quadratic.xreplace({v:x, A:X})
|
||||
assert subbed.as_explicit() == Matrix([[14]])
|
||||
Loading…
Add table
Add a link
Reference in a new issue