def _choose_2x2_inversion_formula(A, B, C, D): """ Assuming [[A, B], [C, D]] would form a valid square block matrix, find which of the classical 2x2 block matrix inversion formulas would be best suited. Returns 'A', 'B', 'C', 'D' to represent the algorithm involving inversion of the given argument or None if the matrix cannot be inverted using any of those formulas. """ # Try to find a known invertible matrix. Note that the Schur complement # is currently not being considered for this A_inv = ask(Q.invertible(A)) if A_inv == True: return 'A' B_inv = ask(Q.invertible(B)) if B_inv == True: return 'B' C_inv = ask(Q.invertible(C)) if C_inv == True: return 'C' D_inv = ask(Q.invertible(D)) if D_inv == True: return 'D' # Otherwise try to find a matrix that isn't known to be non-invertible if A_inv != False: return 'A' if B_inv != False: return 'B' if C_inv != False: return 'C' if D_inv != False: return 'D' return None
def refine_MatMul(expr, assumptions): """ >>> from sympy import MatrixSymbol, Q, assuming, refine >>> X = MatrixSymbol('X', 2, 2) >>> expr = X * X.T >>> print(expr) X*X.T >>> with assuming(Q.orthogonal(X)): ... print(refine(expr)) I """ newargs = [] exprargs = [] for args in expr.args: if args.is_Matrix: exprargs.append(args) else: newargs.append(args) last = exprargs[0] for arg in exprargs[1:]: if arg == last.T and ask(Q.orthogonal(arg), assumptions): last = Identity(arg.shape[0]) elif arg == last.conjugate() and ask(Q.unitary(arg), assumptions): last = Identity(arg.shape[0]) else: newargs.append(last) last = arg newargs.append(last) return MatMul(*newargs)
def test_non_trivial_implies(): X = MatrixSymbol('X', 3, 3) Y = MatrixSymbol('Y', 3, 3) assert ask(Q.lower_triangular(X + Y), Q.lower_triangular(X) & Q.lower_triangular(Y)) is True assert ask(Q.triangular(X), Q.lower_triangular(X)) is True assert ask(Q.triangular(X + Y), Q.lower_triangular(X) & Q.lower_triangular(Y)) is True
def _eval_determinant(self): if self.blockshape == (1, 1): return det(self.blocks[0, 0]) if self.blockshape == (2, 2): [[A, B], [C, D]] = self.blocks.tolist() if ask(Q.invertible(A)): return det(A) * det(D - C * A.I * B) elif ask(Q.invertible(D)): return det(D) * det(A - B * D.I * C) return Determinant(self)
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_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 refine_Determinant(expr, assumptions): """ >>> from sympy import MatrixSymbol, Q, assuming, refine, det >>> X = MatrixSymbol('X', 2, 2) >>> det(X) Determinant(X) >>> with assuming(Q.orthogonal(X)): ... print(refine(det(X))) 1 """ if ask(Q.orthogonal(expr.arg), assumptions): return S.One elif ask(Q.singular(expr.arg), assumptions): return S.Zero elif ask(Q.unit_triangular(expr.arg), assumptions): return S.One return expr
def refine_Inverse(expr, assumptions): """ >>> from sympy import MatrixSymbol, Q, assuming, refine >>> X = MatrixSymbol('X', 2, 2) >>> X.I X**(-1) >>> with assuming(Q.orthogonal(X)): ... print(refine(X.I)) X.T """ if ask(Q.orthogonal(expr), assumptions): return expr.arg.T elif ask(Q.unitary(expr), assumptions): return expr.arg.conjugate() elif ask(Q.singular(expr), assumptions): raise ValueError("Inverse of singular matrix %s" % expr.arg) return expr
def refine_Inverse(expr, assumptions): """ >>> from sympy import MatrixSymbol, Q, assuming, refine >>> X = MatrixSymbol('X', 2, 2) >>> X.I X^-1 >>> with assuming(Q.orthogonal(X)): ... print(refine(X.I)) X.T """ if ask(Q.orthogonal(expr), assumptions): return expr.arg.T elif ask(Q.unitary(expr), assumptions): return expr.arg.conjugate() elif ask(Q.singular(expr), assumptions): raise ValueError("Inverse of singular matrix %s" % expr.arg) return expr
def _eval_power(self, exp): # exp = -1, 0, 1 are already handled at this stage if self._is_1x1() == True: return Identity(1) if (exp < 0) == True: raise NonInvertibleMatrixError("Matrix det == 0; not invertible") if ask(Q.integer(exp)): return self.shape[0]**(exp - 1) * OneMatrix(*self.shape) return super(OneMatrix, self)._eval_power(exp)
def test_matrix_element_sets(): X = MatrixSymbol('X', 4, 4) assert ask(Q.real(X[1, 2]), Q.real_elements(X)) assert ask(Q.integer(X[1, 2]), Q.integer_elements(X)) assert ask(Q.complex(X[1, 2]), Q.complex_elements(X)) assert ask(Q.integer_elements(Identity(3))) assert ask(Q.integer_elements(ZeroMatrix(3, 3))) assert ask(Q.integer_elements(OneMatrix(3, 3))) from sympy.matrices.expressions.fourier import DFT assert ask(Q.complex_elements(DFT(3)))
def test_invertible_BlockMatrix(): assert ask(Q.invertible(BlockMatrix([Identity(3)]))) == True assert ask(Q.invertible(BlockMatrix([ZeroMatrix(3, 3)]))) == False X = Matrix([[1, 2, 3], [3, 5, 4]]) Y = Matrix([[4, 2, 7], [2, 3, 5]]) # non-invertible A block assert ask( Q.invertible( BlockMatrix([ [Matrix.ones(3, 3), Y.T], [X, Matrix.eye(2)], ]))) == True # non-invertible B block assert ask( Q.invertible( BlockMatrix([ [Y.T, Matrix.ones(3, 3)], [Matrix.eye(2), X], ]))) == True # non-invertible C block assert ask( Q.invertible( BlockMatrix([ [X, Matrix.eye(2)], [Matrix.ones(3, 3), Y.T], ]))) == True # non-invertible D block assert ask( Q.invertible( BlockMatrix([ [Matrix.eye(2), X], [Y.T, Matrix.ones(3, 3)], ]))) == True
def refine_Transpose(expr, assumptions): """ >>> from sympy import MatrixSymbol, Q, assuming, refine >>> X = MatrixSymbol('X', 2, 2) >>> X.T X.T >>> with assuming(Q.symmetric(X)): ... print(refine(X.T)) X """ if ask(Q.symmetric(expr), assumptions): return expr.arg return expr
def test_invertible_BlockDiagMatrix(): assert ask(Q.invertible(BlockDiagMatrix(Identity(3), Identity(5)))) == True assert ask(Q.invertible(BlockDiagMatrix(ZeroMatrix(3, 3), Identity(5)))) == False assert ask(Q.invertible(BlockDiagMatrix(Identity(3), OneMatrix(5, 5)))) == False
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.diagonal(OneMatrix(1, 1))) is True assert ask(Q.diagonal(OneMatrix(3, 3))) is False 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_det_trace_positive(): X = MatrixSymbol('X', 4, 4) assert ask(Q.positive(Trace(X)), Q.positive_definite(X)) assert ask(Q.positive(Determinant(X)), Q.positive_definite(X))
def test_field_assumptions(): X = MatrixSymbol('X', 4, 4) Y = MatrixSymbol('Y', 4, 4) assert ask(Q.real_elements(X), Q.real_elements(X)) assert not ask(Q.integer_elements(X), Q.real_elements(X)) assert ask(Q.complex_elements(X), Q.real_elements(X)) assert ask(Q.complex_elements(X**2), Q.real_elements(X)) assert ask(Q.real_elements(X**2), Q.integer_elements(X)) assert ask(Q.real_elements(X + Y), Q.real_elements(X)) is None assert ask(Q.real_elements(X + Y), Q.real_elements(X) & Q.real_elements(Y)) from sympy.matrices.expressions.hadamard import HadamardProduct assert ask(Q.real_elements(HadamardProduct(X, Y)), Q.real_elements(X) & Q.real_elements(Y)) assert ask(Q.complex_elements(X + Y), Q.real_elements(X) & Q.complex_elements(Y)) assert ask(Q.real_elements(X.T), Q.real_elements(X)) assert ask(Q.real_elements(X.I), Q.real_elements(X) & Q.invertible(X)) assert ask(Q.real_elements(Trace(X)), Q.real_elements(X)) assert ask(Q.integer_elements(Determinant(X)), Q.integer_elements(X)) assert not ask(Q.integer_elements(X.I), Q.integer_elements(X)) alpha = Symbol('alpha') assert ask(Q.real_elements(alpha * X), Q.real_elements(X) & Q.real(alpha)) assert ask(Q.real_elements(LofLU(X)), Q.real_elements(X)) e = Symbol('e', integer=True, negative=True) assert ask(Q.real_elements(X**e), Q.real_elements(X) & Q.invertible(X)) assert ask(Q.real_elements(X**e), Q.real_elements(X)) is None
def test_invertible(): assert ask(Q.invertible(X), Q.invertible(X)) assert ask(Q.invertible(Y)) is False assert ask(Q.invertible(X * Y), Q.invertible(X)) is False assert ask(Q.invertible(X * Z), Q.invertible(X)) is None assert ask(Q.invertible(X * Z), Q.invertible(X) & Q.invertible(Z)) is True assert ask(Q.invertible(X.T)) is None assert ask(Q.invertible(X.T), Q.invertible(X)) is True assert ask(Q.invertible(X.I)) is True assert ask(Q.invertible(Identity(3))) is True assert ask(Q.invertible(ZeroMatrix(3, 3))) is False assert ask(Q.invertible(OneMatrix(1, 1))) is True assert ask(Q.invertible(OneMatrix(3, 3))) is False assert ask(Q.invertible(X), Q.fullrank(X) & Q.square(X))
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 _contains(self, other): if ask(Q.negative(other)) == False and ask(Q.integer(other)): return True return False
def _contains(self, other): if ask(Q.positive(other)) and ask(Q.integer(other)): return True return False
def _contains(self, other): return (other >= self.inf and other <= self.sup and ask(Q.integer((self.start - other)/self.step)))
def test_non_atoms(): assert ask(Q.real(Trace(X)), Q.positive(Trace(X)))
def _contains(self, other): from sympy.assumptions.ask import ask, Q return (other >= self.inf and other <= self.sup and ask(Q.integer((self.start - other)/self.step)))
def test_matrix_element_sets_slices_blocks(): X = MatrixSymbol('X', 4, 4) assert ask(Q.integer_elements(X[:, 3]), Q.integer_elements(X)) assert ask(Q.integer_elements(BlockMatrix([[X], [X]])), Q.integer_elements(X))
def test_matrix_element_sets_determinant_trace(): assert ask(Q.integer(Determinant(X)), Q.integer_elements(X)) assert ask(Q.integer(Trace(X)), Q.integer_elements(X))
def test_invertible_fullrank(): assert ask(Q.invertible(X), Q.fullrank(X)) is True
def test_singular(): assert ask(Q.singular(X)) is None assert ask(Q.singular(X), Q.invertible(X)) is False assert ask(Q.singular(X), ~Q.invertible(X)) is True
def test_triangular(): assert ask(Q.upper_triangular(X + Z.T + Identity(2)), Q.upper_triangular(X) & Q.lower_triangular(Z)) is True assert ask(Q.upper_triangular(X * Z.T), Q.upper_triangular(X) & Q.lower_triangular(Z)) is True assert ask(Q.lower_triangular(Identity(3))) is True assert ask(Q.lower_triangular(ZeroMatrix(3, 3))) is True assert ask(Q.upper_triangular(ZeroMatrix(3, 3))) is True assert ask(Q.lower_triangular(OneMatrix(1, 1))) is True assert ask(Q.upper_triangular(OneMatrix(1, 1))) is True assert ask(Q.lower_triangular(OneMatrix(3, 3))) is False assert ask(Q.upper_triangular(OneMatrix(3, 3))) is False assert ask(Q.triangular(X), Q.unit_triangular(X)) assert ask(Q.upper_triangular(X**3), Q.upper_triangular(X)) assert ask(Q.lower_triangular(X**3), Q.lower_triangular(X))
def test_positive_definite(): assert ask(Q.positive_definite(X), Q.positive_definite(X)) assert ask(Q.positive_definite(X.T), Q.positive_definite(X)) is True assert ask(Q.positive_definite(X.I), Q.positive_definite(X)) is True assert ask(Q.positive_definite(Y)) is False assert ask(Q.positive_definite(X)) is None assert ask(Q.positive_definite(X**3), Q.positive_definite(X)) assert ask(Q.positive_definite(X * Z * X), Q.positive_definite(X) & Q.positive_definite(Z)) is True assert ask(Q.positive_definite(X), Q.orthogonal(X)) assert ask(Q.positive_definite(Y.T * X * Y), Q.positive_definite(X) & Q.fullrank(Y)) is True assert not ask(Q.positive_definite(Y.T * X * Y), Q.positive_definite(X)) assert ask(Q.positive_definite(Identity(3))) is True assert ask(Q.positive_definite(ZeroMatrix(3, 3))) is False assert ask(Q.positive_definite(OneMatrix(1, 1))) is True assert ask(Q.positive_definite(OneMatrix(3, 3))) is False assert ask(Q.positive_definite(X + Z), Q.positive_definite(X) & Q.positive_definite(Z)) is True assert not ask(Q.positive_definite(-X), Q.positive_definite(X)) assert ask(Q.positive(X[1, 1]), Q.positive_definite(X))
def _contains(self, other): from sympy.assumptions.ask import ask, Q if ask(Q.negative(other)) == False and ask(Q.integer(other)): return True return False
def test_symmetric(): assert ask(Q.symmetric(X), Q.symmetric(X)) assert ask(Q.symmetric(X * Z), Q.symmetric(X)) is None assert ask(Q.symmetric(X * Z), Q.symmetric(X) & Q.symmetric(Z)) is True assert ask(Q.symmetric(X + Z), Q.symmetric(X) & Q.symmetric(Z)) is True assert ask(Q.symmetric(Y)) is False assert ask(Q.symmetric(Y * Y.T)) is True assert ask(Q.symmetric(Y.T * X * Y)) is None assert ask(Q.symmetric(Y.T * X * Y), Q.symmetric(X)) is True assert ask(Q.symmetric(X**10), Q.symmetric(X)) is True assert ask(Q.symmetric(A1x1)) is True assert ask(Q.symmetric(A1x1 + B1x1)) is True assert ask(Q.symmetric(A1x1 * B1x1)) is True assert ask(Q.symmetric(V1.T * V1)) is True assert ask(Q.symmetric(V1.T * (V1 + V2))) is True assert ask(Q.symmetric(V1.T * (V1 + V2) + A1x1)) is True assert ask(Q.symmetric(MatrixSlice(Y, (0, 1), (1, 2)))) is True assert ask(Q.symmetric(Identity(3))) is True assert ask(Q.symmetric(ZeroMatrix(3, 3))) is True assert ask(Q.symmetric(OneMatrix(3, 3))) is True
def test_square(): assert ask(Q.square(X)) assert not ask(Q.square(Y)) assert ask(Q.square(Y * Y.T))
def _contains(self, other): from sympy.assumptions.ask import ask, Q return (other >= self.inf and other <= self.sup and ask(Q.integer((self.start - other) / self.step)))
def test_fullrank(): assert ask(Q.fullrank(X), Q.fullrank(X)) assert ask(Q.fullrank(X**2), Q.fullrank(X)) assert ask(Q.fullrank(X.T), Q.fullrank(X)) is True assert ask(Q.fullrank(X)) is None assert ask(Q.fullrank(Y)) is None assert ask(Q.fullrank(X * Z), Q.fullrank(X) & Q.fullrank(Z)) is True assert ask(Q.fullrank(Identity(3))) is True assert ask(Q.fullrank(ZeroMatrix(3, 3))) is False assert ask(Q.fullrank(OneMatrix(1, 1))) is True assert ask(Q.fullrank(OneMatrix(3, 3))) is False assert ask(Q.invertible(X), ~Q.fullrank(X)) == False