o
    oho|                     @   s  d dl mZmZ d dlmZmZmZmZ d dlm	Z	 d dl
mZ d dlmZmZ d dlmZmZmZmZmZ d dlmZ d dlmZmZ d d	lmZ d d
lmZmZ d dlm Z  d dl!m"Z"m#Z# d dl$m%Z% d dl&m'Z' d dl(m)Z)m*Z* d dl+m,Z, d dl-m.Z. d dl/m0Z0 d dl1m2Z2m3Z3 d dl4m5Z5 d dl6m7Z7m8Z8 G dd de)Z9G dd de9Z:dd Z;dd Z<dd Z=d d! Z>d"d# Z?d$d% Z@d&d' ZAd(d) ZBd*d+ ZCd,d- ZDd.d/ ZEd0d1 ZFd2d3 ZGd4d5 ZHd6d7 ZId8S )9    )Qask)BasicAddMulS_sympifyadjoint)reim)typedexhaust	conditiondo_oneunpack)	bottom_up)is_sequencesift)
filldedent)Matrix
ShapeError)NonInvertibleMatrixError)detDeterminant)Inverse)MatAdd)
MatrixExprMatrixElement)MatMul)MatPowMatrixSlice)
ZeroMatrixIdentitytrace)	Transpose	transposec                       s   e Zd ZdZdd Zedd Zedd Zedd	 Zed
d Z	edd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zd d! Zd4d$d%Zd&d' Zd(d) Zd*d+ Zd,d- Zed.d/ Zed0d1 Z fd2d3Z  ZS )5BlockMatrixau  A BlockMatrix is a Matrix comprised of other matrices.

    The submatrices are stored in a SymPy Matrix object but accessed as part of
    a Matrix Expression

    >>> from sympy import (MatrixSymbol, BlockMatrix, symbols,
    ...     Identity, 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)
    Matrix([
    [X, Z],
    [0, Y]])

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

    >>> print(block_collapse(C*B))
    Matrix([[X, Z + Z*Y]])

    Some matrices might be comprised of rows of blocks with
    the matrices in each row having the same height and the
    rows all having the same total number of columns but
    not having the same number of columns for each matrix
    in each row. In this case, the matrix is not a block
    matrix and should be instantiated by Matrix.

    >>> from sympy import ones, Matrix
    >>> dat = [
    ... [ones(3,2), ones(3,3)*2],
    ... [ones(2,3)*3, ones(2,2)*4]]
    ...
    >>> BlockMatrix(dat)
    Traceback (most recent call last):
    ...
    ValueError:
    Although this matrix is comprised of blocks, the blocks do not fill
    the matrix in a size-symmetric fashion. To create a full matrix from
    these arguments, pass them directly to Matrix.
    >>> Matrix(dat)
    Matrix([
    [1, 1, 2, 2, 2],
    [1, 1, 2, 2, 2],
    [1, 1, 2, 2, 2],
    [3, 3, 3, 4, 4],
    [3, 3, 3, 4, 4]])

    See Also
    ========
    sympy.matrices.matrixbase.MatrixBase.irregular
    c           	         sj  ddl m} dd t|dks%t|d r%tfdd|d D dkr+ttd|r1|d ng srBd rBgtd	d D dk }}|rD ]}td
d |D dk}|sd nqS|}|rttd D ] t fddttD dk}|s nqq|stdd D dk}|r|rttdttd|dd}t| |}|S )Nr   ImmutableDenseMatrixc                 S   s   t | ddS )N	is_MatrixF)getattri r1   z/var/www/html/construction_image-detection-poc/venv/lib/python3.10/site-packages/sympy/matrices/expressions/blockmatrix.py<lambda>S   s    z%BlockMatrix.__new__.<locals>.<lambda>   c                    s   h | ]} |qS r1   r1   .0r)isMatr1   r2   	<setcomp>V       z&BlockMatrix.__new__.<locals>.<setcomp>z\
                expecting a sequence of 1 or more rows
                containing Matrices.c                 S   s   h | ]}t |qS r1   )lenr5   r1   r1   r2   r9   `   r:   c                 S   s   h | ]}|j qS r1   rowsr6   r0   r1   r1   r2   r9   d       c                    s   h | ]	}|   j qS r1   colsr>   )cr=   r1   r2   r9   k   s    c                 S   s   h | ]}t d d |D qS )c                 s       | ]}|j V  qd S Nr@   r>   r1   r1   r2   	<genexpr>r       z0BlockMatrix.__new__.<locals>.<setcomp>.<genexpr>)sumr5   r1   r1   r2   r9   q   s    a0  
                        Although this matrix is comprised of blocks,
                        the blocks do not fill the matrix in a
                        size-symmetric fashion. To create a full matrix
                        from these arguments, pass them directly to
                        Matrix.a}  
                    When there are not the same number of rows in each
                    row's matrices or there are not the same number of
                    total columns in each row, the matrix is not a
                    block matrix. If this matrix is known to consist of
                    blocks fully filling a 2-D space then see
                    Matrix.irregular.Fevaluate)	sympy.matrices.immutabler,   r;   r   
ValueErrorr   ranger   __new__)	clsargskwargsr,   blockyokr7   matobjr1   )rB   r8   r=   r2   rM   Q   sR   

zBlockMatrix.__new__c                 C   sj   d }}| j }t|jd D ]}|||df jd 7 }qt|jd D ]}||d|f jd 7 }q#||fS )Nr   r4   )blocksrL   shape)selfnumrowsnumcolsMr0   r1   r1   r2   rV      s   zBlockMatrix.shapec                 C   s   | j jS rD   rU   rV   rW   r1   r1   r2   
blockshape   s   zBlockMatrix.blockshapec                 C   s
   | j d S )Nr   rO   r\   r1   r1   r2   rU      s   
zBlockMatrix.blocksc                        fddt  jd D S )Nc                    s   g | ]
} j |d f jqS r   )rU   r=   r>   r\   r1   r2   
<listcomp>       z-BlockMatrix.rowblocksizes.<locals>.<listcomp>r   rL   r]   r\   r1   r\   r2   rowblocksizes      zBlockMatrix.rowblocksizesc                    r_   )Nc                    s   g | ]
} j d |f jqS r`   )rU   rA   r>   r\   r1   r2   ra      rb   z-BlockMatrix.colblocksizes.<locals>.<listcomp>r4   rc   r\   r1   r\   r2   colblocksizes   re   zBlockMatrix.colblocksizesc                 C   s:   t |to| j|jko| j|jko| j|jko| j|jkS rD   )
isinstancer*   rV   r]   rd   rf   rW   otherr1   r1   r2   structurally_equal   s   




zBlockMatrix.structurally_equalc                 C   s.   t |tr| j|jkrt| j|j S | | S rD   )rg   r*   rf   rd   rU   rh   r1   r1   r2   	_blockmul   s   
zBlockMatrix._blockmulc                 C   s,   t |tr| |rt| j|j S | | S rD   )rg   r*   rj   rU   rh   r1   r1   r2   	_blockadd   s
   
zBlockMatrix._blockaddc                 C   8   dd | j D }t| jd | jd |}| }t|S )Nc                 S      g | ]}t |qS r1   r)   r6   matrixr1   r1   r2   ra      r:   z/BlockMatrix._eval_transpose.<locals>.<listcomp>r   r4   rU   r   r]   r)   r*   rW   matricesrZ   r1   r1   r2   _eval_transpose      zBlockMatrix._eval_transposec                 C   rm   )Nc                 S   rn   r1   r
   rp   r1   r1   r2   ra      r:   z-BlockMatrix._eval_adjoint.<locals>.<listcomp>r   r4   rr   rs   r1   r1   r2   _eval_adjoint   rv   zBlockMatrix._eval_adjointc                    s>    j  jkr fddt jd D }tdd |D  S d S )Nc                    s   g | ]	} j ||f qS r1   rU   r>   r\   r1   r2   ra          z+BlockMatrix._eval_trace.<locals>.<listcomp>r   c                 S   rn   r1   r&   r6   blockr1   r1   r2   ra      r:   )rd   rf   rL   r]   r   )rW   rU   r1   r\   r2   _eval_trace   s   zBlockMatrix._eval_tracec                 C   s   | j dkrt| jd S | j dkrH| j \\}}\}}tt|r2t|t|||j |   S tt|rHt|t|||j |   S t| S )Nr4   r4   r   r      r   )	r]   r   rU   tolistr   r   
invertibleIr   )rW   ABCDr1   r1   r2   _eval_determinant   s   

zBlockMatrix._eval_determinantc                 C   s`   dd | j D }t| jd | jd |}dd | j D }t| jd | jd |}t|t|fS )Nc                 S   rn   r1   )r   rp   r1   r1   r2   ra      r:   z2BlockMatrix._eval_as_real_imag.<locals>.<listcomp>r   r4   c                 S   rn   r1   )r   rp   r1   r1   r2   ra      r:   )rU   r   r]   r*   )rW   real_matricesim_matricesr1   r1   r2   _eval_as_real_imag   s
   zBlockMatrix._eval_as_real_imagc                 C   s   t | j|S rD   )r*   rU   diff)rW   xr1   r1   r2   _eval_derivative   s   zBlockMatrix._eval_derivativec                 C   s   |   S )a  Return transpose of matrix.

        Examples
        ========

        >>> from sympy import MatrixSymbol, BlockMatrix, ZeroMatrix
        >>> from sympy.abc import m, n
        >>> X = MatrixSymbol('X', n, n)
        >>> Y = MatrixSymbol('Y', m, m)
        >>> Z = MatrixSymbol('Z', n, m)
        >>> B = BlockMatrix([[X, Z], [ZeroMatrix(m,n), Y]])
        >>> B.transpose()
        Matrix([
        [X.T,  0],
        [Z.T, Y.T]])
        >>> _.transpose()
        Matrix([
        [X, Z],
        [0, Y]])
        )ru   r\   r1   r1   r2   r)      s   zBlockMatrix.transposer   Fc           	      C   s   | j dkrr| j \\}}\}}||||d}zO|r*|| j||   || j n||  }|dkr=||| |  W S |dkrJ||| |  W S |dkrW||| |  W S |dkrd||| |  W S | W S  tyq   tdw td)	a  Return the Schur Complement of the 2x2 BlockMatrix

        Parameters
        ==========

        mat : String, optional
            The matrix with respect to which the
            Schur Complement is calculated. 'A' is
            used by default

        generalized : bool, optional
            If True, returns the generalized Schur
            Component which uses Moore-Penrose Inverse

        Examples
        ========

        >>> from sympy import symbols, MatrixSymbol, BlockMatrix
        >>> m, n = symbols('m n')
        >>> A = MatrixSymbol('A', n, n)
        >>> B = MatrixSymbol('B', n, m)
        >>> C = MatrixSymbol('C', m, n)
        >>> D = MatrixSymbol('D', m, m)
        >>> X = BlockMatrix([[A, B], [C, D]])

        The default Schur Complement is evaluated with "A"

        >>> X.schur()
        -C*A**(-1)*B + D
        >>> X.schur('D')
        A - B*D**(-1)*C

        Schur complement with non-invertible matrices is not
        defined. Instead, the generalized Schur complement can
        be calculated which uses the Moore-Penrose Inverse. To
        achieve this, `generalized` must be set to `True`

        >>> X.schur('B', generalized=True)
        C - D*(B.T*B)**(-1)*B.T*A
        >>> X.schur('C', generalized=True)
        -A*(C.T*C)**(-1)*C.T*D + B

        Returns
        =======

        M : Matrix
            The Schur Complement Matrix

        Raises
        ======

        ShapeError
            If the block matrix is not a 2x2 matrix

        NonInvertibleMatrixError
            If given matrix is non-invertible

        References
        ==========

        .. [1] Wikipedia Article on Schur Component : https://en.wikipedia.org/wiki/Schur_complement

        See Also
        ========

        sympy.matrices.matrixbase.MatrixBase.pinv
        r   )r   r   r   r   r   r   r   r   zThe given matrix is not invertible. Please set generalized=True             to compute the generalized Schur Complement which uses Moore-Penrose Inversez>Schur Complement can only be calculated for 2x2 block matrices)r]   rU   r   Tinvr   r   )	rW   rS   generalizedr   r   r   r   dr   r1   r1   r2   schur   s(   
E0zBlockMatrix.schurc                 C   s   | j dkrY| j \\}}\}}z|j}W n ty    tdw t|jd }t|jd }t|j }t||g|| |gg}	t	|| 
 }t||| g|j|gg}
|	||
fS td)aL  Returns the Block LDU decomposition of
        a 2x2 Block Matrix

        Returns
        =======

        (L, D, U) : Matrices
            L : Lower Diagonal Matrix
            D : Diagonal Matrix
            U : Upper Diagonal Matrix

        Examples
        ========

        >>> from sympy import symbols, MatrixSymbol, BlockMatrix, block_collapse
        >>> m, n = symbols('m n')
        >>> A = MatrixSymbol('A', n, n)
        >>> B = MatrixSymbol('B', n, m)
        >>> C = MatrixSymbol('C', m, n)
        >>> D = MatrixSymbol('D', m, m)
        >>> X = BlockMatrix([[A, B], [C, D]])
        >>> L, D, U = X.LDUdecomposition()
        >>> block_collapse(L*D*U)
        Matrix([
        [A, B],
        [C, D]])

        Raises
        ======

        ShapeError
            If the block matrix is not a 2x2 matrix

        NonInvertibleMatrixError
            If the matrix "A" is non-invertible

        See Also
        ========
        sympy.matrices.expressions.blockmatrix.BlockMatrix.UDLdecomposition
        sympy.matrices.expressions.blockmatrix.BlockMatrix.LUdecomposition
        r   zTBlock LDU decomposition cannot be calculated when                    "A" is singularr   r4   z@Block LDU decomposition is supported only for 2x2 block matrices)r]   rU   r   r   r   r%   rV   r$   r*   BlockDiagMatrixr   r   r   )rW   r   r   r   r   AIIpIqZLUr1   r1   r2   LDUdecompositionU  s"   
*


zBlockMatrix.LDUdecompositionc                 C   s   | j dkrZ| j \\}}\}}z|j}W n ty    tdw t|jd }t|jd }t|j }t||| g|j	|gg}	t
| d|}t||g|| |gg}
|	||
fS td)aL  Returns the Block UDL decomposition of
        a 2x2 Block Matrix

        Returns
        =======

        (U, D, L) : Matrices
            U : Upper Diagonal Matrix
            D : Diagonal Matrix
            L : Lower Diagonal Matrix

        Examples
        ========

        >>> from sympy import symbols, MatrixSymbol, BlockMatrix, block_collapse
        >>> m, n = symbols('m n')
        >>> A = MatrixSymbol('A', n, n)
        >>> B = MatrixSymbol('B', n, m)
        >>> C = MatrixSymbol('C', m, n)
        >>> D = MatrixSymbol('D', m, m)
        >>> X = BlockMatrix([[A, B], [C, D]])
        >>> U, D, L = X.UDLdecomposition()
        >>> block_collapse(U*D*L)
        Matrix([
        [A, B],
        [C, D]])

        Raises
        ======

        ShapeError
            If the block matrix is not a 2x2 matrix

        NonInvertibleMatrixError
            If the matrix "D" is non-invertible

        See Also
        ========
        sympy.matrices.expressions.blockmatrix.BlockMatrix.LDUdecomposition
        sympy.matrices.expressions.blockmatrix.BlockMatrix.LUdecomposition
        r   zTBlock UDL decomposition cannot be calculated when                    "D" is singularr   r4   r   z@Block UDL decomposition is supported only for 2x2 block matrices)r]   rU   r   r   r   r%   rV   r$   r*   r   r   r   r   )rW   r   r   r   r   DIr   r   r   r   r   r1   r1   r2   UDLdecomposition  s"   
*


zBlockMatrix.UDLdecompositionc           
      C   s   | j dkrO| j \\}}\}}z
|tj }|j}W n ty%   tdw t|j }| 	 tj }t
||g|| |gg}t
||| g|j|gg}	||	fS td)a#  Returns the Block LU decomposition of
        a 2x2 Block Matrix

        Returns
        =======

        (L, U) : Matrices
            L : Lower Diagonal Matrix
            U : Upper Diagonal Matrix

        Examples
        ========

        >>> from sympy import symbols, MatrixSymbol, BlockMatrix, block_collapse
        >>> m, n = symbols('m n')
        >>> A = MatrixSymbol('A', n, n)
        >>> B = MatrixSymbol('B', n, m)
        >>> C = MatrixSymbol('C', m, n)
        >>> D = MatrixSymbol('D', m, m)
        >>> X = BlockMatrix([[A, B], [C, D]])
        >>> L, U = X.LUdecomposition()
        >>> block_collapse(L*U)
        Matrix([
        [A, B],
        [C, D]])

        Raises
        ======

        ShapeError
            If the block matrix is not a 2x2 matrix

        NonInvertibleMatrixError
            If the matrix "A" is non-invertible

        See Also
        ========
        sympy.matrices.expressions.blockmatrix.BlockMatrix.UDLdecomposition
        sympy.matrices.expressions.blockmatrix.BlockMatrix.LDUdecomposition
        r   zSBlock LU decomposition cannot be calculated when                    "A" is singularz?Block LU decomposition is supported only for 2x2 block matrices)r]   rU   r   r   Halfr   r   r$   rV   r   r*   r   r   )
rW   r   r   r   r   r   r   r   r   r   r1   r1   r2   LUdecomposition  s    
)


zBlockMatrix.LUdecompositionc                 K   s   ||}}t | jD ](\}}||k }|dkr n|dkr!||8 }q
|| jd d k r2t| ||  S q
t | jD ](\}	}
||
k }|dkrF n|dkrO||
8 }q8|	| jd d k r`t| ||  S q8| j||	f ||f S )NTFr   r4   )	enumeraterd   r]   r   rf   rU   )rW   r0   jrP   orig_iorig_j	row_blockrX   cmp	col_blockrY   r1   r1   r2   _entry  s(   


zBlockMatrix._entryc                 C   s   | j d | j d krdS t| j d D ],}t| j d D ]"}||kr.| j||f js.  dS ||kr>| j||f js>  dS qqdS )Nr   r4   FT)r]   rL   rU   is_Identityis_ZeroMatrix)rW   r0   r   r1   r1   r2   r     s   zBlockMatrix.is_Identityc                 C   s   | j | jkS rD   )rd   rf   r\   r1   r1   r2   is_structurally_symmetric)  s   z%BlockMatrix.is_structurally_symmetricc                    s2   | |krdS t |tr| j|jkrdS t |S )NT)rg   r*   rU   superequalsrh   	__class__r1   r2   r   -  s
   zBlockMatrix.equals)r   F)__name__
__module____qualname____doc__rM   propertyrV   r]   rU   rd   rf   rj   rk   rl   ru   rw   r|   r   r   r   r)   r   r   r   r   r   r   r   r   __classcell__r1   r1   r   r2   r*      sB    74
	



			
[<<:

r*   c                   @   s   e Zd ZdZdd Zedd Zedd Zedd	 Zed
d Z	edd Z
edd Zdd Zdd Zd ddZdd Zdd Zdd Zdd ZdS )!r   a  A sparse matrix with block matrices along its diagonals

    Examples
    ========

    >>> from sympy import MatrixSymbol, BlockDiagMatrix, symbols
    >>> n, m, l = symbols('n m l')
    >>> X = MatrixSymbol('X', n, n)
    >>> Y = MatrixSymbol('Y', m, m)
    >>> BlockDiagMatrix(X, Y)
    Matrix([
    [X, 0],
    [0, Y]])

    Notes
    =====

    If you want to get the individual diagonal blocks, use
    :meth:`get_diag_blocks`.

    See Also
    ========

    sympy.matrices.dense.diag
    c                 G   s   t jtgdd |D R  S )Nc                 S   rn   r1   r   )r6   mr1   r1   r2   ra   P  r:   z+BlockDiagMatrix.__new__.<locals>.<listcomp>)r   rM   r   )rN   matsr1   r1   r2   rM   O  s   zBlockDiagMatrix.__new__c                 C      | j S rD   r^   r\   r1   r1   r2   diagR  s   zBlockDiagMatrix.diagc                    s8   ddl m} | j  fddtt D }||ddS )Nr   r+   c                    s(   g | ]  fd dt tD qS )c                    s2   g | ]} |kr  n
t   j| jqS r1   )r$   r=   rA   r6   r   )r0   r   r1   r2   ra   Z  s    *z5BlockDiagMatrix.blocks.<locals>.<listcomp>.<listcomp>)rL   r;   r6   r   r/   r2   ra   Z  s
    

z*BlockDiagMatrix.blocks.<locals>.<listcomp>FrH   )rJ   r,   rO   rL   r;   )rW   r,   datar1   r   r2   rU   V  s   

zBlockDiagMatrix.blocksc                 C   s(   t dd | jD t dd | jD fS )Nc                 s   rC   rD   r<   rz   r1   r1   r2   rE   a  rF   z(BlockDiagMatrix.shape.<locals>.<genexpr>c                 s   rC   rD   r@   rz   r1   r1   r2   rE   b  rF   )rG   rO   r\   r1   r1   r2   rV   _  s   zBlockDiagMatrix.shapec                 C   s   t | j}||fS rD   )r;   rO   )rW   nr1   r1   r2   r]   d  s   
zBlockDiagMatrix.blockshapec                 C      dd | j D S )Nc                 S      g | ]}|j qS r1   r<   rz   r1   r1   r2   ra   k  r?   z1BlockDiagMatrix.rowblocksizes.<locals>.<listcomp>r^   r\   r1   r1   r2   rd   i     zBlockDiagMatrix.rowblocksizesc                 C   r   )Nc                 S   r   r1   r@   rz   r1   r1   r2   ra   o  r?   z1BlockDiagMatrix.colblocksizes.<locals>.<listcomp>r^   r\   r1   r1   r2   rf   m  r   zBlockDiagMatrix.colblocksizesc                 C   s   t dd | jD S )z%Returns true if all blocks are squarec                 s   rC   rD   )	is_squarer6   rS   r1   r1   r2   rE   s  rF   z5BlockDiagMatrix._all_square_blocks.<locals>.<genexpr>)allrO   r\   r1   r1   r2   _all_square_blocksq  s   z"BlockDiagMatrix._all_square_blocksc                 C   s"   |   rtdd | jD  S tjS )Nc                 S   rn   r1   )r   r   r1   r1   r2   ra   w  r:   z5BlockDiagMatrix._eval_determinant.<locals>.<listcomp>)r   r   rO   r   Zeror\   r1   r1   r2   r   u  s   z!BlockDiagMatrix._eval_determinantignoredc                 C   s$   |   rtdd | jD  S td)Nc                 S      g | ]}|  qS r1   )inverser   r1   r1   r2   ra   ~  r:   z1BlockDiagMatrix._eval_inverse.<locals>.<listcomp>z Matrix det == 0; not invertible.)r   r   rO   r   )rW   expandr1   r1   r2   _eval_inverse|  s   zBlockDiagMatrix._eval_inversec                 C   s   t dd | jD  S )Nc                 S   r   r1   ro   r   r1   r1   r2   ra     r:   z3BlockDiagMatrix._eval_transpose.<locals>.<listcomp>)r   rO   r\   r1   r1   r2   ru     s   zBlockDiagMatrix._eval_transposec                 C   s>   t |tr| j|jkrtdd t| j|jD  S t| |S )Nc                 S   s   g | ]\}}|| qS r1   r1   r6   abr1   r1   r2   ra         z-BlockDiagMatrix._blockmul.<locals>.<listcomp>)rg   r   rf   rd   ziprO   r*   rk   rh   r1   r1   r2   rk     s   
zBlockDiagMatrix._blockmulc                 C   sV   t |tr%| j|jkr%| j|jkr%| j|jkr%tdd t| j|jD  S t| |S )Nc                 S   s   g | ]\}}|| qS r1   r1   r   r1   r1   r2   ra     r   z-BlockDiagMatrix._blockadd.<locals>.<listcomp>)	rg   r   r]   rd   rf   r   rO   r*   rl   rh   r1   r1   r2   rl     s   
zBlockDiagMatrix._blockaddc                 C   r   )a  Return the list of diagonal blocks of the matrix.

        Examples
        ========

        >>> from sympy import BlockDiagMatrix, Matrix

        >>> A = Matrix([[1, 2], [3, 4]])
        >>> B = Matrix([[5, 6], [7, 8]])
        >>> M = BlockDiagMatrix(A, B)

        How to get diagonal blocks from the block diagonal matrix:

        >>> diag_blocks = M.get_diag_blocks()
        >>> diag_blocks[0]
        Matrix([
        [1, 2],
        [3, 4]])
        >>> diag_blocks[1]
        Matrix([
        [5, 6],
        [7, 8]])
        r^   r\   r1   r1   r2   get_diag_blocks  s   zBlockDiagMatrix.get_diag_blocksN)r   )r   r   r   r   rM   r   r   rU   rV   r]   rd   rf   r   r   r   ru   rk   rl   r   r1   r1   r1   r2   r   5  s,    






	r   c                 C   s   ddl m} dd }t|tttttttt	t
tt	tttttttti}ttt||d}|| }t|dd}|durA| S |S )a  Evaluates a block matrix expression

    >>> from sympy import MatrixSymbol, BlockMatrix, symbols, Identity, 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)
    Matrix([
    [X, Z],
    [0, Y]])

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

    >>> print(block_collapse(C*B))
    Matrix([[X, Z + Z*Y]])
    r   )expr_fnsc                 S   s   t | to	| tS rD   )rg   r   hasr*   exprr1   r1   r2   r3     r:   z block_collapse.<locals>.<lambda>)fnsdoitN)sympy.strategies.utilr   r   r   r   r   	bc_mataddbc_block_plus_identr    	bc_matmulbc_distr!   r(   bc_transposer   
bc_inverser*   	bc_unpackdeblockr   r   r.   )r   r   hasbmconditioned_rlruleresultr   r1   r1   r2   block_collapse  s2   


r   c                 C   s   | j dkr
| jd S | S )Nr}   r~   )r]   rU   r   r1   r1   r2   r     s   

r   c                 C   s`   t | jdd }|d }|s| S |d }|d }|dd  D ]}||}q|r.t| | S |S )Nc                 S   s
   t | tS rD   rg   r*   )rZ   r1   r1   r2   r3     s   
 zbc_matadd.<locals>.<lambda>TFr   r4   )r   rO   rl   r   )r   rO   rU   	nonblocksr{   r   r1   r1   r2   r     s   r   c                    s   dd | j D }|s| S dd | j D   rJt fdd D rJ d jrJtdd  d jD  }dd | j D }t|t| g |R   S | S )	Nc                 S   s   g | ]}|j r|qS r1   )r   r6   argr1   r1   r2   ra     s    z'bc_block_plus_ident.<locals>.<listcomp>c                 S   s   g | ]	}t |tr|qS r1   r   r   r1   r1   r2   ra     ry   c                 3   s    | ]
}|  d  V  qdS )r   N)rj   )r6   r   rx   r1   r2   rE     s    z&bc_block_plus_ident.<locals>.<genexpr>r   c                 S   rn   r1   )r%   )r6   kr1   r1   r2   ra     s    c                 S   s    g | ]}|j st|ts|qS r1   )r   rg   r*   r   r1   r1   r2   ra     s     )rO   r   r   r   rd   r   r;   r   )r   identsblock_idrestr1   rx   r2   r     s    r   c                    s   |   \}dkr| S t|}t|tr%|j fdd D }t| S t|tr>|j  fddt jD }t|S | S )z  Turn  a*[X, Y] into [a*X, a*Y] r4   c                    s   g | ]} | qS r1   r1   r   )factorr1   r2   ra     r:   zbc_dist.<locals>.<listcomp>c                    s(   g | ]  fd dt jD qS )c                    s   g | ]
} |f  qS r1   r1   r   )r   r   r0   r1   r2   ra     rb   z&bc_dist.<locals>.<listcomp>.<listcomp>)rL   rA   r   r   r   r/   r2   ra     s    )	as_coeff_mmulr   rg   r   r   r*   rU   rL   r=   )r   rS   unpackednew_Br1   r   r2   r     s   

r   c                 C   s8  t | tr#| jd jr!| jd dkr!d| jd g| jd  }}n| S |  \}}d}|d t|k r|||d  \}}t |trVt |trV||||< ||d  n4t |trn|t|gg||< ||d  nt |trt|gg|||< ||d  n|d7 }|d t|k s3t	|g|R  
 S )Nr4   r   r   )rg   r!   rO   
is_Integeras_coeff_matricesr;   r*   rk   popr    r   )r   r   rt   r0   r   r   r1   r1   r2   r     s(   


r   c                 C   s   t | j}| S rD   )r   r   ru   )r   collapser1   r1   r2   r   3  s   
r   c                 C   s:   t | jtr
|  S t| }| |kr|S ttt| jS rD   )rg   r   r   r   blockinverse_1x1blockinverse_2x2r   reblock_2x2)r   expr2r1   r1   r2   r   8  s   r   c                 C   s<   t | jtr| jjdkrt| jjd  gg}t|S | S )Nr}   r   )rg   r   r*   r]   r   rU   r   )r   rS   r1   r1   r2   r   A  s   r   c                 C   s  t | jtr| jjdkr| jj \\}}\}}t||||}|d kr*| j|j}|dkrO|j}t||| | | |  | | | g| | | |ggS |dkrt|j}t| | | |g||| | | |  | | | ggS |dkr|j}	t|	 | | |	|	| | | |	  g|| | |	 ggS |dkr|j}
t|| | |
 g|
 | | |
|
| | | |
  ggS | S )Nr   r   r   r   r   )	rg   r   r*   r]   rU   r   _choose_2x2_inversion_formular   r   )r   r   r   r   r   formulaMIr   BICIr   r1   r1   r2   r   H  s(   
<<<<r   c                 C   s   t t| }|dkrdS t t|}|dkrdS t t|}|dkr'dS t t|}|dkr4dS |dkr:dS |dkr@dS |dkrFdS |dkrLdS dS )a\  
    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.
    Tr   r   r   r   FN)r   r   r   )r   r   r   r   A_invB_invC_invD_invr1   r1   r2   r   a  s*   r   c                    s   t | tr| jts| S dd }| j| zGtdt fddt jd D g }td jd D ]%}t |df j}td jd D ]}|	 ||f j}qG|
|}q4t|W S  tyi   |  Y S w )z( Flatten a BlockMatrix of BlockMatrices c                 S   s   t | tr| S t| ggS rD   r   )r   r1   r1   r2   r3     ry   zdeblock.<locals>.<lambda>r   c                 3   s$    | ]} d |f j jd V  qdS )r   r4   Nr[   r>   bbr1   r2   rE     s   " zdeblock.<locals>.<genexpr>r4   )rg   r*   rU   r   	applyfuncr   rG   rL   rV   row_joincol_joinr   )r   wrapMMrowrZ   colr1   r  r2   r     s   (
r   c                 C   sD  t | trtdd | jD s| S t}| j\}}| j}td|D ][}td|D ]S}t||d|d|f }t||d||df }t|||dd|f }	t|||d|df }
t|||	|
}|durzt||g|	|
gg    S q'q ||d ||dddf g||dddf ||ddddf ggS )z
    Reblock a BlockMatrix so that it has 2x2 blocks of block matrices.  If
    possible in such a way that the matrix continues to be invertible using the
    classical 2x2 block inversion formulas.
    c                 s   s    | ]}|d kV  qdS )r   Nr1   )r6   r   r1   r1   r2   rE     s    zreblock_2x2.<locals>.<genexpr>r4   Nr~   r   )rg   r*   r   r]   rU   rL   r   r   )r   BM	rowblocks	colblocksrU   r0   r   r   r   r   r   r   r1   r1   r2   r     s&   
*r   c                 C   s0   d}g }| D ]}| ||| f ||7 }q|S )z Convert sequence of numbers into pairs of low-high pairs

    >>> from sympy.matrices.expressions.blockmatrix import bounds
    >>> bounds((1, 10, 50))
    [(0, 1), (1, 11), (11, 61)]
    r   )append)sizeslowrvsizer1   r1   r2   bounds  s   
r  c                    s(   t |}t | t fdd|D S )a   Cut a matrix expression into Blocks

    >>> from sympy import ImmutableMatrix, blockcut
    >>> M = ImmutableMatrix(4, 4, range(16))
    >>> B = blockcut(M, (1, 3), (1, 3))
    >>> type(B).__name__
    'BlockMatrix'
    >>> ImmutableMatrix(B.blocks[0, 1])
    Matrix([[1, 2, 3]])
    c                    s    g | ]  fd dD qS )c                    s   g | ]}t  |qS r1   r"   )r6   colbound)r   rowboundr1   r2   ra     s    z'blockcut.<locals>.<listcomp>.<listcomp>r1   r   	colboundsr   )r  r2   ra     s
    
zblockcut.<locals>.<listcomp>)r  r*   )r   rowsizescolsizes	rowboundsr1   r  r2   blockcut  s
   r  N)Jsympy.assumptions.askr   r   
sympy.corer   r   r   r   sympy.core.sympifyr	   sympy.functionsr   $sympy.functions.elementary.complexesr   r   sympy.strategiesr   r   r   r   r   sympy.strategies.traverser   sympy.utilities.iterablesr   r   sympy.utilities.miscr   sympy.matricesr   r   sympy.matrices.exceptionsr   &sympy.matrices.expressions.determinantr   r   "sympy.matrices.expressions.inverser   !sympy.matrices.expressions.mataddr   "sympy.matrices.expressions.matexprr   r   !sympy.matrices.expressions.matmulr    !sympy.matrices.expressions.matpowr!    sympy.matrices.expressions.slicer#   "sympy.matrices.expressions.specialr$   r%    sympy.matrices.expressions.tracer'   $sympy.matrices.expressions.transposer(   r)   r*   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r1   r1   r1   r2   <module>   sT         {3	$