B
    [8                 @   s  d dl mZmZ d dlmZmZ d dlmZmZm	Z	 d dl
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 d dl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" 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.m/Z/ G dd deZ0G dd de0Z1dd Z2dd Z3dd Z4dd Z5dd Z6d d! Z7d"d# Z8d$d% Z9d&d' Z:d(d) Z;d*d+ Z<d,d- Z=d.d/ Z>d0d1 Z?d2S )3    )print_functiondivision)askQ)BasicAddsympify)range)typedexhaust	conditiondo_oneunpack)	bottom_up)sift)
MatrixExpr
ZeroMatrixIdentity)MatMul)MatAdd)	Transpose	transpose)Trace)detDeterminant)MatrixSlice)Inverse)Matrix
ShapeError)reimc                   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ed d! Zed"d# Z fd$d%Z  ZS )&BlockMatrixa  A BlockMatrix is a Matrix composed of other smaller, submatrices

    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*Y + Z]])

    c             G   s.   ddl m} tt|}|| }t| |}|S )Nr   )ImmutableDenseMatrix)sympy.matrices.immutabler"   mapr   r   __new__)clsargsr"   matobj r*   Elib/python3.7/site-packages/sympy/matrices/expressions/blockmatrix.pyr%   /   s
    
zBlockMatrix.__new__c             C   sr   d }}| j }x,t|jd D ]}|||df jd 7 }qW x,t|jd D ]}||d|f jd 7 }qLW ||fS )Nr      )blocksr	   shape)selfnumrowsnumcolsMir*   r*   r+   r.   7   s    zBlockMatrix.shapec             C   s   | j jS )N)r-   r.   )r/   r*   r*   r+   
blockshapeA   s    zBlockMatrix.blockshapec             C   s
   | j d S )Nr   )r'   )r/   r*   r*   r+   r-   E   s    zBlockMatrix.blocksc                s    fddt  jd D S )Nc                s   g | ]} j |d f jqS )r   )r-   rows).0r3   )r/   r*   r+   
<listcomp>K   s    z-BlockMatrix.rowblocksizes.<locals>.<listcomp>r   )r	   r4   )r/   r*   )r/   r+   rowblocksizesI   s    zBlockMatrix.rowblocksizesc                s    fddt  jd D S )Nc                s   g | ]} j d |f jqS )r   )r-   cols)r6   r3   )r/   r*   r+   r7   O   s    z-BlockMatrix.colblocksizes.<locals>.<listcomp>r,   )r	   r4   )r/   r*   )r/   r+   colblocksizesM   s    zBlockMatrix.colblocksizesc             C   s:   t |to8| j|jko8| j|jko8| j|jko8| j|jkS )N)
isinstancer!   r.   r4   r8   r:   )r/   otherr*   r*   r+   structurally_equalQ   s
    
zBlockMatrix.structurally_equalc             C   s.   t |tr&| j|jkr&t| j|j S | | S )N)r;   r!   r:   r8   r-   )r/   r<   r*   r*   r+   	_blockmulX   s    
zBlockMatrix._blockmulc             C   s,   t |tr$| |r$t| j|j S | | S )N)r;   r!   r=   r-   )r/   r<   r*   r*   r+   	_blockadd_   s    

zBlockMatrix._blockaddc             C   s8   dd | j D }t| jd | jd |}| }t|S )Nc             S   s   g | ]}t |qS r*   )r   )r6   matrixr*   r*   r+   r7   h   s    z/BlockMatrix._eval_transpose.<locals>.<listcomp>r   r,   )r-   r   r4   r   r!   )r/   matricesr2   r*   r*   r+   _eval_transposef   s    zBlockMatrix._eval_transposec                s8    j  jkr,t fddt jd D  S tdd S )Nc                s   g | ]}t  j||f qS r*   )r   r-   )r6   r3   )r/   r*   r+   r7   q   s   z+BlockMatrix._eval_trace.<locals>.<listcomp>r   z+Can't perform trace of irregular blockshape)r8   r:   r   r	   r4   NotImplementedError)r/   r*   )r/   r+   _eval_traceo   s
    zBlockMatrix._eval_tracec             C   s   | j dkrx| j \\}}\}}tt|rLt|t|||j |   S tt|rxt|t|||j |   S t| S )N)   rE   )	r4   r-   tolistr   r   Z
invertibler   Ir   )r/   ABCDr*   r*   r+   _eval_determinantv   s    
zBlockMatrix._eval_determinantc             C   sX   dd | j D }t| jd | jd |}dd | j D }t| jd | jd |}||fS )Nc             S   s   g | ]}t |qS r*   )r   )r6   r@   r*   r*   r+   r7      s    z,BlockMatrix.as_real_imag.<locals>.<listcomp>r   r,   c             S   s   g | ]}t |qS r*   )r    )r6   r@   r*   r*   r+   r7      s    )r-   r   r4   )r/   Zreal_matricesZim_matricesr*   r*   r+   as_real_imag   s
    zBlockMatrix.as_real_imagc             C   s   |   S )a	  Return transpose of matrix.

        Examples
        ========

        >>> from sympy import MatrixSymbol, BlockMatrix, ZeroMatrix
        >>> from sympy.abc import l, 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]])
        )rB   )r/   r*   r*   r+   r      s    zBlockMatrix.transposec             C   sv   x.t | jD ] \}}||k dkr$P q||8 }qW x.t | jD ] \}}||k dkrTP q<||8 }q<W | j||f ||f S )NF)	enumerater8   r:   r-   )r/   r3   jZ	row_blockr0   Z	col_blockr1   r*   r*   r+   _entry   s    zBlockMatrix._entryc             C   s   | j d | j d krdS xft| j d D ]T}xNt| j d D ]<}||kr\| j||f js\dS ||kr<| j||f js<dS q<W q(W dS )Nr   r,   FT)r4   r	   r-   is_IdentityZis_ZeroMatrix)r/   r3   rO   r*   r*   r+   rQ      s    zBlockMatrix.is_Identityc             C   s   | j | jkS )N)r8   r:   )r/   r*   r*   r+   is_structurally_symmetric   s    z%BlockMatrix.is_structurally_symmetricc                s6   | |krdS t |tr&| j|jkr&dS tt| |S )NT)r;   r!   r-   superequals)r/   r<   )	__class__r*   r+   rT      s
    zBlockMatrix.equals)__name__
__module____qualname____doc__r%   propertyr.   r4   r-   r8   r:   r=   r>   r?   rB   rD   rL   rM   r   rP   rQ   rR   rT   __classcell__r*   r*   )rU   r+   r!      s&   
	
	r!   c               @   sz   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dZdd Zdd ZdS )BlockDiagMatrixaL  
    A BlockDiagMatrix is a BlockMatrix with matrices only along the diagonal

    >>> from sympy import MatrixSymbol, BlockDiagMatrix, symbols, Identity
    >>> 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]])

    c             G   s   t jtf| S )N)r   r%   r\   )r&   matsr*   r*   r+   r%      s    zBlockDiagMatrix.__new__c             C   s   | j S )N)r'   )r/   r*   r*   r+   diag   s    zBlockDiagMatrix.diagc                s4   ddl m} | j  fddtt 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 r*   )r   r5   r9   )r6   rO   )r3   r]   r*   r+   r7      s   z5BlockDiagMatrix.blocks.<locals>.<listcomp>.<listcomp>)r	   len)r6   )r]   )r3   r+   r7      s   z*BlockDiagMatrix.blocks.<locals>.<listcomp>)r#   r"   r'   r	   r_   )r/   r"   datar*   )r]   r+   r-      s
    
zBlockDiagMatrix.blocksc             C   s(   t dd | jD t dd | jD fS )Nc             s   s   | ]}|j V  qd S )N)r5   )r6   blockr*   r*   r+   	<genexpr>   s    z(BlockDiagMatrix.shape.<locals>.<genexpr>c             s   s   | ]}|j V  qd S )N)r9   )r6   ra   r*   r*   r+   rb      s    )sumr'   )r/   r*   r*   r+   r.      s    zBlockDiagMatrix.shapec             C   s   t | j}||fS )N)r_   r'   )r/   nr*   r*   r+   r4      s    
zBlockDiagMatrix.blockshapec             C   s   dd | j D S )Nc             S   s   g | ]
}|j qS r*   )r5   )r6   ra   r*   r*   r+   r7      s    z1BlockDiagMatrix.rowblocksizes.<locals>.<listcomp>)r'   )r/   r*   r*   r+   r8      s    zBlockDiagMatrix.rowblocksizesc             C   s   dd | j D S )Nc             S   s   g | ]
}|j qS r*   )r9   )r6   ra   r*   r*   r+   r7      s    z1BlockDiagMatrix.colblocksizes.<locals>.<listcomp>)r'   )r/   r*   r*   r+   r:      s    zBlockDiagMatrix.colblocksizesignoredc             C   s   t dd | jD  S )Nc             S   s   g | ]}|  qS r*   )inverse)r6   r(   r*   r*   r+   r7      s    z1BlockDiagMatrix._eval_inverse.<locals>.<listcomp>)r\   r'   )r/   expandr*   r*   r+   _eval_inverse   s    zBlockDiagMatrix._eval_inversec             C   sB   t |tr2| j|jkr2tdd t| j|jD  S t| |S d S )Nc             S   s   g | ]\}}|| qS r*   r*   )r6   abr*   r*   r+   r7      s    z-BlockDiagMatrix._blockmul.<locals>.<listcomp>)r;   r\   r:   r8   zipr'   r!   r>   )r/   r<   r*   r*   r+   r>      s    
zBlockDiagMatrix._blockmulc             C   sZ   t |trJ| j|jkrJ| j|jkrJ| j|jkrJtdd t| j|jD  S t| |S d S )Nc             S   s   g | ]\}}|| qS r*   r*   )r6   ri   rj   r*   r*   r+   r7     s    z-BlockDiagMatrix._blockadd.<locals>.<listcomp>)	r;   r\   r4   r8   r:   rk   r'   r!   r?   )r/   r<   r*   r*   r+   r?      s    
zBlockDiagMatrix._blockaddN)re   )rV   rW   rX   rY   r%   rZ   r^   r-   r.   r4   r8   r:   rh   r>   r?   r*   r*   r*   r+   r\      s   	
r\   c             C   sr   dd }t tt t|tttttttt	t
tttttttti}|| }y| S  tk
rl   |S X dS )a=  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)
    Matrix([
    [X, Z],
    [0, Y]])

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

    >>> print(block_collapse(C*B))
    Matrix([[X, Z*Y + Z]])
    c             S   s   t | to| tS )N)r;   r   hasr!   )exprr*   r*   r+   <lambda>  s    z block_collapse.<locals>.<lambda>N)r   r   r   r
   r   r   	bc_mataddbc_block_plus_identr   	bc_matmulbc_distr   bc_transposer   
bc_inverser!   	bc_unpackdeblockdoitAttributeError)rm   ZhasbmZruleresultr*   r*   r+   block_collapse	  s    


rz   c             C   s   | j dkr| jd S | S )N)r,   r,   )r   r   )r4   r-   )rm   r*   r*   r+   ru   -  s    

ru   c             C   sh   t | jdd }|d }|s | S |d }|d }x|dd  D ]}||}q>W |r`t| | S |S d S )Nc             S   s
   t | tS )N)r;   r!   )r2   r*   r*   r+   rn   3  s    zbc_matadd.<locals>.<lambda>TFr   r,   )r   r'   r?   r   )rm   r'   r-   Z	nonblocksra   rj   r*   r*   r+   ro   2  s    ro   c                s   dd | j D }|s| S dd | j D   r~t fdd D r~ d jr~tdd  d jD  }t|t| f   S | S )Nc             S   s   g | ]}|j r|qS r*   )rQ   )r6   argr*   r*   r+   r7   B  s    z'bc_block_plus_ident.<locals>.<listcomp>c             S   s   g | ]}t |tr|qS r*   )r;   r!   )r6   r{   r*   r*   r+   r7   F  s    c             3   s   | ]}|  d  V  qdS )r   N)r=   )r6   rj   )r-   r*   r+   rb   G  s    z&bc_block_plus_ident.<locals>.<genexpr>r   c             S   s   g | ]}t |qS r*   )r   )r6   kr*   r*   r+   r7   I  s   )r'   allrR   r\   r8   r   r_   rw   )rm   ZidentsZblock_idr*   )r-   r+   rp   A  s    
rp   c                sN   |   \}dkrJtt|trJt|j t fddt jD S | S )z  Turn  a*[X, Y] into [a*X, a*Y] r,   c                s(   g | ]   fd dt jD qS )c                s   g | ]} |f  qS r*   r*   )r6   rO   )rI   factorr3   r*   r+   r7   T  s    z&bc_dist.<locals>.<listcomp>.<listcomp>)r	   r9   )r6   )rI   r~   )r3   r+   r7   T  s   zbc_dist.<locals>.<listcomp>)Zas_coeff_mmulr;   r   r!   r-   r	   r5   )rm   r(   r*   )rI   r~   r+   rr   O  s    
rr   c             C   s   |   \}}d}x|d t|k r|||d  \}}t|trht|trh||||< ||d  qt|tr|t|gg||< ||d  qt|trt|gg|||< ||d  q|d7 }qW t|f|  S )Nr   r,   rE   )Zas_coeff_matricesr_   r;   r!   r>   popr   rw   )rm   r~   rA   r3   rH   rI   r*   r*   r+   rq   Y  s    

rq   c             C   s   t t| jjtjS )N)r!   rz   r{   r-   	applyfuncr   T)rm   r*   r*   r+   rs   l  s    rs   c             C   s&   t | }| |kr|S ttt| jS )N)blockinverse_1x1blockinverse_2x2r   reblock_2x2r{   )rm   Zexpr2r*   r*   r+   rt   p  s    rt   c             C   s<   t | jtr8| jjdkr8t| jjd  gg}t|S | S )N)r,   r,   r   )r;   r{   r!   r4   r   r-   rf   )rm   r(   r*   r*   r+   r   v  s    r   c             C   s   t | jtr| jjdkr| jj \\}}\}}t|||j |  j| j| |||j |  j g|||j |  j | |j |||j |  jggS | S d S )N)rE   rE   )r;   r{   r!   r4   r-   rF   rG   )rm   rH   rI   rJ   rK   r*   r*   r+   r   |  s
    48r   c                s   t | tr| jts| S dd }| j| ddlm} y|dt fddt j	d D g }xbtd j	d D ]N}| |df j}x,td j	d D ]}|
 ||f j}qW ||}qvW t|S  tk
r   | S X dS )	z( Flatten a BlockMatrix of BlockMatrices c             S   s   t | tr| S t| ggS )N)r;   r!   )xr*   r*   r+   rn     s    zdeblock.<locals>.<lambda>r   )r   c             3   s"   | ]} d |f j jd V  qdS )r   r,   N)r-   r.   )r6   r3   )bbr*   r+   rb     s    zdeblock.<locals>.<genexpr>r,   N)r;   r!   r-   rl   r   sympyr   rc   r	   r.   Zrow_joinZcol_joinr   )rI   Zwrapr   ZMMrowr2   colr*   )r   r+   rv     s    (rv   c             C   s|   t | tr tdd | jjD s$| S t}|| jd || jdddf g|| jdddf || jddddf ggS )zC Reblock a BlockMatrix so that it has 2x2 blocks of block matrices c             s   s   | ]}|d kV  qdS )rE   Nr*   )r6   dr*   r*   r+   rb     s    zreblock_2x2.<locals>.<genexpr>)r   r   r   r,   N)r;   r!   r}   r-   r.   )rI   ZBMr*   r*   r+   r     s
      r   c             C   s4   d}g }x&| D ]}| ||| f ||7 }qW |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)ZsizesZlowrvsizer*   r*   r+   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 r*   )r   )r6   Zcolbound)rm   rowboundr*   r+   r7     s   z'blockcut.<locals>.<listcomp>.<listcomp>r*   )r6   )	colboundsrm   )r   r+   r7     s   zblockcut.<locals>.<listcomp>)r   r!   )rm   ZrowsizesZcolsizesZ	rowboundsr*   )r   rm   r+   blockcut  s    r   N)@Z
__future__r   r   r   r   r   Z
sympy.corer   r   r   Zsympy.core.compatibilityr	   Zsympy.strategiesr
   r   r   r   r   Zsympy.strategies.traverser   Zsympy.utilitiesr   Z"sympy.matrices.expressions.matexprr   r   r   Z!sympy.matrices.expressions.matmulr   Z!sympy.matrices.expressions.mataddr   Z$sympy.matrices.expressions.transposer   r   Z sympy.matrices.expressions.tracer   Z&sympy.matrices.expressions.determinantr   r   Z sympy.matrices.expressions.slicer   Z"sympy.matrices.expressions.inverser   Zsympy.matricesr   r   Z$sympy.functions.elementary.complexesr   r    r!   r\   rz   ru   ro   rp   rr   rq   rs   rt   r   r   rv   r   r   r   r*   r*   r*   r+   <module>   sB    1D$

