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_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_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_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_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_PermutationMatrix_inverse(): P = PermutationMatrix(Permutation(0, 1, 2)) assert Inverse(P).doit() == PermutationMatrix(Permutation(0, 2, 1))
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_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 _connected_components_decomposition(M): """Decomposes a square matrix into block diagonal form only using the permutations. Explanation =========== The decomposition is in a form of $A = P B P^{-1}$ where $P$ is a permutation matrix and $B$ is a block diagonal matrix. Returns ======= P, B : PermutationMatrix, BlockDiagMatrix *P* is a permutation matrix for the similarity transform as in the explanation. And *B* is the block diagonal matrix of the result of the permutation. If you would like to get the diagonal blocks from the BlockDiagMatrix, see :meth:`~sympy.matrices.expressions.blockmatrix.BlockDiagMatrix.get_diag_blocks`. Examples ======== >>> from sympy import symbols, Matrix >>> a, b, c, d, e, f, g, h = symbols('a:h') >>> A = Matrix([ ... [a, 0, b, 0], ... [0, e, 0, f], ... [c, 0, d, 0], ... [0, g, 0, h]]) >>> P, B = A.connected_components_decomposition() >>> P = P.as_explicit() >>> P_inv = P.inv().as_explicit() >>> B = B.as_explicit() >>> P Matrix([ [1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]) >>> B Matrix([ [a, b, 0, 0], [c, d, 0, 0], [0, 0, e, f], [0, 0, g, h]]) >>> P * B * P_inv Matrix([ [a, 0, b, 0], [0, e, 0, f], [c, 0, d, 0], [0, g, 0, h]]) Notes ===== This problem corresponds to the finding of the connected components of a graph, when a matrix is viewed as a weighted graph. """ from sympy.combinatorics.permutations import Permutation from sympy.matrices.expressions.blockmatrix import BlockDiagMatrix from sympy.matrices.expressions.permutation import PermutationMatrix iblocks = M.connected_components() p = Permutation(flatten(iblocks)) P = PermutationMatrix(p) blocks = [] for b in iblocks: blocks.append(M[b, b]) B = BlockDiagMatrix(*blocks) return P, B
def _connected_components_decomposition(M): """Decomposes a square matrix into block diagonal form only using the permutations. Explanation =========== The decomposition is in a form of $A = P^{-1} B P$ where $P$ is a permutation matrix and $B$ is a block diagonal matrix. Returns ======= P, B : PermutationMatrix, BlockDiagMatrix *P* is a permutation matrix for the similarity transform as in the explanation. And *B* is the block diagonal matrix of the result of the permutation. If you would like to get the diagonal blocks from the BlockDiagMatrix, see :meth:`~sympy.matrices.expressions.blockmatrix.BlockDiagMatrix.get_diag_blocks`. Examples ======== >>> from sympy import Matrix, pprint >>> A = Matrix([ ... [66, 0, 0, 68, 0, 0, 0, 0, 67], ... [0, 55, 0, 0, 0, 0, 54, 53, 0], ... [0, 0, 0, 0, 1, 2, 0, 0, 0], ... [86, 0, 0, 88, 0, 0, 0, 0, 87], ... [0, 0, 10, 0, 11, 12, 0, 0, 0], ... [0, 0, 20, 0, 21, 22, 0, 0, 0], ... [0, 45, 0, 0, 0, 0, 44, 43, 0], ... [0, 35, 0, 0, 0, 0, 34, 33, 0], ... [76, 0, 0, 78, 0, 0, 0, 0, 77]]) >>> P, B = A.connected_components_decomposition() >>> pprint(P) PermutationMatrix((1 3)(2 8 5 7 4 6)) >>> pprint(B) [[66 68 67] ] [[ ] ] [[86 88 87] 0 0 ] [[ ] ] [[76 78 77] ] [ ] [ [55 54 53] ] [ [ ] ] [ 0 [45 44 43] 0 ] [ [ ] ] [ [35 34 33] ] [ ] [ [0 1 2 ]] [ [ ]] [ 0 0 [10 11 12]] [ [ ]] [ [20 21 22]] >>> P = P.as_explicit() >>> B = B.as_explicit() >>> P.T*B*P == A True Notes ===== This problem corresponds to the finding of the connected components of a graph, when a matrix is viewed as a weighted graph. """ from sympy.combinatorics.permutations import Permutation from sympy.matrices.expressions.blockmatrix import BlockDiagMatrix from sympy.matrices.expressions.permutation import PermutationMatrix iblocks = M.connected_components() p = Permutation(flatten(iblocks)) P = PermutationMatrix(p) blocks = [] for b in iblocks: blocks.append(M[b, b]) B = BlockDiagMatrix(*blocks) return P, B
def _strongly_connected_components_decomposition(M, lower=True): """Decomposes a square matrix into block triangular form only using the permutations. Explanation =========== The decomposition is in a form of $A = P^{-1} B P$ where $P$ is a permutation matrix and $B$ is a block diagonal matrix. Parameters ========== lower : bool Makes $B$ lower block triangular when ``True``. Otherwise, makes $B$ upper block triangular. Returns ======= P, B : PermutationMatrix, BlockMatrix *P* is a permutation matrix for the similarity transform as in the explanation. And *B* is the block triangular matrix of the result of the permutation. Examples ======== >>> from sympy import Matrix, pprint >>> A = Matrix([ ... [44, 0, 0, 0, 43, 0, 45, 0, 0], ... [0, 66, 62, 61, 0, 68, 0, 60, 67], ... [0, 0, 22, 21, 0, 0, 0, 20, 0], ... [0, 0, 12, 11, 0, 0, 0, 10, 0], ... [34, 0, 0, 0, 33, 0, 35, 0, 0], ... [0, 86, 82, 81, 0, 88, 0, 80, 87], ... [54, 0, 0, 0, 53, 0, 55, 0, 0], ... [0, 0, 2, 1, 0, 0, 0, 0, 0], ... [0, 76, 72, 71, 0, 78, 0, 70, 77]]) A lower block triangular decomposition: >>> P, B = A.strongly_connected_components_decomposition() >>> pprint(P) PermutationMatrix((8)(1 4 3 2 6)(5 7)) >>> pprint(B) [[44 43 45] [0 0 0] [0 0 0] ] [[ ] [ ] [ ] ] [[34 33 35] [0 0 0] [0 0 0] ] [[ ] [ ] [ ] ] [[54 53 55] [0 0 0] [0 0 0] ] [ ] [ [0 0 0] [22 21 20] [0 0 0] ] [ [ ] [ ] [ ] ] [ [0 0 0] [12 11 10] [0 0 0] ] [ [ ] [ ] [ ] ] [ [0 0 0] [2 1 0 ] [0 0 0] ] [ ] [ [0 0 0] [62 61 60] [66 68 67]] [ [ ] [ ] [ ]] [ [0 0 0] [82 81 80] [86 88 87]] [ [ ] [ ] [ ]] [ [0 0 0] [72 71 70] [76 78 77]] >>> P = P.as_explicit() >>> B = B.as_explicit() >>> P.T * B * P == A True An upper block triangular decomposition: >>> P, B = A.strongly_connected_components_decomposition(lower=False) >>> pprint(P) PermutationMatrix((0 1 5 7 4 3 2 8 6)) >>> pprint(B) [[66 68 67] [62 61 60] [0 0 0] ] [[ ] [ ] [ ] ] [[86 88 87] [82 81 80] [0 0 0] ] [[ ] [ ] [ ] ] [[76 78 77] [72 71 70] [0 0 0] ] [ ] [ [0 0 0] [22 21 20] [0 0 0] ] [ [ ] [ ] [ ] ] [ [0 0 0] [12 11 10] [0 0 0] ] [ [ ] [ ] [ ] ] [ [0 0 0] [2 1 0 ] [0 0 0] ] [ ] [ [0 0 0] [0 0 0] [44 43 45]] [ [ ] [ ] [ ]] [ [0 0 0] [0 0 0] [34 33 35]] [ [ ] [ ] [ ]] [ [0 0 0] [0 0 0] [54 53 55]] >>> P = P.as_explicit() >>> B = B.as_explicit() >>> P.T * B * P == A True """ from sympy.combinatorics.permutations import Permutation from sympy.matrices.expressions.blockmatrix import BlockMatrix from sympy.matrices.expressions.permutation import PermutationMatrix iblocks = M.strongly_connected_components() if not lower: iblocks = list(reversed(iblocks)) p = Permutation(flatten(iblocks)) P = PermutationMatrix(p) rows = [] for a in iblocks: cols = [] for b in iblocks: cols.append(M[a, b]) rows.append(cols) B = BlockMatrix(rows) return P, B