from sympy.assumptions import Q from sympy.core.expr import Expr from sympy.core.add import Add from sympy.core.function import Function from sympy.core.kind import NumberKind, UndefinedKind from sympy.core.numbers import I, Integer, oo, pi, Rational from sympy.core.singleton import S from sympy.core.symbol import Symbol, symbols from sympy.functions.elementary.complexes import Abs from sympy.functions.elementary.exponential import exp from sympy.functions.elementary.miscellaneous import sqrt from sympy.functions.elementary.trigonometric import cos, sin from sympy.matrices.common import (ShapeError, NonSquareMatrixError, _MinimalMatrix, _CastableMatrix, MatrixShaping, MatrixProperties, MatrixOperations, MatrixArithmetic, MatrixSpecial, MatrixKind) from sympy.matrices.matrices import MatrixCalculus from sympy.matrices import (Matrix, diag, eye, matrix_multiply_elementwise, ones, zeros, SparseMatrix, banded, MutableDenseMatrix, MutableSparseMatrix, ImmutableDenseMatrix, ImmutableSparseMatrix) from sympy.polys.polytools import Poly from sympy.utilities.iterables import flatten from sympy.testing.pytest import raises, XFAIL from sympy.tensor.array.dense_ndim_array import ImmutableDenseNDimArray as Array from sympy.abc import x, y, z # classes to test the basic matrix classes class ShapingOnlyMatrix(_MinimalMatrix, _CastableMatrix, MatrixShaping): pass def eye_Shaping(n): return ShapingOnlyMatrix(n, n, lambda i, j: int(i == j)) def zeros_Shaping(n): return ShapingOnlyMatrix(n, n, lambda i, j: 0) class PropertiesOnlyMatrix(_MinimalMatrix, _CastableMatrix, MatrixProperties): pass def eye_Properties(n): return PropertiesOnlyMatrix(n, n, lambda i, j: int(i == j)) def zeros_Properties(n): return PropertiesOnlyMatrix(n, n, lambda i, j: 0) class OperationsOnlyMatrix(_MinimalMatrix, _CastableMatrix, MatrixOperations): pass def eye_Operations(n): return OperationsOnlyMatrix(n, n, lambda i, j: int(i == j)) def zeros_Operations(n): return OperationsOnlyMatrix(n, n, lambda i, j: 0) class ArithmeticOnlyMatrix(_MinimalMatrix, _CastableMatrix, MatrixArithmetic): pass def eye_Arithmetic(n): return ArithmeticOnlyMatrix(n, n, lambda i, j: int(i == j)) def zeros_Arithmetic(n): return ArithmeticOnlyMatrix(n, n, lambda i, j: 0) class SpecialOnlyMatrix(_MinimalMatrix, _CastableMatrix, MatrixSpecial): pass class CalculusOnlyMatrix(_MinimalMatrix, _CastableMatrix, MatrixCalculus): pass def test__MinimalMatrix(): x = _MinimalMatrix(2, 3, [1, 2, 3, 4, 5, 6]) assert x.rows == 2 assert x.cols == 3 assert x[2] == 3 assert x[1, 1] == 5 assert list(x) == [1, 2, 3, 4, 5, 6] assert list(x[1, :]) == [4, 5, 6] assert list(x[:, 1]) == [2, 5] assert list(x[:, :]) == list(x) assert x[:, :] == x assert _MinimalMatrix(x) == x assert _MinimalMatrix([[1, 2, 3], [4, 5, 6]]) == x assert _MinimalMatrix(([1, 2, 3], [4, 5, 6])) == x assert _MinimalMatrix([(1, 2, 3), (4, 5, 6)]) == x assert _MinimalMatrix(((1, 2, 3), (4, 5, 6))) == x assert not (_MinimalMatrix([[1, 2], [3, 4], [5, 6]]) == x) def test_kind(): assert Matrix([[1, 2], [3, 4]]).kind == MatrixKind(NumberKind) assert Matrix([[0, 0], [0, 0]]).kind == MatrixKind(NumberKind) assert Matrix(0, 0, []).kind == MatrixKind(NumberKind) assert Matrix([[x]]).kind == MatrixKind(NumberKind) assert Matrix([[1, Matrix([[1]])]]).kind == MatrixKind(UndefinedKind) assert SparseMatrix([[1]]).kind == MatrixKind(NumberKind) assert SparseMatrix([[1, Matrix([[1]])]]).kind == MatrixKind(UndefinedKind) # ShapingOnlyMatrix tests def test_vec(): m = ShapingOnlyMatrix(2, 2, [1, 3, 2, 4]) m_vec = m.vec() assert m_vec.cols == 1 for i in range(4): assert m_vec[i] == i + 1 def test_todok(): a, b, c, d = symbols('a:d') m1 = MutableDenseMatrix([[a, b], [c, d]]) m2 = ImmutableDenseMatrix([[a, b], [c, d]]) m3 = MutableSparseMatrix([[a, b], [c, d]]) m4 = ImmutableSparseMatrix([[a, b], [c, d]]) assert m1.todok() == m2.todok() == m3.todok() == m4.todok() == \ {(0, 0): a, (0, 1): b, (1, 0): c, (1, 1): d} def test_tolist(): lst = [[S.One, S.Half, x*y, S.Zero], [x, y, z, x**2], [y, -S.One, z*x, 3]] flat_lst = [S.One, S.Half, x*y, S.Zero, x, y, z, x**2, y, -S.One, z*x, 3] m = ShapingOnlyMatrix(3, 4, flat_lst) assert m.tolist() == lst def test_todod(): m = ShapingOnlyMatrix(3, 2, [[S.One, 0], [0, S.Half], [x, 0]]) dict = {0: {0: S.One}, 1: {1: S.Half}, 2: {0: x}} assert m.todod() == dict def test_row_col_del(): e = ShapingOnlyMatrix(3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9]) raises(IndexError, lambda: e.row_del(5)) raises(IndexError, lambda: e.row_del(-5)) raises(IndexError, lambda: e.col_del(5)) raises(IndexError, lambda: e.col_del(-5)) assert e.row_del(2) == e.row_del(-1) == Matrix([[1, 2, 3], [4, 5, 6]]) assert e.col_del(2) == e.col_del(-1) == Matrix([[1, 2], [4, 5], [7, 8]]) assert e.row_del(1) == e.row_del(-2) == Matrix([[1, 2, 3], [7, 8, 9]]) assert e.col_del(1) == e.col_del(-2) == Matrix([[1, 3], [4, 6], [7, 9]]) def test_get_diag_blocks1(): a = Matrix([[1, 2], [2, 3]]) b = Matrix([[3, x], [y, 3]]) c = Matrix([[3, x, 3], [y, 3, z], [x, y, z]]) assert a.get_diag_blocks() == [a] assert b.get_diag_blocks() == [b] assert c.get_diag_blocks() == [c] def test_get_diag_blocks2(): a = Matrix([[1, 2], [2, 3]]) b = Matrix([[3, x], [y, 3]]) c = Matrix([[3, x, 3], [y, 3, z], [x, y, z]]) A, B, C, D = diag(a, b, b), diag(a, b, c), diag(a, c, b), diag(c, c, b) A = ShapingOnlyMatrix(A.rows, A.cols, A) B = ShapingOnlyMatrix(B.rows, B.cols, B) C = ShapingOnlyMatrix(C.rows, C.cols, C) D = ShapingOnlyMatrix(D.rows, D.cols, D) assert A.get_diag_blocks() == [a, b, b] assert B.get_diag_blocks() == [a, b, c] assert C.get_diag_blocks() == [a, c, b] assert D.get_diag_blocks() == [c, c, b] def test_shape(): m = ShapingOnlyMatrix(1, 2, [0, 0]) assert m.shape == (1, 2) def test_reshape(): m0 = eye_Shaping(3) assert m0.reshape(1, 9) == Matrix(1, 9, (1, 0, 0, 0, 1, 0, 0, 0, 1)) m1 = ShapingOnlyMatrix(3, 4, lambda i, j: i + j) assert m1.reshape( 4, 3) == Matrix(((0, 1, 2), (3, 1, 2), (3, 4, 2), (3, 4, 5))) assert m1.reshape(2, 6) == Matrix(((0, 1, 2, 3, 1, 2), (3, 4, 2, 3, 4, 5))) def test_row_col(): m = ShapingOnlyMatrix(3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9]) assert m.row(0) == Matrix(1, 3, [1, 2, 3]) assert m.col(0) == Matrix(3, 1, [1, 4, 7]) def test_row_join(): assert eye_Shaping(3).row_join(Matrix([7, 7, 7])) == \ Matrix([[1, 0, 0, 7], [0, 1, 0, 7], [0, 0, 1, 7]]) def test_col_join(): assert eye_Shaping(3).col_join(Matrix([[7, 7, 7]])) == \ Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1], [7, 7, 7]]) def test_row_insert(): r4 = Matrix([[4, 4, 4]]) for i in range(-4, 5): l = [1, 0, 0] l.insert(i, 4) assert flatten(eye_Shaping(3).row_insert(i, r4).col(0).tolist()) == l def test_col_insert(): c4 = Matrix([4, 4, 4]) for i in range(-4, 5): l = [0, 0, 0] l.insert(i, 4) assert flatten(zeros_Shaping(3).col_insert(i, c4).row(0).tolist()) == l # issue 13643 assert eye_Shaping(6).col_insert(3, Matrix([[2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2]])) == \ Matrix([[1, 0, 0, 2, 2, 0, 0, 0], [0, 1, 0, 2, 2, 0, 0, 0], [0, 0, 1, 2, 2, 0, 0, 0], [0, 0, 0, 2, 2, 1, 0, 0], [0, 0, 0, 2, 2, 0, 1, 0], [0, 0, 0, 2, 2, 0, 0, 1]]) def test_extract(): m = ShapingOnlyMatrix(4, 3, lambda i, j: i*3 + j) assert m.extract([0, 1, 3], [0, 1]) == Matrix(3, 2, [0, 1, 3, 4, 9, 10]) assert m.extract([0, 3], [0, 0, 2]) == Matrix(2, 3, [0, 0, 2, 9, 9, 11]) assert m.extract(range(4), range(3)) == m raises(IndexError, lambda: m.extract([4], [0])) raises(IndexError, lambda: m.extract([0], [3])) def test_hstack(): m = ShapingOnlyMatrix(4, 3, lambda i, j: i*3 + j) m2 = ShapingOnlyMatrix(3, 4, lambda i, j: i*3 + j) assert m == m.hstack(m) assert m.hstack(m, m, m) == ShapingOnlyMatrix.hstack(m, m, m) == Matrix([ [0, 1, 2, 0, 1, 2, 0, 1, 2], [3, 4, 5, 3, 4, 5, 3, 4, 5], [6, 7, 8, 6, 7, 8, 6, 7, 8], [9, 10, 11, 9, 10, 11, 9, 10, 11]]) raises(ShapeError, lambda: m.hstack(m, m2)) assert Matrix.hstack() == Matrix() # test regression #12938 M1 = Matrix.zeros(0, 0) M2 = Matrix.zeros(0, 1) M3 = Matrix.zeros(0, 2) M4 = Matrix.zeros(0, 3) m = ShapingOnlyMatrix.hstack(M1, M2, M3, M4) assert m.rows == 0 and m.cols == 6 def test_vstack(): m = ShapingOnlyMatrix(4, 3, lambda i, j: i*3 + j) m2 = ShapingOnlyMatrix(3, 4, lambda i, j: i*3 + j) assert m == m.vstack(m) assert m.vstack(m, m, m) == ShapingOnlyMatrix.vstack(m, m, m) == Matrix([ [0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]) raises(ShapeError, lambda: m.vstack(m, m2)) assert Matrix.vstack() == Matrix() # PropertiesOnlyMatrix tests def test_atoms(): m = PropertiesOnlyMatrix(2, 2, [1, 2, x, 1 - 1/x]) assert m.atoms() == {S.One, S(2), S.NegativeOne, x} assert m.atoms(Symbol) == {x} def test_free_symbols(): assert PropertiesOnlyMatrix([[x], [0]]).free_symbols == {x} def test_has(): A = PropertiesOnlyMatrix(((x, y), (2, 3))) assert A.has(x) assert not A.has(z) assert A.has(Symbol) A = PropertiesOnlyMatrix(((2, y), (2, 3))) assert not A.has(x) def test_is_anti_symmetric(): x = symbols('x') assert PropertiesOnlyMatrix(2, 1, [1, 2]).is_anti_symmetric() is False m = PropertiesOnlyMatrix(3, 3, [0, x**2 + 2*x + 1, y, -(x + 1)**2, 0, x*y, -y, -x*y, 0]) assert m.is_anti_symmetric() is True assert m.is_anti_symmetric(simplify=False) is False assert m.is_anti_symmetric(simplify=lambda x: x) is False m = PropertiesOnlyMatrix(3, 3, [x.expand() for x in m]) assert m.is_anti_symmetric(simplify=False) is True m = PropertiesOnlyMatrix(3, 3, [x.expand() for x in [S.One] + list(m)[1:]]) assert m.is_anti_symmetric() is False def test_diagonal_symmetrical(): m = PropertiesOnlyMatrix(2, 2, [0, 1, 1, 0]) assert not m.is_diagonal() assert m.is_symmetric() assert m.is_symmetric(simplify=False) m = PropertiesOnlyMatrix(2, 2, [1, 0, 0, 1]) assert m.is_diagonal() m = PropertiesOnlyMatrix(3, 3, diag(1, 2, 3)) assert m.is_diagonal() assert m.is_symmetric() m = PropertiesOnlyMatrix(3, 3, [1, 0, 0, 0, 2, 0, 0, 0, 3]) assert m == diag(1, 2, 3) m = PropertiesOnlyMatrix(2, 3, zeros(2, 3)) assert not m.is_symmetric() assert m.is_diagonal() m = PropertiesOnlyMatrix(((5, 0), (0, 6), (0, 0))) assert m.is_diagonal() m = PropertiesOnlyMatrix(((5, 0, 0), (0, 6, 0))) assert m.is_diagonal() m = Matrix(3, 3, [1, x**2 + 2*x + 1, y, (x + 1)**2, 2, 0, y, 0, 3]) assert m.is_symmetric() assert not m.is_symmetric(simplify=False) assert m.expand().is_symmetric(simplify=False) def test_is_hermitian(): a = PropertiesOnlyMatrix([[1, I], [-I, 1]]) assert a.is_hermitian a = PropertiesOnlyMatrix([[2*I, I], [-I, 1]]) assert a.is_hermitian is False a = PropertiesOnlyMatrix([[x, I], [-I, 1]]) assert a.is_hermitian is None a = PropertiesOnlyMatrix([[x, 1], [-I, 1]]) assert a.is_hermitian is False def test_is_Identity(): assert eye_Properties(3).is_Identity assert not PropertiesOnlyMatrix(zeros(3)).is_Identity assert not PropertiesOnlyMatrix(ones(3)).is_Identity # issue 6242 assert not PropertiesOnlyMatrix([[1, 0, 0]]).is_Identity def test_is_symbolic(): a = PropertiesOnlyMatrix([[x, x], [x, x]]) assert a.is_symbolic() is True a = PropertiesOnlyMatrix([[1, 2, 3, 4], [5, 6, 7, 8]]) assert a.is_symbolic() is False a = PropertiesOnlyMatrix([[1, 2, 3, 4], [5, 6, x, 8]]) assert a.is_symbolic() is True a = PropertiesOnlyMatrix([[1, x, 3]]) assert a.is_symbolic() is True a = PropertiesOnlyMatrix([[1, 2, 3]]) assert a.is_symbolic() is False a = PropertiesOnlyMatrix([[1], [x], [3]]) assert a.is_symbolic() is True a = PropertiesOnlyMatrix([[1], [2], [3]]) assert a.is_symbolic() is False def test_is_upper(): a = PropertiesOnlyMatrix([[1, 2, 3]]) assert a.is_upper is True a = PropertiesOnlyMatrix([[1], [2], [3]]) assert a.is_upper is False def test_is_lower(): a = PropertiesOnlyMatrix([[1, 2, 3]]) assert a.is_lower is False a = PropertiesOnlyMatrix([[1], [2], [3]]) assert a.is_lower is True def test_is_square(): m = PropertiesOnlyMatrix([[1], [1]]) m2 = PropertiesOnlyMatrix([[2, 2], [2, 2]]) assert not m.is_square assert m2.is_square def test_is_symmetric(): m = PropertiesOnlyMatrix(2, 2, [0, 1, 1, 0]) assert m.is_symmetric() m = PropertiesOnlyMatrix(2, 2, [0, 1, 0, 1]) assert not m.is_symmetric() def test_is_hessenberg(): A = PropertiesOnlyMatrix([[3, 4, 1], [2, 4, 5], [0, 1, 2]]) assert A.is_upper_hessenberg A = PropertiesOnlyMatrix(3, 3, [3, 2, 0, 4, 4, 1, 1, 5, 2]) assert A.is_lower_hessenberg A = PropertiesOnlyMatrix(3, 3, [3, 2, -1, 4, 4, 1, 1, 5, 2]) assert A.is_lower_hessenberg is False assert A.is_upper_hessenberg is False A = PropertiesOnlyMatrix([[3, 4, 1], [2, 4, 5], [3, 1, 2]]) assert not A.is_upper_hessenberg def test_is_zero(): assert PropertiesOnlyMatrix(0, 0, []).is_zero_matrix assert PropertiesOnlyMatrix([[0, 0], [0, 0]]).is_zero_matrix assert PropertiesOnlyMatrix(zeros(3, 4)).is_zero_matrix assert not PropertiesOnlyMatrix(eye(3)).is_zero_matrix assert PropertiesOnlyMatrix([[x, 0], [0, 0]]).is_zero_matrix == None assert PropertiesOnlyMatrix([[x, 1], [0, 0]]).is_zero_matrix == False a = Symbol('a', nonzero=True) assert PropertiesOnlyMatrix([[a, 0], [0, 0]]).is_zero_matrix == False def test_values(): assert set(PropertiesOnlyMatrix(2, 2, [0, 1, 2, 3] ).values()) == {1, 2, 3} x = Symbol('x', real=True) assert set(PropertiesOnlyMatrix(2, 2, [x, 0, 0, 1] ).values()) == {x, 1} # OperationsOnlyMatrix tests def test_applyfunc(): m0 = OperationsOnlyMatrix(eye(3)) assert m0.applyfunc(lambda x: 2*x) == eye(3)*2 assert m0.applyfunc(lambda x: 0) == zeros(3) assert m0.applyfunc(lambda x: 1) == ones(3) def test_adjoint(): dat = [[0, I], [1, 0]] ans = OperationsOnlyMatrix([[0, 1], [-I, 0]]) assert ans.adjoint() == Matrix(dat) def test_as_real_imag(): m1 = OperationsOnlyMatrix(2, 2, [1, 2, 3, 4]) m3 = OperationsOnlyMatrix(2, 2, [1 + S.ImaginaryUnit, 2 + 2*S.ImaginaryUnit, 3 + 3*S.ImaginaryUnit, 4 + 4*S.ImaginaryUnit]) a, b = m3.as_real_imag() assert a == m1 assert b == m1 def test_conjugate(): M = OperationsOnlyMatrix([[0, I, 5], [1, 2, 0]]) assert M.T == Matrix([[0, 1], [I, 2], [5, 0]]) assert M.C == Matrix([[0, -I, 5], [1, 2, 0]]) assert M.C == M.conjugate() assert M.H == M.T.C assert M.H == Matrix([[ 0, 1], [-I, 2], [ 5, 0]]) def test_doit(): a = OperationsOnlyMatrix([[Add(x, x, evaluate=False)]]) assert a[0] != 2*x assert a.doit() == Matrix([[2*x]]) def test_evalf(): a = OperationsOnlyMatrix(2, 1, [sqrt(5), 6]) assert all(a.evalf()[i] == a[i].evalf() for i in range(2)) assert all(a.evalf(2)[i] == a[i].evalf(2) for i in range(2)) assert all(a.n(2)[i] == a[i].n(2) for i in range(2)) def test_expand(): m0 = OperationsOnlyMatrix([[x*(x + y), 2], [((x + y)*y)*x, x*(y + x*(x + y))]]) # Test if expand() returns a matrix m1 = m0.expand() assert m1 == Matrix( [[x*y + x**2, 2], [x*y**2 + y*x**2, x*y + y*x**2 + x**3]]) a = Symbol('a', real=True) assert OperationsOnlyMatrix(1, 1, [exp(I*a)]).expand(complex=True) == \ Matrix([cos(a) + I*sin(a)]) def test_refine(): m0 = OperationsOnlyMatrix([[Abs(x)**2, sqrt(x**2)], [sqrt(x**2)*Abs(y)**2, sqrt(y**2)*Abs(x)**2]]) m1 = m0.refine(Q.real(x) & Q.real(y)) assert m1 == Matrix([[x**2, Abs(x)], [y**2*Abs(x), x**2*Abs(y)]]) m1 = m0.refine(Q.positive(x) & Q.positive(y)) assert m1 == Matrix([[x**2, x], [x*y**2, x**2*y]]) m1 = m0.refine(Q.negative(x) & Q.negative(y)) assert m1 == Matrix([[x**2, -x], [-x*y**2, -x**2*y]]) def test_replace(): F, G = symbols('F, G', cls=Function) K = OperationsOnlyMatrix(2, 2, lambda i, j: G(i+j)) M = OperationsOnlyMatrix(2, 2, lambda i, j: F(i+j)) N = M.replace(F, G) assert N == K def test_replace_map(): F, G = symbols('F, G', cls=Function) K = OperationsOnlyMatrix(2, 2, [(G(0), {F(0): G(0)}), (G(1), {F(1): G(1)}), (G(1), {F(1) \ : G(1)}), (G(2), {F(2): G(2)})]) M = OperationsOnlyMatrix(2, 2, lambda i, j: F(i+j)) N = M.replace(F, G, True) assert N == K def test_rot90(): A = Matrix([[1, 2], [3, 4]]) assert A == A.rot90(0) == A.rot90(4) assert A.rot90(2) == A.rot90(-2) == A.rot90(6) == Matrix(((4, 3), (2, 1))) assert A.rot90(3) == A.rot90(-1) == A.rot90(7) == Matrix(((2, 4), (1, 3))) assert A.rot90() == A.rot90(-7) == A.rot90(-3) == Matrix(((3, 1), (4, 2))) def test_simplify(): n = Symbol('n') f = Function('f') M = OperationsOnlyMatrix([[ 1/x + 1/y, (x + x*y) / x ], [ (f(x) + y*f(x))/f(x), 2 * (1/n - cos(n * pi)/n) / pi ]]) assert M.simplify() == Matrix([[ (x + y)/(x * y), 1 + y ], [ 1 + y, 2*((1 - 1*cos(pi*n))/(pi*n)) ]]) eq = (1 + x)**2 M = OperationsOnlyMatrix([[eq]]) assert M.simplify() == Matrix([[eq]]) assert M.simplify(ratio=oo) == Matrix([[eq.simplify(ratio=oo)]]) # https://github.com/sympy/sympy/issues/19353 m = Matrix([[30, 2], [3, 4]]) assert (1/(m.trace())).simplify() == Rational(1, 34) def test_subs(): assert OperationsOnlyMatrix([[1, x], [x, 4]]).subs(x, 5) == Matrix([[1, 5], [5, 4]]) assert OperationsOnlyMatrix([[x, 2], [x + y, 4]]).subs([[x, -1], [y, -2]]) == \ Matrix([[-1, 2], [-3, 4]]) assert OperationsOnlyMatrix([[x, 2], [x + y, 4]]).subs([(x, -1), (y, -2)]) == \ Matrix([[-1, 2], [-3, 4]]) assert OperationsOnlyMatrix([[x, 2], [x + y, 4]]).subs({x: -1, y: -2}) == \ Matrix([[-1, 2], [-3, 4]]) assert OperationsOnlyMatrix([[x*y]]).subs({x: y - 1, y: x - 1}, simultaneous=True) == \ Matrix([[(x - 1)*(y - 1)]]) def test_trace(): M = OperationsOnlyMatrix([[1, 0, 0], [0, 5, 0], [0, 0, 8]]) assert M.trace() == 14 def test_xreplace(): assert OperationsOnlyMatrix([[1, x], [x, 4]]).xreplace({x: 5}) == \ Matrix([[1, 5], [5, 4]]) assert OperationsOnlyMatrix([[x, 2], [x + y, 4]]).xreplace({x: -1, y: -2}) == \ Matrix([[-1, 2], [-3, 4]]) def test_permute(): a = OperationsOnlyMatrix(3, 4, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) raises(IndexError, lambda: a.permute([[0, 5]])) raises(ValueError, lambda: a.permute(Symbol('x'))) b = a.permute_rows([[0, 2], [0, 1]]) assert a.permute([[0, 2], [0, 1]]) == b == Matrix([ [5, 6, 7, 8], [9, 10, 11, 12], [1, 2, 3, 4]]) b = a.permute_cols([[0, 2], [0, 1]]) assert a.permute([[0, 2], [0, 1]], orientation='cols') == b ==\ Matrix([ [ 2, 3, 1, 4], [ 6, 7, 5, 8], [10, 11, 9, 12]]) b = a.permute_cols([[0, 2], [0, 1]], direction='backward') assert a.permute([[0, 2], [0, 1]], orientation='cols', direction='backward') == b ==\ Matrix([ [ 3, 1, 2, 4], [ 7, 5, 6, 8], [11, 9, 10, 12]]) assert a.permute([1, 2, 0, 3]) == Matrix([ [5, 6, 7, 8], [9, 10, 11, 12], [1, 2, 3, 4]]) from sympy.combinatorics import Permutation assert a.permute(Permutation([1, 2, 0, 3])) == Matrix([ [5, 6, 7, 8], [9, 10, 11, 12], [1, 2, 3, 4]]) def test_upper_triangular(): A = OperationsOnlyMatrix([ [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1] ]) R = A.upper_triangular(2) assert R == OperationsOnlyMatrix([ [0, 0, 1, 1], [0, 0, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0] ]) R = A.upper_triangular(-2) assert R == OperationsOnlyMatrix([ [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [0, 1, 1, 1] ]) R = A.upper_triangular() assert R == OperationsOnlyMatrix([ [1, 1, 1, 1], [0, 1, 1, 1], [0, 0, 1, 1], [0, 0, 0, 1] ]) def test_lower_triangular(): A = OperationsOnlyMatrix([ [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1] ]) L = A.lower_triangular() assert L == ArithmeticOnlyMatrix([ [1, 0, 0, 0], [1, 1, 0, 0], [1, 1, 1, 0], [1, 1, 1, 1]]) L = A.lower_triangular(2) assert L == ArithmeticOnlyMatrix([ [1, 1, 1, 0], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1] ]) L = A.lower_triangular(-2) assert L == ArithmeticOnlyMatrix([ [0, 0, 0, 0], [0, 0, 0, 0], [1, 0, 0, 0], [1, 1, 0, 0] ]) # ArithmeticOnlyMatrix tests def test_abs(): m = ArithmeticOnlyMatrix([[1, -2], [x, y]]) assert abs(m) == ArithmeticOnlyMatrix([[1, 2], [Abs(x), Abs(y)]]) def test_add(): m = ArithmeticOnlyMatrix([[1, 2, 3], [x, y, x], [2*y, -50, z*x]]) assert m + m == ArithmeticOnlyMatrix([[2, 4, 6], [2*x, 2*y, 2*x], [4*y, -100, 2*z*x]]) n = ArithmeticOnlyMatrix(1, 2, [1, 2]) raises(ShapeError, lambda: m + n) def test_multiplication(): a = ArithmeticOnlyMatrix(( (1, 2), (3, 1), (0, 6), )) b = ArithmeticOnlyMatrix(( (1, 2), (3, 0), )) raises(ShapeError, lambda: b*a) raises(TypeError, lambda: a*{}) c = a*b assert c[0, 0] == 7 assert c[0, 1] == 2 assert c[1, 0] == 6 assert c[1, 1] == 6 assert c[2, 0] == 18 assert c[2, 1] == 0 try: eval('c = a @ b') except SyntaxError: pass else: assert c[0, 0] == 7 assert c[0, 1] == 2 assert c[1, 0] == 6 assert c[1, 1] == 6 assert c[2, 0] == 18 assert c[2, 1] == 0 h = a.multiply_elementwise(c) assert h == matrix_multiply_elementwise(a, c) assert h[0, 0] == 7 assert h[0, 1] == 4 assert h[1, 0] == 18 assert h[1, 1] == 6 assert h[2, 0] == 0 assert h[2, 1] == 0 raises(ShapeError, lambda: a.multiply_elementwise(b)) c = b * Symbol("x") assert isinstance(c, ArithmeticOnlyMatrix) assert c[0, 0] == x assert c[0, 1] == 2*x assert c[1, 0] == 3*x assert c[1, 1] == 0 c2 = x * b assert c == c2 c = 5 * b assert isinstance(c, ArithmeticOnlyMatrix) assert c[0, 0] == 5 assert c[0, 1] == 2*5 assert c[1, 0] == 3*5 assert c[1, 1] == 0 try: eval('c = 5 @ b') except SyntaxError: pass else: assert isinstance(c, ArithmeticOnlyMatrix) assert c[0, 0] == 5 assert c[0, 1] == 2*5 assert c[1, 0] == 3*5 assert c[1, 1] == 0 # https://github.com/sympy/sympy/issues/22353 A = Matrix(ones(3, 1)) _h = -Rational(1, 2) B = Matrix([_h, _h, _h]) assert A.multiply_elementwise(B) == Matrix([ [_h], [_h], [_h]]) def test_matmul(): a = Matrix([[1, 2], [3, 4]]) assert a.__matmul__(2) == NotImplemented assert a.__rmatmul__(2) == NotImplemented #This is done this way because @ is only supported in Python 3.5+ #To check 2@a case try: eval('2 @ a') except SyntaxError: pass except TypeError: #TypeError is raised in case of NotImplemented is returned pass #Check a@2 case try: eval('a @ 2') except SyntaxError: pass except TypeError: #TypeError is raised in case of NotImplemented is returned pass def test_non_matmul(): """ Test that if explicitly specified as non-matrix, mul reverts to scalar multiplication. """ class foo(Expr): is_Matrix=False is_MatrixLike=False shape = (1, 1) A = Matrix([[1, 2], [3, 4]]) b = foo() assert b*A == Matrix([[b, 2*b], [3*b, 4*b]]) assert A*b == Matrix([[b, 2*b], [3*b, 4*b]]) def test_power(): raises(NonSquareMatrixError, lambda: Matrix((1, 2))**2) A = ArithmeticOnlyMatrix([[2, 3], [4, 5]]) assert (A**5)[:] == (6140, 8097, 10796, 14237) A = ArithmeticOnlyMatrix([[2, 1, 3], [4, 2, 4], [6, 12, 1]]) assert (A**3)[:] == (290, 262, 251, 448, 440, 368, 702, 954, 433) assert A**0 == eye(3) assert A**1 == A assert (ArithmeticOnlyMatrix([[2]]) ** 100)[0, 0] == 2**100 assert ArithmeticOnlyMatrix([[1, 2], [3, 4]])**Integer(2) == ArithmeticOnlyMatrix([[7, 10], [15, 22]]) A = Matrix([[1,2],[4,5]]) assert A.pow(20, method='cayley') == A.pow(20, method='multiply') def test_neg(): n = ArithmeticOnlyMatrix(1, 2, [1, 2]) assert -n == ArithmeticOnlyMatrix(1, 2, [-1, -2]) def test_sub(): n = ArithmeticOnlyMatrix(1, 2, [1, 2]) assert n - n == ArithmeticOnlyMatrix(1, 2, [0, 0]) def test_div(): n = ArithmeticOnlyMatrix(1, 2, [1, 2]) assert n/2 == ArithmeticOnlyMatrix(1, 2, [S.Half, S(2)/2]) # SpecialOnlyMatrix tests def test_eye(): assert list(SpecialOnlyMatrix.eye(2, 2)) == [1, 0, 0, 1] assert list(SpecialOnlyMatrix.eye(2)) == [1, 0, 0, 1] assert type(SpecialOnlyMatrix.eye(2)) == SpecialOnlyMatrix assert type(SpecialOnlyMatrix.eye(2, cls=Matrix)) == Matrix def test_ones(): assert list(SpecialOnlyMatrix.ones(2, 2)) == [1, 1, 1, 1] assert list(SpecialOnlyMatrix.ones(2)) == [1, 1, 1, 1] assert SpecialOnlyMatrix.ones(2, 3) == Matrix([[1, 1, 1], [1, 1, 1]]) assert type(SpecialOnlyMatrix.ones(2)) == SpecialOnlyMatrix assert type(SpecialOnlyMatrix.ones(2, cls=Matrix)) == Matrix def test_zeros(): assert list(SpecialOnlyMatrix.zeros(2, 2)) == [0, 0, 0, 0] assert list(SpecialOnlyMatrix.zeros(2)) == [0, 0, 0, 0] assert SpecialOnlyMatrix.zeros(2, 3) == Matrix([[0, 0, 0], [0, 0, 0]]) assert type(SpecialOnlyMatrix.zeros(2)) == SpecialOnlyMatrix assert type(SpecialOnlyMatrix.zeros(2, cls=Matrix)) == Matrix def test_diag_make(): diag = SpecialOnlyMatrix.diag a = Matrix([[1, 2], [2, 3]]) b = Matrix([[3, x], [y, 3]]) c = Matrix([[3, x, 3], [y, 3, z], [x, y, z]]) assert diag(a, b, b) == Matrix([ [1, 2, 0, 0, 0, 0], [2, 3, 0, 0, 0, 0], [0, 0, 3, x, 0, 0], [0, 0, y, 3, 0, 0], [0, 0, 0, 0, 3, x], [0, 0, 0, 0, y, 3], ]) assert diag(a, b, c) == Matrix([ [1, 2, 0, 0, 0, 0, 0], [2, 3, 0, 0, 0, 0, 0], [0, 0, 3, x, 0, 0, 0], [0, 0, y, 3, 0, 0, 0], [0, 0, 0, 0, 3, x, 3], [0, 0, 0, 0, y, 3, z], [0, 0, 0, 0, x, y, z], ]) assert diag(a, c, b) == Matrix([ [1, 2, 0, 0, 0, 0, 0], [2, 3, 0, 0, 0, 0, 0], [0, 0, 3, x, 3, 0, 0], [0, 0, y, 3, z, 0, 0], [0, 0, x, y, z, 0, 0], [0, 0, 0, 0, 0, 3, x], [0, 0, 0, 0, 0, y, 3], ]) a = Matrix([x, y, z]) b = Matrix([[1, 2], [3, 4]]) c = Matrix([[5, 6]]) # this "wandering diagonal" is what makes this # a block diagonal where each block is independent # of the others assert diag(a, 7, b, c) == Matrix([ [x, 0, 0, 0, 0, 0], [y, 0, 0, 0, 0, 0], [z, 0, 0, 0, 0, 0], [0, 7, 0, 0, 0, 0], [0, 0, 1, 2, 0, 0], [0, 0, 3, 4, 0, 0], [0, 0, 0, 0, 5, 6]]) raises(ValueError, lambda: diag(a, 7, b, c, rows=5)) assert diag(1) == Matrix([[1]]) assert diag(1, rows=2) == Matrix([[1, 0], [0, 0]]) assert diag(1, cols=2) == Matrix([[1, 0], [0, 0]]) assert diag(1, rows=3, cols=2) == Matrix([[1, 0], [0, 0], [0, 0]]) assert diag(*[2, 3]) == Matrix([ [2, 0], [0, 3]]) assert diag(Matrix([2, 3])) == Matrix([ [2], [3]]) assert diag([1, [2, 3], 4], unpack=False) == \ diag([[1], [2, 3], [4]], unpack=False) == Matrix([ [1, 0], [2, 3], [4, 0]]) assert type(diag(1)) == SpecialOnlyMatrix assert type(diag(1, cls=Matrix)) == Matrix assert Matrix.diag([1, 2, 3]) == Matrix.diag(1, 2, 3) assert Matrix.diag([1, 2, 3], unpack=False).shape == (3, 1) assert Matrix.diag([[1, 2, 3]]).shape == (3, 1) assert Matrix.diag([[1, 2, 3]], unpack=False).shape == (1, 3) assert Matrix.diag([[[1, 2, 3]]]).shape == (1, 3) # kerning can be used to move the starting point assert Matrix.diag(ones(0, 2), 1, 2) == Matrix([ [0, 0, 1, 0], [0, 0, 0, 2]]) assert Matrix.diag(ones(2, 0), 1, 2) == Matrix([ [0, 0], [0, 0], [1, 0], [0, 2]]) def test_diagonal(): m = Matrix(3, 3, range(9)) d = m.diagonal() assert d == m.diagonal(0) assert tuple(d) == (0, 4, 8) assert tuple(m.diagonal(1)) == (1, 5) assert tuple(m.diagonal(-1)) == (3, 7) assert tuple(m.diagonal(2)) == (2,) assert type(m.diagonal()) == type(m) s = SparseMatrix(3, 3, {(1, 1): 1}) assert type(s.diagonal()) == type(s) assert type(m) != type(s) raises(ValueError, lambda: m.diagonal(3)) raises(ValueError, lambda: m.diagonal(-3)) raises(ValueError, lambda: m.diagonal(pi)) M = ones(2, 3) assert banded({i: list(M.diagonal(i)) for i in range(1-M.rows, M.cols)}) == M def test_jordan_block(): assert SpecialOnlyMatrix.jordan_block(3, 2) == SpecialOnlyMatrix.jordan_block(3, eigenvalue=2) \ == SpecialOnlyMatrix.jordan_block(size=3, eigenvalue=2) \ == SpecialOnlyMatrix.jordan_block(3, 2, band='upper') \ == SpecialOnlyMatrix.jordan_block( size=3, eigenval=2, eigenvalue=2) \ == Matrix([ [2, 1, 0], [0, 2, 1], [0, 0, 2]]) assert SpecialOnlyMatrix.jordan_block(3, 2, band='lower') == Matrix([ [2, 0, 0], [1, 2, 0], [0, 1, 2]]) # missing eigenvalue raises(ValueError, lambda: SpecialOnlyMatrix.jordan_block(2)) # non-integral size raises(ValueError, lambda: SpecialOnlyMatrix.jordan_block(3.5, 2)) # size not specified raises(ValueError, lambda: SpecialOnlyMatrix.jordan_block(eigenvalue=2)) # inconsistent eigenvalue raises(ValueError, lambda: SpecialOnlyMatrix.jordan_block( eigenvalue=2, eigenval=4)) # Using alias keyword assert SpecialOnlyMatrix.jordan_block(size=3, eigenvalue=2) == \ SpecialOnlyMatrix.jordan_block(size=3, eigenval=2) def test_orthogonalize(): m = Matrix([[1, 2], [3, 4]]) assert m.orthogonalize(Matrix([[2], [1]])) == [Matrix([[2], [1]])] assert m.orthogonalize(Matrix([[2], [1]]), normalize=True) == \ [Matrix([[2*sqrt(5)/5], [sqrt(5)/5]])] assert m.orthogonalize(Matrix([[1], [2]]), Matrix([[-1], [4]])) == \ [Matrix([[1], [2]]), Matrix([[Rational(-12, 5)], [Rational(6, 5)]])] assert m.orthogonalize(Matrix([[0], [0]]), Matrix([[-1], [4]])) == \ [Matrix([[-1], [4]])] assert m.orthogonalize(Matrix([[0], [0]])) == [] n = Matrix([[9, 1, 9], [3, 6, 10], [8, 5, 2]]) vecs = [Matrix([[-5], [1]]), Matrix([[-5], [2]]), Matrix([[-5], [-2]])] assert n.orthogonalize(*vecs) == \ [Matrix([[-5], [1]]), Matrix([[Rational(5, 26)], [Rational(25, 26)]])] vecs = [Matrix([0, 0, 0]), Matrix([1, 2, 3]), Matrix([1, 4, 5])] raises(ValueError, lambda: Matrix.orthogonalize(*vecs, rankcheck=True)) vecs = [Matrix([1, 2, 3]), Matrix([4, 5, 6]), Matrix([7, 8, 9])] raises(ValueError, lambda: Matrix.orthogonalize(*vecs, rankcheck=True)) def test_wilkinson(): wminus, wplus = Matrix.wilkinson(1) assert wminus == Matrix([ [-1, 1, 0], [1, 0, 1], [0, 1, 1]]) assert wplus == Matrix([ [1, 1, 0], [1, 0, 1], [0, 1, 1]]) wminus, wplus = Matrix.wilkinson(3) assert wminus == Matrix([ [-3, 1, 0, 0, 0, 0, 0], [1, -2, 1, 0, 0, 0, 0], [0, 1, -1, 1, 0, 0, 0], [0, 0, 1, 0, 1, 0, 0], [0, 0, 0, 1, 1, 1, 0], [0, 0, 0, 0, 1, 2, 1], [0, 0, 0, 0, 0, 1, 3]]) assert wplus == Matrix([ [3, 1, 0, 0, 0, 0, 0], [1, 2, 1, 0, 0, 0, 0], [0, 1, 1, 1, 0, 0, 0], [0, 0, 1, 0, 1, 0, 0], [0, 0, 0, 1, 1, 1, 0], [0, 0, 0, 0, 1, 2, 1], [0, 0, 0, 0, 0, 1, 3]]) # CalculusOnlyMatrix tests @XFAIL def test_diff(): x, y = symbols('x y') m = CalculusOnlyMatrix(2, 1, [x, y]) # TODO: currently not working as ``_MinimalMatrix`` cannot be sympified: assert m.diff(x) == Matrix(2, 1, [1, 0]) def test_integrate(): x, y = symbols('x y') m = CalculusOnlyMatrix(2, 1, [x, y]) assert m.integrate(x) == Matrix(2, 1, [x**2/2, y*x]) def test_jacobian2(): rho, phi = symbols("rho,phi") X = CalculusOnlyMatrix(3, 1, [rho*cos(phi), rho*sin(phi), rho**2]) Y = CalculusOnlyMatrix(2, 1, [rho, phi]) J = Matrix([ [cos(phi), -rho*sin(phi)], [sin(phi), rho*cos(phi)], [ 2*rho, 0], ]) assert X.jacobian(Y) == J m = CalculusOnlyMatrix(2, 2, [1, 2, 3, 4]) m2 = CalculusOnlyMatrix(4, 1, [1, 2, 3, 4]) raises(TypeError, lambda: m.jacobian(Matrix([1, 2]))) raises(TypeError, lambda: m2.jacobian(m)) def test_limit(): x, y = symbols('x y') m = CalculusOnlyMatrix(2, 1, [1/x, y]) assert m.limit(x, 5) == Matrix(2, 1, [Rational(1, 5), y]) def test_issue_13774(): M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) v = [1, 1, 1] raises(TypeError, lambda: M*v) raises(TypeError, lambda: v*M) def test_companion(): x = Symbol('x') y = Symbol('y') raises(ValueError, lambda: Matrix.companion(1)) raises(ValueError, lambda: Matrix.companion(Poly([1], x))) raises(ValueError, lambda: Matrix.companion(Poly([2, 1], x))) raises(ValueError, lambda: Matrix.companion(Poly(x*y, [x, y]))) c0, c1, c2 = symbols('c0:3') assert Matrix.companion(Poly([1, c0], x)) == Matrix([-c0]) assert Matrix.companion(Poly([1, c1, c0], x)) == \ Matrix([[0, -c0], [1, -c1]]) assert Matrix.companion(Poly([1, c2, c1, c0], x)) == \ Matrix([[0, 0, -c0], [1, 0, -c1], [0, 1, -c2]]) def test_issue_10589(): x, y, z = symbols("x, y z") M1 = Matrix([x, y, z]) M1 = M1.subs(zip([x, y, z], [1, 2, 3])) assert M1 == Matrix([[1], [2], [3]]) M2 = Matrix([[x, x, x, x, x], [x, x, x, x, x], [x, x, x, x, x]]) M2 = M2.subs(zip([x], [1])) assert M2 == Matrix([[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1]]) def test_rmul_pr19860(): class Foo(ImmutableDenseMatrix): _op_priority = MutableDenseMatrix._op_priority + 0.01 a = Matrix(2, 2, [1, 2, 3, 4]) b = Foo(2, 2, [1, 2, 3, 4]) # This would throw a RecursionError: maximum recursion depth # since b always has higher priority even after a.as_mutable() c = a*b assert isinstance(c, Foo) assert c == Matrix([[7, 10], [15, 22]]) def test_issue_18956(): A = Array([[1, 2], [3, 4]]) B = Matrix([[1,2],[3,4]]) raises(TypeError, lambda: B + A) raises(TypeError, lambda: A + B) def test__eq__(): class My(object): def __iter__(self): yield 1 yield 2 return def __getitem__(self, i): return list(self)[i] a = Matrix(2, 1, [1, 2]) assert a != My() class My_sympy(My): def _sympy_(self): return Matrix(self) assert a == My_sympy()