def test_MatrixSlice(): X = MatrixSymbol('X', 4, 4) B = MatrixSlice(X, (1, 3), (1, 3)) C = MatrixSlice(X, (0, 3), (1, 3)) assert ask(Q.symmetric(B), Q.symmetric(X)) assert ask(Q.invertible(B), Q.invertible(X)) assert ask(Q.diagonal(B), Q.diagonal(X)) assert ask(Q.orthogonal(B), Q.orthogonal(X)) assert ask(Q.upper_triangular(B), Q.upper_triangular(X)) assert not ask(Q.symmetric(C), Q.symmetric(X)) assert not ask(Q.invertible(C), Q.invertible(X)) assert not ask(Q.diagonal(C), Q.diagonal(X)) assert not ask(Q.orthogonal(C), Q.orthogonal(X)) assert not ask(Q.upper_triangular(C), Q.upper_triangular(X))
def test_diagonal(): assert ask(Q.diagonal(X + Z.T + Identity(2)), Q.diagonal(X) & Q.diagonal(Z)) is True assert ask(Q.diagonal(ZeroMatrix(3, 3))) assert ask(Q.lower_triangular(X) & Q.upper_triangular(X), Q.diagonal(X)) assert ask(Q.diagonal(X), Q.lower_triangular(X) & Q.upper_triangular(X)) assert ask(Q.symmetric(X), Q.diagonal(X)) assert ask(Q.triangular(X), Q.diagonal(X))
def test_MatrixSlice(): X = MatrixSymbol('X', 4, 4) B = MatrixSlice(X, (1, 3), (1, 3)) C = MatrixSlice(X, (0, 3), (1, 3)) assert ask(Q.symmetric(B), Q.symmetric(X)) assert ask(Q.invertible(B), Q.invertible(X)) assert ask(Q.diagonal(B), Q.diagonal(X)) assert ask(Q.orthogonal(B), Q.orthogonal(X)) assert ask(Q.upper_triangular(B), Q.upper_triangular(X)) assert not ask(Q.symmetric(C), Q.symmetric(X)) assert not ask(Q.invertible(C), Q.invertible(X)) assert not ask(Q.diagonal(C), Q.diagonal(X)) assert not ask(Q.orthogonal(C), Q.orthogonal(X)) assert not ask(Q.upper_triangular(C), Q.upper_triangular(X))
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_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_DiagonalMatrix_Assumptions(): assert ask(Q.diagonal(D))
def test_diagonal(): assert ask(Q.diagonal(X + Z.T + Identity(2)), Q.diagonal(X) & Q.diagonal(Z)) is True assert ask(Q.diagonal(ZeroMatrix(3, 3))) assert ask(Q.lower_triangular(X) & Q.upper_triangular(X), Q.diagonal(X)) assert ask(Q.diagonal(X), Q.lower_triangular(X) & Q.upper_triangular(X)) assert ask(Q.symmetric(X), Q.diagonal(X)) assert ask(Q.triangular(X), Q.diagonal(X)) assert ask(Q.diagonal(C0x0)) assert ask(Q.diagonal(A1x1)) assert ask(Q.diagonal(A1x1 + B1x1)) assert ask(Q.diagonal(A1x1*B1x1)) assert ask(Q.diagonal(V1.T*V2)) assert ask(Q.diagonal(V1.T*(X + Z)*V1)) assert ask(Q.diagonal(MatrixSlice(Y, (0, 1), (1, 2)))) is True assert ask(Q.diagonal(V1.T*(V1 + V2))) is True assert ask(Q.diagonal(X**3), Q.diagonal(X)) assert ask(Q.diagonal(Identity(3))) assert ask(Q.diagonal(DiagMatrix(V1))) assert ask(Q.diagonal(DiagonalMatrix(X)))
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))
def test_diagonal(): assert ask(Q.diagonal(X + Z.T + Identity(2)), Q.diagonal(X) & Q.diagonal(Z)) is True assert ask(Q.diagonal(ZeroMatrix(3, 3))) assert ask(Q.lower_triangular(X) & Q.upper_triangular(X), Q.diagonal(X)) assert ask(Q.diagonal(X), Q.lower_triangular(X) & Q.upper_triangular(X)) assert ask(Q.symmetric(X), Q.diagonal(X)) assert ask(Q.triangular(X), Q.diagonal(X)) assert ask(Q.diagonal(C0x0)) assert ask(Q.diagonal(A1x1)) assert ask(Q.diagonal(A1x1 + B1x1)) assert ask(Q.diagonal(A1x1*B1x1)) assert ask(Q.diagonal(V1.T*V2)) assert ask(Q.diagonal(V1.T*(X + Z)*V1)) assert ask(Q.diagonal(MatrixSlice(Y, (0, 1), (1, 2)))) is True assert ask(Q.diagonal(V1.T*(V1 + V2))) is True
def split_multiple_contractions(self): """ Recognize multiple contractions and attempt at rewriting them as paired-contractions. """ from sympy import ask, Q contraction_indices = self.contraction_indices if isinstance(self.expr, ArrayTensorProduct): args = list(self.expr.args) else: args = [self.expr] # TODO: unify API, best location in ArrayTensorProduct subranks = [get_rank(i) for i in args] # TODO: unify API mapping = _get_mapping_from_subranks(subranks) reverse_mapping = {v:k for k, v in mapping.items()} new_contraction_indices = [] for indl, links in enumerate(contraction_indices): if len(links) <= 2: new_contraction_indices.append(links) continue # Check multiple contractions: # # Examples: # # * `A_ij b_j0 C_jk` ===> `A*DiagMatrix(b)*C` # # Care for: # - matrix being diagonalized (i.e. `A_ii`) # - vectors being diagonalized (i.e. `a_i0`) # Also consider the case of diagonal matrices being contracted: current_dimension = self.expr.shape[links[0]] tuple_links = [mapping[i] for i in links] arg_indices, arg_positions = zip(*tuple_links) args_updates = {} if len(arg_indices) != len(set(arg_indices)): # Maybe trace should be supported? raise NotImplementedError not_vectors = [] vectors = [] for arg_ind, arg_pos in tuple_links: mat = args[arg_ind] other_arg_pos = 1-arg_pos other_arg_abs = reverse_mapping[arg_ind, other_arg_pos] if (((1 not in mat.shape) and (not ask(Q.diagonal(mat)))) or ((current_dimension == 1) is True and mat.shape != (1, 1)) or any([other_arg_abs in l for li, l in enumerate(contraction_indices) if li != indl]) ): not_vectors.append((arg_ind, arg_pos)) continue args_updates[arg_ind] = diagonalize_vector(mat) vectors.append((arg_ind, arg_pos)) vectors.append((arg_ind, 1-arg_pos)) if len(not_vectors) > 2: new_contraction_indices.append(links) continue if len(not_vectors) == 0: new_sequence = vectors[:1] + vectors[2:] elif len(not_vectors) == 1: new_sequence = not_vectors[:1] + vectors[:-1] else: new_sequence = not_vectors[:1] + vectors + not_vectors[1:] for i in range(0, len(new_sequence) - 1, 2): arg1, pos1 = new_sequence[i] arg2, pos2 = new_sequence[i+1] if arg1 == arg2: raise NotImplementedError continue abspos1 = reverse_mapping[arg1, pos1] abspos2 = reverse_mapping[arg2, pos2] new_contraction_indices.append((abspos1, abspos2)) for ind, newarg in args_updates.items(): args[ind] = newarg return ArrayContraction( ArrayTensorProduct(*args), *new_contraction_indices )
def identify_removable_identity_matrices(expr): editor = _EditArrayContraction(expr) flag: bool = True while flag: flag = False for arg_with_ind in editor.args_with_ind: if isinstance(arg_with_ind.element, Identity): k = arg_with_ind.element.shape[0] # Candidate for removal: if arg_with_ind.indices == [None, None]: # Free identity matrix, will be cleared by _remove_trivial_dims: continue elif None in arg_with_ind.indices: ind = [j for j in arg_with_ind.indices if j is not None][0] counted = editor.count_args_with_index(ind) if counted == 1: # Identity matrix contracted only on one index with itself, # transform to a OneArray(k) element: editor.insert_after(arg_with_ind, OneArray(k)) editor.args_with_ind.remove(arg_with_ind) flag = True break elif counted > 2: # Case counted = 2 is a matrix multiplication by identity matrix, skip it. # Case counted > 2 is a multiple contraction, # this is a case where the contraction becomes a diagonalization if the # identity matrix is dropped. continue elif arg_with_ind.indices[0] == arg_with_ind.indices[1]: ind = arg_with_ind.indices[0] counted = editor.count_args_with_index(ind) if counted > 1: editor.args_with_ind.remove(arg_with_ind) flag = True break else: # This is a trace, skip it as it will be recognized somewhere else: pass elif ask(Q.diagonal(arg_with_ind.element)): if arg_with_ind.indices == [None, None]: continue elif None in arg_with_ind.indices: pass elif arg_with_ind.indices[0] == arg_with_ind.indices[1]: ind = arg_with_ind.indices[0] counted = editor.count_args_with_index(ind) if counted == 3: # A_ai B_bi D_ii ==> A_ai D_ij B_bj ind_new = editor.get_new_contraction_index() other_args = [ j for j in editor.args_with_ind if j != arg_with_ind ] other_args[1].indices = [ ind_new if j == ind else j for j in other_args[1].indices ] arg_with_ind.indices = [ind, ind_new] flag = True break return editor.to_array_contraction()
def test_DiagonalMatrix_Assumptions(): assert ask(Q.diagonal(D))
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))