switching to high quality piper tts and added label translations
This commit is contained in:
+34
@@ -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)
|
||||
+118
@@ -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
|
||||
+469
@@ -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)
|
||||
+48
@@ -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]])
|
||||
+477
@@ -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
|
||||
+65
@@ -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
|
||||
+156
@@ -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
|
||||
+35
@@ -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
|
||||
+29
@@ -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))
|
||||
+44
@@ -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]])
|
||||
+54
@@ -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
|
||||
+141
@@ -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))
|
||||
+299
@@ -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)
|
||||
+69
@@ -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()
|
||||
+150
@@ -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)]
|
||||
+58
@@ -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))
|
||||
+592
@@ -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
|
||||
+193
@@ -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()
|
||||
+217
@@ -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))
|
||||
+166
@@ -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))
|
||||
+65
@@ -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, :]
|
||||
+228
@@ -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)
|
||||
+116
@@ -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
|
||||
+69
@@ -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]])
|
||||
Reference in New Issue
Block a user