a
    a7j                     @   s$  d Z dZg dZddlZddlmZ ddl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 ddlmZ ddlmZ ddlmZ ddlmZ d,ddZd-ddZd.ddZddedfddZd/ddZ d0ddZ!dd Z"d1ddZ#d2d d!Z$d3d"d#Z%d4d$d%Z&d5d(d)Z'd6d*d+Z(dS )7z'Functions to construct sparse matrices
zrestructuredtext en)spdiagseyeidentitykronkronsumhstackvstackbmatrandrandomdiags
block_diag    N)partial)check_random_staterng_integers   )upcastget_index_dtypeisscalarlike)
csr_matrix)
csc_matrix)
bsr_matrix)
coo_matrix)
dia_matrix)issparsec                 C   s   t | |f||fd|S )a  
    Return a sparse matrix from diagonals.

    Parameters
    ----------
    data : array_like
        matrix diagonals stored row-wise
    diags : diagonals to set
        - k = 0  the main diagonal
        - k > 0  the k-th upper diagonal
        - k < 0  the k-th lower diagonal
    m, n : int
        shape of the result
    format : str, optional
        Format of the result. By default (format=None) an appropriate sparse
        matrix format is returned. This choice is subject to change.

    See Also
    --------
    diags : more convenient form of this function
    dia_matrix : the sparse DIAgonal format.

    Examples
    --------
    >>> from scipy.sparse import spdiags
    >>> data = np.array([[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]])
    >>> diags = np.array([0, -1, 2])
    >>> spdiags(data, diags, 4, 4).toarray()
    array([[1, 0, 3, 0],
           [1, 2, 0, 4],
           [0, 2, 3, 0],
           [0, 0, 3, 4]])

    shape)r   asformat)datar   mnformat r"   f/Users/vegardjervell/Documents/master/model/venv/lib/python3.9/site-packages/scipy/sparse/construct.pyr      s    #r   c                    s  t |r8t| dks t | d r.t| g} qHtdntttj| } t|}t| t|krjtd|du rt| d tt|d     f}|du rtj	|  }|\ t
 fdd|D }t
d|}tjt||f|d}t }t| D ]\}}	|| }
t
d|
}t |
 |
 |}|dk rBtd|
|f z$|	dd|f ||||| f< W q ty } zFt|	|krt|	d	krtd
|t|	|
 f | W Y d}~qd}~0 0 qt||f fd|S )a  
    Construct a sparse matrix from diagonals.

    Parameters
    ----------
    diagonals : sequence of array_like
        Sequence of arrays containing the matrix diagonals,
        corresponding to `offsets`.
    offsets : sequence of int or an int, optional
        Diagonals to set:
          - k = 0  the main diagonal (default)
          - k > 0  the kth upper diagonal
          - k < 0  the kth lower diagonal
    shape : tuple of int, optional
        Shape of the result. If omitted, a square matrix large enough
        to contain the diagonals is returned.
    format : {"dia", "csr", "csc", "lil", ...}, optional
        Matrix format of the result. By default (format=None) an
        appropriate sparse matrix format is returned. This choice is
        subject to change.
    dtype : dtype, optional
        Data type of the matrix.

    See Also
    --------
    spdiags : construct matrix from diagonals

    Notes
    -----
    This function differs from `spdiags` in the way it handles
    off-diagonals.

    The result from `diags` is the sparse equivalent of::

        np.diag(diagonals[0], offsets[0])
        + ...
        + np.diag(diagonals[k], offsets[k])

    Repeated diagonal offsets are disallowed.

    .. versionadded:: 0.11

    Examples
    --------
    >>> from scipy.sparse import diags
    >>> diagonals = [[1, 2, 3, 4], [1, 2, 3], [1, 2]]
    >>> diags(diagonals, [0, -1, 2]).toarray()
    array([[1, 0, 1, 0],
           [1, 2, 0, 2],
           [0, 2, 3, 0],
           [0, 0, 3, 4]])

    Broadcasting of scalars is supported (but shape needs to be
    specified):

    >>> diags([1, -2, 1], [-1, 0, 1], shape=(4, 4)).toarray()
    array([[-2.,  1.,  0.,  0.],
           [ 1., -2.,  1.,  0.],
           [ 0.,  1., -2.,  1.],
           [ 0.,  0.,  1., -2.]])


    If only one diagonal is wanted (as in `numpy.diag`), the following
    works as well:

    >>> diags([1, 2, 3], 1).toarray()
    array([[ 0.,  1.,  0.,  0.],
           [ 0.,  0.,  2.,  0.],
           [ 0.,  0.,  0.,  3.],
           [ 0.,  0.,  0.,  0.]])
    r   z*Different number of diagonals and offsets.Nc                    s(   g | ] }t  | | td | qS )r   )minmax).0offsetr   r    r"   r#   
<listcomp>   s   zdiags.<locals>.<listcomp>dtypez"Offset %d (index %d) out of bounds.r   zUDiagonal length (index %d: %d at offset %d) does not agree with matrix size (%d, %d).r   )r   lennpZ
atleast_1d
ValueErrorlistmapabsintZcommon_typer%   zerosr$   	enumerater   r   )Z	diagonalsoffsetsr   r!   r+   MZdata_arrKjZdiagonalr'   klengther"   r(   r#   r   ?   sP    I






$r   dc                 C   s   t | | ||dS )a  Identity matrix in sparse format

    Returns an identity matrix with shape (n,n) using a given
    sparse format and dtype.

    Parameters
    ----------
    n : int
        Shape of the identity matrix.
    dtype : dtype, optional
        Data type of the matrix
    format : str, optional
        Sparse format of the result, e.g., format="csr", etc.

    Examples
    --------
    >>> from scipy.sparse import identity
    >>> identity(3).toarray()
    array([[ 1.,  0.,  0.],
           [ 0.,  1.,  0.],
           [ 0.,  0.,  1.]])
    >>> identity(3, dtype='int8', format='dia')
    <3x3 sparse matrix of type '<class 'numpy.int8'>'
            with 3 stored elements (1 diagonals) in DIAgonal format>

    )r+   r!   )r   )r    r+   r!   r"   r"   r#   r      s    r   c                 C   s  |du r| }t | t | } }| |kr|dkr|dv rt|d}tj|d |d}tj||d}tj||d}ttd| }	|	|||f||fS |dkrt|d}tj||d}
tj||d}tj||d}t||
|ff||fS tjdtdt	| | |f|d}t
||| ||S )a[  Sparse matrix with ones on diagonal

    Returns a sparse (m x n) matrix where the kth diagonal
    is all ones and everything else is zeros.

    Parameters
    ----------
    m : int
        Number of rows in the matrix.
    n : int, optional
        Number of columns. Default: `m`.
    k : int, optional
        Diagonal to place ones on. Default: 0 (main diagonal).
    dtype : dtype, optional
        Data type of the matrix.
    format : str, optional
        Sparse format of the result, e.g., format="csr", etc.

    Examples
    --------
    >>> from scipy import sparse
    >>> sparse.eye(3).toarray()
    array([[ 1.,  0.,  0.],
           [ 0.,  1.,  0.],
           [ 0.,  0.,  1.]])
    >>> sparse.eye(3, dtype=np.int8)
    <3x3 sparse matrix of type '<class 'numpy.int8'>'
        with 3 stored elements (1 diagonals) in DIAgonal format>

    Nr   )csrcscmaxvalr   r*   coo)r2   r   r-   arangeZonesr   r   r   r%   r$   r   r   )r   r    r9   r+   r!   	idx_dtypeindptrindicesr   clsrowcolr   r"   r"   r#   r      s&    

"r   c                 C   sF  t |}|du s|dkrd|j |jd |jd  krt| dd} | jd |jd  | jd |jd  f}| jdks~|jdkrt ||S | }| j|j	d|jd |jd }|| }t
|| j| jf|d	S t | } | jd |jd  | jd |jd  f}| jdks|jdkr,t ||S | j|j}| j|j}| j|j}t| jd |jd  | jd |jd  td
jkr|tj}|tj}||jd 9 }||jd 9 }|	d|j|	d|j }}||j7 }||j7 }|	d|	d }}|	d|j|j }|	d}t |||ff|d	|S dS )aY  kronecker product of sparse matrices A and B

    Parameters
    ----------
    A : sparse or dense matrix
        first matrix of the product
    B : sparse or dense matrix
        second matrix of the product
    format : str, optional
        format of the result (e.g. "csr")

    Returns
    -------
    kronecker product in a sparse matrix format


    Examples
    --------
    >>> from scipy import sparse
    >>> A = sparse.csr_matrix(np.array([[0, 2], [5, 0]]))
    >>> B = sparse.csr_matrix(np.array([[1, 2], [3, 4]]))
    >>> sparse.kron(A, B).toarray()
    array([[ 0,  0,  2,  4],
           [ 0,  0,  6,  8],
           [ 5, 10,  0,  0],
           [15, 20,  0,  0]])

    >>> sparse.kron(A, [[1, 2], [3, 4]]).toarray()
    array([[ 0,  0,  2,  4],
           [ 0,  0,  6,  8],
           [ 5, 10,  0,  0],
           [15, 20,  0,  0]])

    Nbsr   r   r   Tcopyr   Zint32)r   nnzr   r   r   Ztoarrayr   repeatsizeZreshaper   rE   rD   rG   rH   r%   r-   iinfoastypeint64)ABr!   Zoutput_shaper   rG   rH   r"   r"   r#   r     s:    #.($(8


r   c                 C   s   t | } t |}| jd | jd kr,td|jd |jd krHtdt| j|j}tt|jd |d| |d}t|t| jd |d|d}|| |S )a  kronecker sum of sparse matrices A and B

    Kronecker sum of two sparse matrices is a sum of two Kronecker
    products kron(I_n,A) + kron(B,I_m) where A has shape (m,m)
    and B has shape (n,n) and I_m and I_n are identity matrices
    of shape (m,m) and (n,n), respectively.

    Parameters
    ----------
    A
        square matrix
    B
        square matrix
    format : str
        format of the result (e.g. "csr")

    Returns
    -------
    kronecker sum in a sparse matrix format

    Examples
    --------


    r   r   zA is not squarezB is not squarer*   )r!   )r   r   r.   r   r+   r   r   r   )rT   rU   r!   r+   LRr"   r"   r#   r   h  s    r   c                    sn   dkrdnd}t dd | D }| d j| }tdd | D t|j|d}t j|j|d}t jt fdd	| D d |d}|d}d}	d}
| D ]}|j| |krtd
| |j	||
|
|j	j < |
|j	j7 }
t
|	|	|j   }|jdd ||< ||  |7  < |	|j  7 }	||jd 7 }q||d<  dkrTt|||f|	|fdS t|||f||	fdS dS )z^
    Stacking fast path for CSR/CSC matrices
    (i) vstack for CSR, (ii) hstack for CSC.
    r   r   c                 S   s   g | ]
}|j qS r"   )r   r&   br"   r"   r#   r)         z,_compressed_sparse_stack.<locals>.<listcomp>c                 S   s   g | ]
}|j qS r"   )rD   rX   r"   r"   r#   r)     rZ   )Zarraysr@   r*   c                 3   s   | ]}|j   V  qd S Nr   rX   axisr"   r#   	<genexpr>  rZ   z+_compressed_sparse_stack.<locals>.<genexpr>z#incompatible dimensions for axis %dNrM   r   )r-   concatenater   r   r%   rP   emptysumr.   rE   slicerD   r   r   )blocksr]   Z
other_axisr   Zconstant_dimrC   rE   rD   Zlast_indptrZsum_dimZsum_indicesrY   Zidxsr"   r\   r#   _compressed_sparse_stack  s:    
$


rd   c                 C   s   t | g||dS )a  
    Stack sparse matrices horizontally (column wise)

    Parameters
    ----------
    blocks
        sequence of sparse matrices with compatible shapes
    format : str
        sparse format of the result (e.g., "csr")
        by default an appropriate sparse matrix format is returned.
        This choice is subject to change.
    dtype : dtype, optional
        The data-type of the output matrix. If not given, the dtype is
        determined from that of `blocks`.

    See Also
    --------
    vstack : stack sparse matrices vertically (row wise)

    Examples
    --------
    >>> from scipy.sparse import coo_matrix, hstack
    >>> A = coo_matrix([[1, 2], [3, 4]])
    >>> B = coo_matrix([[5], [6]])
    >>> hstack([A,B]).toarray()
    array([[1, 2, 5],
           [3, 4, 6]])

    r!   r+   r   rc   r!   r+   r"   r"   r#   r     s    r   c                 C   s   t dd | D ||dS )a0  
    Stack sparse matrices vertically (row wise)

    Parameters
    ----------
    blocks
        sequence of sparse matrices with compatible shapes
    format : str, optional
        sparse format of the result (e.g., "csr")
        by default an appropriate sparse matrix format is returned.
        This choice is subject to change.
    dtype : dtype, optional
        The data-type of the output matrix. If not given, the dtype is
        determined from that of `blocks`.

    See Also
    --------
    hstack : stack sparse matrices horizontally (column wise)

    Examples
    --------
    >>> from scipy.sparse import coo_matrix, vstack
    >>> A = coo_matrix([[1, 2], [3, 4]])
    >>> B = coo_matrix([[5, 6]])
    >>> vstack([A, B]).toarray()
    array([[1, 2],
           [3, 4],
           [5, 6]])

    c                 S   s   g | ]
}|gqS r"   r"   rX   r"   r"   r#   r)     rZ   zvstack.<locals>.<listcomp>re   rf   rg   r"   r"   r#   r     s    r   c                 C   sF  t j| dd} | jdkr td| j\}}|dkrz|dv rztdd | jD rzt| d	d	d
f d
}|d	urv||}|S |dkr|dv rtdd | jD rt| d
d	d	f d}|d	ur||}|S t j	| jt
d}t j	|t jd}t j	|t jd}t|D ]}	t|D ]}
| |	|
f d	urt| |	|
f }|| |	|
f< d||	|
f< ||	 d
krj|jd
 ||	< n8||	 |jd
 krdj|	|
||	 |jd
 d}t|||
 d
kr|jd ||
< n8||
 |jd krdj|	|
||
 |jd d}t|qqtdd | | D }|d	u rDdd | | D }|r@t| nd	}t d
t |}t d
t |}|d |d f}t j||d}tt|d}t j||d}t j||d}d
}t |\}}t||D ]^\}	}
| |	|
f }t|||j }|j||< |j||	  ||< |j||
  ||< ||j7 }qt|||ff|d|S )aQ  
    Build a sparse matrix from sparse sub-blocks

    Parameters
    ----------
    blocks : array_like
        Grid of sparse matrices with compatible shapes.
        An entry of None implies an all-zero matrix.
    format : {'bsr', 'coo', 'csc', 'csr', 'dia', 'dok', 'lil'}, optional
        The sparse format of the result (e.g. "csr"). By default an
        appropriate sparse matrix format is returned.
        This choice is subject to change.
    dtype : dtype, optional
        The data-type of the output matrix. If not given, the dtype is
        determined from that of `blocks`.

    Returns
    -------
    bmat : sparse matrix

    See Also
    --------
    block_diag, diags

    Examples
    --------
    >>> from scipy.sparse import coo_matrix, bmat
    >>> A = coo_matrix([[1, 2], [3, 4]])
    >>> B = coo_matrix([[5], [6]])
    >>> C = coo_matrix([[7]])
    >>> bmat([[A, B], [None, C]]).toarray()
    array([[1, 2, 5],
           [3, 4, 6],
           [0, 0, 7]])

    >>> bmat([[A, None], [None, C]]).toarray()
    array([[1, 2, 0],
           [3, 4, 0],
           [0, 0, 7]])

    objectr*   rJ   zblocks must be 2-Dr   )Nr=   c                 s   s   | ]}t |tV  qd S r[   )
isinstancer   rX   r"   r"   r#   r^   +  s   zbmat.<locals>.<genexpr>Nr   )Nr>   c                 s   s   | ]}t |tV  qd S r[   )ri   r   rX   r"   r"   r#   r^   2  rZ   Tzeblocks[{i},:] has incompatible row dimensions. Got blocks[{i},{j}].shape[0] == {got}, expected {exp}.)ir8   expgotzeblocks[:,{j}] has incompatible row dimensions. Got blocks[{i},{j}].shape[1] == {got}, expected {exp}.c                 s   s   | ]}|j V  qd S r[   )rN   )r&   blockr"   r"   r#   r^   X  rZ   c                 S   s   g | ]
}|j qS r"   r*   )r&   Zblkr"   r"   r#   r)   Z  rZ   zbmat.<locals>.<listcomp>rM   r?   r   )r-   Zasarrayndimr.   r   allZflatrd   rR   r3   boolrS   ranger   r!   ra   r   appendZcumsumr`   r   r%   Znonzeroziprb   rN   r   rG   rH   r   )rc   r!   r+   r6   NrT   Z
block_maskZbrow_lengthsZbcol_lengthsrj   r8   msgrN   Z
all_dtypesZrow_offsetsZcol_offsetsr   r   rC   rG   rH   iiZjjrU   idxr"   r"   r#   r     s    +





r   c                 C   s  g }g }g }d}d}| D ]}t |ttjfr4t|}|j\}	}
t|r|| }||j	|  ||j
|  ||j nDtt|	|
 |
\}}|||  |||  ||  ||	7 }||
7 }qt|}t|}t|}t|||ff||f|d|S )a  
    Build a block diagonal sparse matrix from provided matrices.

    Parameters
    ----------
    mats : sequence of matrices
        Input matrices.
    format : str, optional
        The sparse format of the result (e.g., "csr"). If not given, the matrix
        is returned in "coo" format.
    dtype : dtype specifier, optional
        The data-type of the output matrix. If not given, the dtype is
        determined from that of `blocks`.

    Returns
    -------
    res : sparse matrix

    Notes
    -----

    .. versionadded:: 0.11.0

    See Also
    --------
    bmat, diags

    Examples
    --------
    >>> from scipy.sparse import coo_matrix, block_diag
    >>> A = coo_matrix([[1, 2], [3, 4]])
    >>> B = coo_matrix([[5], [6]])
    >>> C = coo_matrix([[7]])
    >>> block_diag((A, B, C)).toarray()
    array([[1, 2, 0, 0],
           [3, 4, 0, 0],
           [0, 0, 5, 0],
           [0, 0, 6, 0],
           [0, 0, 0, 7]])

    r   )r   r+   )ri   r/   numbersNumberr   r   r   Ztocoorr   rG   rH   r   r-   divmodrB   Zravelr_   r   )Zmatsr!   r+   rG   rH   r   Zr_idxZc_idxaZnrowsZncolsZa_rowZa_colr"   r"   r#   r   t  s:    *




r   {Gz?rA   c                    sP  |dk s|dkrt dt  | | }tj}|t|jkrFtj}|t|jkrnd}	t |	t|j tt||  | }
t	|du rt
 tjr fdd}n*t
 tjṙfdd}ntjd	d
}j||
dd}t|d
 |  j|dd}|||   j|dd}||
j dd}t|||ff| |fdj|ddS )a
  Generate a sparse matrix of the given shape and density with randomly
    distributed values.

    Parameters
    ----------
    m, n : int
        shape of the matrix
    density : real, optional
        density of the generated matrix: density equal to one means a full
        matrix, density of 0 means a matrix with no non-zero items.
    format : str, optional
        sparse matrix format.
    dtype : dtype, optional
        type of the returned matrix values.
    random_state : {None, int, `numpy.random.Generator`,
                    `numpy.random.RandomState`}, optional

        If `seed` is None (or `np.random`), the `numpy.random.RandomState`
        singleton is used.
        If `seed` is an int, a new ``RandomState`` instance is used,
        seeded with `seed`.
        If `seed` is already a ``Generator`` or ``RandomState`` instance then
        that instance is used.
        This random state will be used
        for sampling the sparsity structure, but not necessarily for sampling
        the values of the structurally nonzero entries of the matrix.
    data_rvs : callable, optional
        Samples a requested number of random values.
        This function should take a single argument specifying the length
        of the ndarray that it will return. The structurally nonzero entries
        of the sparse random matrix will be taken from the array sampled
        by this function. By default, uniform [0, 1) random values will be
        sampled using the same random state as is used for sampling
        the sparsity structure.

    Returns
    -------
    res : sparse matrix

    Notes
    -----
    Only float types are supported for now.

    Examples
    --------
    >>> from scipy.sparse import random
    >>> from scipy import stats
    >>> from numpy.random import default_rng
    >>> rng = default_rng()
    >>> rvs = stats.poisson(25, loc=10).rvs
    >>> S = random(3, 4, density=0.25, random_state=rng, data_rvs=rvs)
    >>> S.A
    array([[ 36.,   0.,  33.,   0.],   # random
           [  0.,   0.,   0.,   0.],
           [  0.,   0.,  36.,   0.]])

    >>> from scipy.sparse import random
    >>> from scipy.stats import rv_continuous
    >>> class CustomDistribution(rv_continuous):
    ...     def _rvs(self,  size=None, random_state=None):
    ...         return random_state.standard_normal(size)
    >>> X = CustomDistribution(seed=rng)
    >>> Y = X()  # get a frozen version of the distribution
    >>> S = random(3, 4, density=0.25, random_state=rng, data_rvs=Y.rvs)
    >>> S.A
    array([[ 0.        ,  0.        ,  0.        ,  0.        ],   # random
           [ 0.13569738,  1.9467163 , -0.81205367,  0.        ],
           [ 0.        ,  0.        ,  0.        ,  0.        ]])

    r   r   z(density expected to be 0 <= density <= 1zTrying to generate a random sparse matrix such as the product of dimensions is
greater than %d - this is not supported on this machine
Nc                    s"   t t jt j|  dS )Nr*   )r   r-   rQ   r$   r%   r    r+   random_stater"   r#   data_rvs  s    

zrandom.<locals>.data_rvsc                    s    j | d j | dd  S )N)rP   y              ?)uniformr}   )r   r"   r#   r   "  s    
g        g      ?F)rP   replacerK   r   )r.   r-   r+   ZintcrQ   r%   rS   r2   roundr   Z
issubdtypeintegerZcomplexfloatingr   r   choicefloorrR   r   r   )r   r    densityr!   r+   r   r   mntpru   r9   indr8   rj   valsr"   r~   r#   r
     s2    H
r
   c                 C   s   t | |||||S )aY  Generate a sparse matrix of the given shape and density with uniformly
    distributed values.

    Parameters
    ----------
    m, n : int
        shape of the matrix
    density : real, optional
        density of the generated matrix: density equal to one means a full
        matrix, density of 0 means a matrix with no non-zero items.
    format : str, optional
        sparse matrix format.
    dtype : dtype, optional
        type of the returned matrix values.
    random_state : {None, int, `numpy.random.Generator`,
                    `numpy.random.RandomState`}, optional

        If `seed` is None (or `np.random`), the `numpy.random.RandomState`
        singleton is used.
        If `seed` is an int, a new ``RandomState`` instance is used,
        seeded with `seed`.
        If `seed` is already a ``Generator`` or ``RandomState`` instance then
        that instance is used.

    Returns
    -------
    res : sparse matrix

    Notes
    -----
    Only float types are supported for now.

    See Also
    --------
    scipy.sparse.random : Similar function that allows a user-specified random
        data source.

    Examples
    --------
    >>> from scipy.sparse import rand
    >>> matrix = rand(3, 4, density=0.25, format="csr", random_state=42)
    >>> matrix
    <3x4 sparse matrix of type '<class 'numpy.float64'>'
       with 3 stored elements in Compressed Sparse Row format>
    >>> matrix.todense()
    matrix([[0.05641158, 0.        , 0.        , 0.65088847],
            [0.        , 0.        , 0.        , 0.14286682],
            [0.        , 0.        , 0.        , 0.        ]])

    )r
   )r   r    r   r!   r+   r   r"   r"   r#   r	   1  s    3r	   )N)r   NNN)r<   N)N)N)NN)NN)NN)NN)r|   rA   NNN)r|   rA   NN))__doc__Z__docformat____all__rx   	functoolsr   Znumpyr-   Zscipy._lib._utilr   r   Zsputilsr   r   r   r=   r   r>   r   rI   r   rA   r   Zdiar   baser   r   r   r   floatr   r   r   rd   r   r   r   r   r
   r	   r"   r"   r"   r#   <module>   s8   
&
~
7
V
+"
!
"
|
G  
v