B
    ddY9                 @   s   d dl mZ d dlmZ d dlmZ d dl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mZmZ ddlmZmZ G dd deZG dd deeZeZdS )    )Callable)Dict)sympy_deprecation_warning)is_sequence)as_int   )
MatrixBase)MutableRepMatrix	RepMatrix)_iszero)_liupc _row_structure_symbolic_cholesky_cholesky_sparse_LDLdecomposition_sparse)_lower_triangular_solve_sparse_upper_triangular_solve_sparsec                   s  e Zd ZdZe f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dZd+ddZeedddZeedddZdd Zdd  Zd,d"d#Zd-d$d%Zd&d' Zd(d) Zeje_eje_eje_eje_eje_eje_  ZS ).SparseRepMatrixa  
    A sparse matrix (a matrix with a large number of zero elements).

    Examples
    ========

    >>> from sympy import SparseMatrix, ones
    >>> SparseMatrix(2, 2, range(4))
    Matrix([
    [0, 1],
    [2, 3]])
    >>> SparseMatrix(2, 2, {(1, 1): 2})
    Matrix([
    [0, 0],
    [0, 2]])

    A SparseMatrix can be instantiated from a ragged list of lists:

    >>> SparseMatrix([[1, 2, 3], [1, 2], [1]])
    Matrix([
    [1, 2, 3],
    [1, 2, 0],
    [1, 0, 0]])

    For safety, one may include the expected size and then an error
    will be raised if the indices of any element are out of range or
    (for a flat list) if the total number of elements does not match
    the expected shape:

    >>> SparseMatrix(2, 2, [1, 2])
    Traceback (most recent call last):
    ...
    ValueError: List length (2) != rows*columns (4)

    Here, an error is not raised because the list is not flat and no
    element is out of range:

    >>> SparseMatrix(2, 2, [[1, 2]])
    Matrix([
    [1, 2],
    [0, 0]])

    But adding another element to the first (and only) row will cause
    an error to be raised:

    >>> SparseMatrix(2, 2, [[1, 2, 3]])
    Traceback (most recent call last):
    ...
    ValueError: The location (0, 2) is out of designated range: (1, 1)

    To autosize the matrix, pass None for rows:

    >>> SparseMatrix(None, [[1, 2, 3]])
    Matrix([[1, 2, 3]])
    >>> SparseMatrix(None, {(1, 1): 1, (3, 3): 3})
    Matrix([
    [0, 0, 0, 0],
    [0, 1, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 3]])

    Values that are themselves a Matrix are automatically expanded:

    >>> SparseMatrix(4, 4, {(1, 1): ones(2)})
    Matrix([
    [0, 0, 0, 0],
    [0, 1, 1, 0],
    [0, 1, 1, 0],
    [0, 0, 0, 0]])

    A ValueError is raised if the expanding matrix tries to overwrite
    a different element already present:

    >>> SparseMatrix(3, 3, {(0, 0): ones(2), (1, 1): 2})
    Traceback (most recent call last):
    ...
    ValueError: collision at (1, 1)

    See Also
    ========
    DenseMatrix
    MutableSparseMatrix
    ImmutableSparseMatrix
    c          
      s@  t |dkrDt|d trD|d j}|d j}|d  ||fS i t |dkrn|d d krnd d |d g}t |dkr|d d \}}||  krd krn n
d  }}n0d ||fkrtdnt|d t|d  }}t|d tr|d }d ||fkrtd	|| fddt
|D } fd	dt
|D }	xF|D ]>}
x6|	D ].} ||
|}| jkrP||
|f< qPW qFW ||fS t|d ttfrfd
d}x|d  D ]\\}}}t|trx|  D ]"\\}
}}|||
 || | qW nrt|ttfrd j|f|\}}xLD ]&\}
}|||
 || |
|f  q8W n |}||| | qW nt|d rXtdd |d D  }|sΈ j|d f|\}}n|d }t ||| krtd	t |||xXt
|D ]L}
xDt
|D ]8}||
| |  } |}| jkr||
|f< qW qW |d kr }|rtdd |D d nd}|rtdd |D d nd}nZxX D ]L\}
}|
r|
|ks|r||krtd	|
|fd|d d|d qW ||fS t |dkrt|d ttfr|d }d}xpt|D ]d\}
}t|ttfsf|g}x4t|D ](\}}| jkrp ||
|f< qpW t|t |}qHW |rt |nd}|}||fS t j| \}}}xNt
|D ]B}
x:t
|D ].}|||
 |  }| jkr||
|f< qW qW ||fS d S )Nr   r         z*Pass rows=None and no cols for autosizing.z2{} and {} must be integers for this specification.c                s   g | ]}  |qS  )_sympify).0i)clsr   b/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/sympy/matrices/sparse.py
<listcomp>   s    z;SparseRepMatrix._handle_creation_inputs.<locals>.<listcomp>c                s   g | ]}  |qS r   )r   )r   j)r   r   r   r      s    c                sN   |rJ| |f kr>| | |f kr>t d| |f| | |f | | |f< d S )Nz)There is a collision at {} for {} and {}.)
ValueErrorformat)r   r   v)smatr   r   update   s    z7SparseRepMatrix._handle_creation_inputs.<locals>.updatec             s   s   | ]}t |V  qd S )N)r   )r   r   r   r   r   	<genexpr>   s    z:SparseRepMatrix._handle_creation_inputs.<locals>.<genexpr>zMThe length of the flat list ({}) does not match the specified size ({} * {}).c             S   s   g | ]\}}|qS r   r   )r   r_r   r   r   r      s    c             S   s   g | ]\}}|qS r   r   )r   r$   cr   r   r   r      s    z?The location {} is out of the designated range[{}, {}]x[{}, {}])len
isinstancer   rowscolstodokr   r   r   r   ranger   zerodictr   itemslisttuple_handle_creation_inputsr   anykeysmax	enumeratesuper)r   argskwargsr(   r)   r#   r%   opZrow_indicesZcol_indicesr   r   valuer!   r   vvr$   ZflatZ	flat_listr3   rowmat)	__class__)r   r    r   r1   k   s    







$


 " "
"
z'SparseRepMatrix._handle_creation_inputsc             C   s   t dddd |  S )Nz
            The private _smat attribute of SparseMatrix is deprecated. Use the
            .todok() method instead.
            z1.9z$deprecated-private-matrix-attributes)Zdeprecated_since_versionZactive_deprecations_target)r   r*   )selfr   r   r   _smat   s
    zSparseRepMatrix._smatc             K   s(   | j |dd|dt|dddS )NmethodLDL
iszerofunctry_block_diagF)rA   rC   rD   )invgetr   )r?   r8   r   r   r   _eval_inverse   s    
zSparseRepMatrix._eval_inversec             C   sX   t |stdi }x0|   D ] \}}||}|dkr"|||< q"W | | j| j|S )aX  Apply a function to each element of the matrix.

        Examples
        ========

        >>> from sympy import SparseMatrix
        >>> m = SparseMatrix(2, 2, lambda i, j: i*2+j)
        >>> m
        Matrix([
        [0, 1],
        [2, 3]])
        >>> m.applyfunc(lambda i: 2*i)
        Matrix([
        [0, 2],
        [4, 6]])

        z`f` must be callable.r   )callable	TypeErrorr*   r.   _newr(   r)   )r?   fZdokkr   Zfvr   r   r   	applyfunc   s    zSparseRepMatrix.applyfuncc             C   s   ddl m} || S )z,Returns an Immutable version of this Matrix.r   )ImmutableSparseMatrix)Z	immutablerN   )r?   rN   r   r   r   as_immutable  s    zSparseRepMatrix.as_immutablec             C   s   t | S )aC  Returns a mutable version of this matrix.

        Examples
        ========

        >>> from sympy import ImmutableMatrix
        >>> X = ImmutableMatrix([[1, 2], [3, 4]])
        >>> Y = X.as_mutable()
        >>> Y[1, 1] = 5 # Can set values in Y
        >>> Y
        Matrix([
        [1, 2],
        [3, 5]])
        )MutableSparseMatrix)r?   r   r   r   
as_mutable$  s    zSparseRepMatrix.as_mutablec                s*    fddt t   dd dD S )a  Returns a column-sorted list of non-zero elements of the matrix.

        Examples
        ========

        >>> from sympy import SparseMatrix
        >>> a=SparseMatrix(((1, 2), (3, 4)))
        >>> a
        Matrix([
        [1, 2],
        [3, 4]])
        >>> a.CL
        [(0, 0, 1), (1, 0, 3), (0, 1, 2), (1, 1, 4)]

        See Also
        ========

        sympy.matrices.sparse.SparseMatrix.row_list
        c                s   g | ]}t | | f qS r   )r0   )r   rL   )r?   r   r   r   I  s    z,SparseRepMatrix.col_list.<locals>.<listcomp>c             S   s   t t| S )N)r/   reversed)rL   r   r   r   <lambda>I      z*SparseRepMatrix.col_list.<locals>.<lambda>)key)sortedr/   r*   r3   )r?   r   )r?   r   col_list5  s    zSparseRepMatrix.col_listc             C   s   t |  S )z2Returns the number of non-zero elements in Matrix.)r&   r*   )r?   r   r   r   nnzK  s    zSparseRepMatrix.nnzc                s"    fddt    tdD S )a  Returns a row-sorted list of non-zero elements of the matrix.

        Examples
        ========

        >>> from sympy import SparseMatrix
        >>> a = SparseMatrix(((1, 2), (3, 4)))
        >>> a
        Matrix([
        [1, 2],
        [3, 4]])
        >>> a.RL
        [(0, 0, 1), (0, 1, 2), (1, 0, 3), (1, 1, 4)]

        See Also
        ========

        sympy.matrices.sparse.SparseMatrix.col_list
        c                s   g | ]}t | | f qS r   )r0   )r   rL   )r?   r   r   r   c  s    z,SparseRepMatrix.row_list.<locals>.<listcomp>)rU   )rV   r*   r3   r/   )r?   r   )r?   r   row_listO  s    
zSparseRepMatrix.row_listc             C   s   ||  S )z"Scalar element-wise multiplicationr   )r?   Zscalarr   r   r   scalar_multiplyf  s    zSparseRepMatrix.scalar_multiplyrB   c             C   s   | j }||  j|d| | S )a  Return the least-square fit to the data.

        By default the cholesky_solve routine is used (method='CH'); other
        methods of matrix inversion can be used. To find out which are
        available, see the docstring of the .inv() method.

        Examples
        ========

        >>> from sympy import SparseMatrix, Matrix, ones
        >>> A = Matrix([1, 2, 3])
        >>> B = Matrix([2, 3, 4])
        >>> S = SparseMatrix(A.row_join(B))
        >>> S
        Matrix([
        [1, 2],
        [2, 3],
        [3, 4]])

        If each line of S represent coefficients of Ax + By
        and x and y are [2, 3] then S*xy is:

        >>> r = S*Matrix([2, 3]); r
        Matrix([
        [ 8],
        [13],
        [18]])

        But let's add 1 to the middle value and then solve for the
        least-squares value of xy:

        >>> xy = S.solve_least_squares(Matrix([8, 14, 18])); xy
        Matrix([
        [ 5/3],
        [10/3]])

        The error is given by S*xy - r:

        >>> S*xy - r
        Matrix([
        [1/3],
        [1/3],
        [1/3]])
        >>> _.norm().n(2)
        0.58

        If a different xy is used, the norm will be higher:

        >>> xy += ones(2, 1)/10
        >>> (S*xy - r).norm().n(2)
        1.5

        )rA   )TrE   )r?   rhsrA   tr   r   r   solve_least_squaresj  s    6z#SparseRepMatrix.solve_least_squaresc             C   sH   | j s2| j| jk rtdqD| j| jkrDtdn| j|d|S dS )zReturn solution to self*soln = rhs using given inversion method.

        For a list of possible inversion methods, see the .inv() docstring.
        zUnder-determined system.z]For over-determined system, M, having more rows than columns, try M.solve_least_squares(rhs).)rA   N)Z	is_squarer(   r)   r   rE   multiply)r?   r\   rA   r   r   r   solve  s    

zSparseRepMatrix.solveNzAlternate faster representationc             C   s   t | S )N)r   )r?   r   r   r   liupc  s    zSparseRepMatrix.liupcc             C   s   t | S )N)r   )r?   r   r   r   row_structure_symbolic_cholesky  s    z/SparseRepMatrix.row_structure_symbolic_choleskyTc             C   s   t | |dS )N)	hermitian)r   )r?   rc   r   r   r   cholesky  s    zSparseRepMatrix.choleskyc             C   s   t | |dS )N)rc   )r   )r?   rc   r   r   r   LDLdecomposition  s    z SparseRepMatrix.LDLdecompositionc             C   s
   t | |S )N)r   )r?   r\   r   r   r   lower_triangular_solve  s    z&SparseRepMatrix.lower_triangular_solvec             C   s
   t | |S )N)r   )r?   r\   r   r   r   upper_triangular_solve  s    z&SparseRepMatrix.upper_triangular_solve)rB   )rB   )T)T)__name__
__module____qualname____doc__classmethodr1   propertyr@   rG   rM   rO   rQ   rW   rX   rY   rZ   r^   r`   ZRLZCLra   rb   rd   re   rf   rg   r   r   r   r   __classcell__r   r   )r>   r   r      s8   T  
9


r   c               @   s   e Zd Zedd ZdS )rP   c             O   s*   | j ||\}}}| |||}| |S )N)r1   Z_smat_to_DomainMatrixZ_fromrep)r   r7   r8   r(   r)   r    repr   r   r   rJ     s    zMutableSparseMatrix._newN)rh   ri   rj   rl   rJ   r   r   r   r   rP     s   rP   N)collections.abcr   Zsympy.core.containersr   Zsympy.utilities.exceptionsr   Zsympy.utilities.iterablesr   Zsympy.utilities.miscr   Zmatricesr   Z	repmatrixr	   r
   Z	utilitiesr   Zdecompositionsr   r   r   r   Zsolversr   r   r   rP   ZSparseMatrixr   r   r   r   <module>   s      <