Example #1
0
 def eval_inverse(self, expand=False):
     # Inverse of one by one block matrix is easy
     if self.blockshape==(1,1):
         mat = Matrix(1, 1, (Inverse(self.blocks[0]), ))
         return BlockMatrix(mat)
     # Inverse of a two by two block matrix is known
     elif expand and self.blockshape==(2,2):
         # Cite: The Matrix Cookbook Section 9.1.3
         A11, A12, A21, A22 = (self.blocks[0,0], self.blocks[0,1],
                 self.blocks[1,0], self.blocks[1,1])
         C1 = A11 - A12*Inverse(A22)*A21
         C2 = A22 - A21*Inverse(A11)*A12
         mat = Matrix([[Inverse(C1), Inverse(-A11)*A12*Inverse(C2)],
             [-Inverse(C2)*A21*Inverse(A11), Inverse(C2)]])
         return BlockMatrix(mat)
     else:
         raise NotImplementedError()
Example #2
0
def xxinv(mul):
    """ Y * X * X.I -> Y """
    from sympy.matrices.expressions import Inverse
    factor, matrices = mul.as_coeff_matrices()
    for i, (X, Y) in enumerate(zip(matrices[:-1], matrices[1:])):
        try:
            if X.is_square and Y.is_square and X == Inverse(Y):
                I = Identity(X.rows)
                return newmul(factor, *(matrices[:i] + [I] + matrices[i + 2:]))
        except ValueError:  # Y might not be invertible
            pass

    return mul
Example #3
0
def block_collapse(expr):
    """Evaluates a block matrix expression

    >>> from sympy import MatrixSymbol, BlockMatrix, symbols, Identity, Matrix, ZeroMatrix, block_collapse
    >>> n,m,l = symbols('n m l')
    >>> X = MatrixSymbol('X', n, n)
    >>> Y = MatrixSymbol('Y', m ,m)
    >>> Z = MatrixSymbol('Z', n, m)
    >>> B = BlockMatrix([[X, Z], [ZeroMatrix(m, n), Y]])
    >>> print B
    [X, Z]
    [0, Y]

    >>> C = BlockMatrix([[Identity(n), Z]])
    >>> print C
    [I, Z]

    >>> print block_collapse(C*B)
    [X, Z + Z*Y]
    """
    if expr.__class__ in [tuple, list, set, frozenset]:
        return expr.__class__([block_collapse(arg) for arg in expr])
    if expr.__class__ in [Tuple, FiniteSet]:
        return expr.__class__(*[block_collapse(arg) for arg in expr])

    if not expr.is_Matrix or (not expr.is_Add and not expr.is_Mul
            and not expr.is_Transpose and not expr.is_Pow
            and not expr.is_Inverse):
        return expr

    if expr.is_Transpose:
        expr = Transpose(block_collapse(expr.arg))
        if expr.is_Transpose and expr.arg.is_BlockMatrix:
            expr = expr.arg.eval_transpose()
        return expr

    if expr.is_Inverse:
        return Inverse(block_collapse(expr.arg))

    # Recurse on the subargs
    args = list(expr.args)
    for i in range(len(args)):
        arg = args[i]
        newarg = block_collapse(arg)
        while(newarg != arg): # Repeat until no new changes
            arg = newarg
            newarg = block_collapse(arg)
        args[i] = newarg

    if tuple(args) != expr.args:
        expr = expr.__class__(*args)

    # Turn  -[X, Y] into [-X, -Y]
    if (expr.is_Mul and len(expr.args)==2 and not expr.args[0].is_Matrix
            and expr.args[1].is_BlockMatrix):
        if expr.args[1].is_BlockDiagMatrix:
            return BlockDiagMatrix(
                    *[expr.args[0]*arg for arg in expr.args[1].diag])
        else:
            return BlockMatrix(expr.args[0]*expr.args[1].mat)

    if expr.is_Add:
        nonblocks = [arg for arg in expr.args if not arg.is_BlockMatrix]
        blocks = [arg for arg in expr.args if arg.is_BlockMatrix]
        if not blocks:
            return MatAdd(*nonblocks)
        block = blocks[0]
        for b in blocks[1:]:
            block = block._blockadd(b)
        if block.blockshape == (1,1):
            # Bring all the non-blocks into the block_matrix
            mat = Matrix(1, 1, (block.blocks[0,0] + MatAdd(*nonblocks), ))
            return BlockMatrix(mat)
        # Add identities to the blocks as block identities
        for i, mat in enumerate(nonblocks):
            c, M = mat.as_coeff_Mul()
            if M.is_Identity and block.is_structurally_symmetric:
                block_id = BlockDiagMatrix(
                        *[c*Identity(k) for k in block.rowblocksizes])
                nonblocks.pop(i)
                block = block._blockadd(block_id)


        return MatAdd(*(nonblocks+[block]))

    if expr.is_Mul:
        nonmatrices = [arg for arg in expr.args if not arg.is_Matrix]
        matrices = [arg for arg in expr.args if arg.is_Matrix]
        i = 0
        while (i+1 < len(matrices)):
            A, B = matrices[i:i+2]
            if A.is_BlockMatrix and B.is_BlockMatrix:
                matrices[i] = A._blockmul(B)
                matrices.pop(i+1)
            else:
                i+=1
        return MatMul(*(nonmatrices + matrices))

    if expr.is_Pow:
        rv = expr.base
        for i in range(1, expr.exp):
            rv = rv._blockmul(expr.base)
        return rv
Example #4
0
 def eval_inverse(self):
     return BlockDiagMatrix(*[Inverse(mat) for mat in self.diag])
Example #5
0
 def inverse(self):
     return Inverse(self)
Example #6
0
 def __pow__(self, other):
     if other == -S.One:
         return Inverse(self)
     return MatPow(self, other)
Example #7
0
 def I(self):
     return Inverse(self)
Example #8
0
 def inverse(self):
     # XXX document how this is different than inv
     return Inverse(self)
Example #9
0
 def _eval_inverse(self):
     from inverse import Inverse
     try:
         return MatMul(*[Inverse(arg) for arg in self.args[::-1]])
     except ShapeError:
         raise NotImplementedError("Can not decompose this Inverse")