o
    "j2U                     @   s   d Z ddlZddlZddlZddlmZ ddlmZ ddlZ	g Z
G dd deZG dd deZd	d
 Zdd Zdd Zdd Zdd Zdd Zdd Ze ai add Zdd ZejddfddZejddfdd ZdS )!z#
Utilities of Auto SParsity (ASP).
    N)Enum)permutationsc                   @   s   e Zd ZdZdZdZdZdS )MaskAlgoz
    A collection of all mask generating algorithms.
    There currently are three algorithms, `MASK_1D`, `MASK_2D_GREEDY` and `MASK_2D_BEST`
    get_mask_1dget_mask_2d_greedyget_mask_2d_bestN)__name__
__module____qualname____doc__MASK_1DZMASK_2D_GREEDYZMASK_2D_BEST r   r   Z/var/www/html/Deteccion_Ine/venv/lib/python3.10/site-packages/paddle/incubate/asp/utils.pyr      s
    r   c                   @   s$   e Zd ZdZdZdZedd ZdS )CheckMethodzz
    A collection of all sparsity checking approaches.
    There currently are two methods, `CHECK_1D` and `CHECK_2D`
    check_mask_1dcheck_mask_2dc                 C   s(   t | ts	J d| tjkrtjS tjS )a  
        Get sparsity checking method by mask generating algorithm.

        Args:
            mask_algo (MaskAlgo): The algorithm of mask generating.
        Returns:
            CheckMethod: The corresponded sparsity checking method.
        Examples:
            .. code-block:: python

                >>> import numpy as np
                >>> from paddle.incubate.asp import CheckMethod, MaskAlgo
                >>> print(CheckMethod.get_checking_method(MaskAlgo.MASK_1D))
                CheckMethod.CHECK_1D
                >>> print(CheckMethod.get_checking_method(MaskAlgo.MASK_2D_GREEDY))
                CheckMethod.CHECK_2D
                >>> print(CheckMethod.get_checking_method(MaskAlgo.MASK_2D_BEST))
                CheckMethod.CHECK_2D
        z!mask_algo should be MaskAlgo type)
isinstancer   r   r   CHECK_1DCHECK_2D)Z	mask_algor   r   r   get_checking_method0   s   
zCheckMethod.get_checking_methodN)r   r	   r
   r   r   r   staticmethodr   r   r   r   r   r   (   s    r   c                 C   s"   |   }tt|d j|j S )a  

    Return the density of the input tensor.

    Args:
        x (nparray): The input tensor.

    Returns:
        float, The density of :attr:`x`.

    Examples:
        .. code-block:: python

            >>> import paddle
            >>> import numpy as np

            >>> x = np.array([[0, 1, 3, 0],
            ...             [1, 1, 0, 1]])
            >>> out = paddle.incubate.asp.calculate_density(x)
            >>> print(out)
            0.625

    r   )flattenfloatnpnonzerosize)xZx_flattenedr   r   r   calculate_densityN   s   r   c                 C   s   t | jdksJ d| jd | }| jd | dkrDt| jd | jd ||  f}| |ddd| jd f< |j}|d||fS | d|| jfS )a  
    Reshape the input 2D matrix to shape (-1, m).
    If the second dimension of :attr:`mat` is not a multiples of :attr:`m`,
    then this function would pad the remainder with 0 before reshaping.

    .. math::

        remainder = mat.shape[1] % m

    Args:
        mat (nparray): The input 2D matrix.
        m (int): The second dimension of reshaped matrix.
    Returns:
        tuple: A pair of the reshaped and padded matrix and the shape of padded matrix (non-reshaping).
       $The input mat should be a 2D matrix!   r   N)lenshaper   zerosreshape)matm	remainder
mat_paddedr#   r   r   r   _reshape_1dj   s   "r*   c                 C   sf   t | jdkrt| d| jd |\}}nt| |\}}|D ]}t|d j|| kr0 dS qdS )a  
    Check if every row of the input matrix :attr:`mat` is in 1D `n:m` sparse pattern.
    This function would pad the second dimension of :attr:`mat` by zero
    to be a multiples of :attr:`m` if necessary.

    1D `n:m` sparse pattern: At least :attr:`n` zeros in every :math:`1 \times m` block.

    Args:
        mat (nparray): The input matrix.
        n (int): n of `n:m` sparse pattern.
        m (int): m of `n:m` sparse pattern.
    Returns:
        bool: True if every row of :attr:`mat` is in 1D n:m sparse pattern, else False.
    Examples:
        .. code-block:: python

          >>> import numpy as np
          >>> import paddle.incubate.asp as sparsity

          >>> x = np.array([[0, 1, 3, 0],
          ...               [1, 0, 0, 1]])
          >>> y = sparsity.check_mask_1d(x, 2, 4)
          >>> print(y)
          True

          >>> x = np.array([[0, 1, 5, 4],
          ...               [1, 0, 0, 1]])
          >>> y = sparsity.check_mask_1d(x, 2, 4)
          >>> print(y)
          False

          >>> # x would be padded to shape (2, 8)
          >>> x = np.array([[0, 1, 0, 4, 6],
          ...               [1, 0, 0, 1, 7]])
          >>> y = sparsity.check_mask_1d(x, 2, 4)
          >>> print(y)
          True
    r    r   FT)r"   r#   r*   r%   r   r   r   )r&   nr'   mat_flatternr#   sub_matr   r   r   r      s   'r   c           
      C   s   t | |\}}t|}t| }t|jd D ]}|| }tt|}	d|||	d|  f< q||}|ddd| jd f |ddddf< |S )a  
    Generate 1D `n:m` sparse pattern mask of the input matrix :attr:`mat`
    in row-directory. This function would pad the second dimension of :attr:`mat`
    by zero to be a multiples of :attr:`m` before mask generation.

    1D `n:m` sparse pattern: At least :attr:`n` zeros in every :math:`1 \times m` block.

    Args:
        mat (nparray): The input matrix.
        n (int): n of `n:m` sparse pattern.
        m (int): m of `n:m` sparse pattern.
    Returns:
        nparray: The 1D `n:m` sparse mask of :attr:`mat`.
    Examples:
        .. code-block:: python

          >>> import numpy as np
          >>> import paddle.incubate.asp as sparsity
          >>> mat = np.array([[0, 1, 5, 4],
          ...                 [2, 7, 3, 6]])
          >>> mask = sparsity.get_mask_1d(mat, 2, 4)
          >>> print(mask)
          [[0 0 1 1]
          [0 1 0 1]]
          >>> y = sparsity.check_mask_1d(mask, 2, 4)
          >>> print(y)
          True
    r   Nr    )	r*   r   	ones_likeranger#   argsortabsolutetolistr%   )
r&   r+   r'   r,   r#   mask_flatternmaskir-   Zmin_order_indicesr   r   r   r      s   


*r   c                 C   s8  t | jdksJ d| jd | }| jd | }|dkr"| jd n| jd ||  |dkr3| jd n| jd ||  f}t|}| |d| jd d| jd f< t|d|| }d}td|jd |D ].}|| }	td|jd |D ]}
|
| }t|||	|
|f d}|||< |d7 }qwqh||jfS )a3  
    Reshape the input 2D matrix to shape (-1, :math:`m \times m`).
    In each dimension of :attr:`mat`, if it is not a multiples of :attr:`m`,
    then this function would pad the remainder with 0 before reshaping.

    .. math::

        remainder_0 = mat.shape[0] % m \\
        remainder_1 = mat.shape[1] % m

    Args:
        mat (nparray): The input 2D matrix.
        m (int): The square root of second dimension of reshaped matrix.
    Returns:
        tuple: A pair of the reshaped and padded matrix and the shape of padded matrix (non-reshaping).
    r   r   r   r    Nr!   )r"   r#   r   r$   emptyr%   r/   squeeze)r&   r'   Zremainder_0Zremainder_1Z	new_shaper)   r,   curr_idx	row_startrow_end	col_startcol_endr-   r   r   r   _reshape_2d   s*   ""
 

r=   c              	   C   s~   t | |\}}|D ]3}tt|||dk}ttj|dd|| kdkr<ttj|dd|| kdkr< dS q	dS )a  
    Check if every :math:`m \times m` block of the input matrix :attr:`mat` is in 2D `n:m` sparse pattern.
    This function would pad each dimension of :attr:`mat` by zero to be a multiples of
    :attr:`m` if necessary.

    2D `n:m` sparse pattern: At least :math:`n \times n` zeros in every :math:`m \times m` block
    under the constraint of at least :attr:`n` zeros for each row and column.

    Args:
        mat (nparray): The input matrix.
        n (int): n of `n:m` sparse pattern.
        m (int): m of `n:m` sparse pattern.
    Returns:
        bool: True if  every :math:`m \times m` block of the input matrix :attr:`mat` is in 2D `n:m` sparse pattern, else False.
    Examples:
        .. code-block:: python

          >>> import numpy as np
          >>> import paddle.incubate.asp as sparsity

          >>> x = np.array([[0, 8, 9, 0],
          ...               [9, 0, 0, 10],
          ...               [5, 0, 0, 6],
          ...               [0, 4, 6, 0]])
          >>> y = sparsity.check_mask_2d(x, 2, 4)
          >>> print(y)
          True

          >>> x = np.array([[0, 8, 0, 9],
          ...               [9, 0, 0, 10],
          ...               [0, 5, 0, 6],
          ...               [0, 4, 6, 0]])
          >>> y = sparsity.check_mask_2d(x, 2, 4)
          >>> print(y)
          True

          >>> # x would be padded to shape (8, 8)
          >>> x = np.array([[0, 8, 0, 9],
          ...               [9, 0, 7, 0],
          ...               [0, 5, 0, 6],
          ...               [3, 0, 6, 0],
          ...               [1, 1, 0, 1]])
          >>> y = sparsity.check_mask_2d(x, 2, 4)
          >>> print(y)
          True
    r   r    ZaxisFT)r=   r   r1   r7   r%   sum)r&   r+   r'   r)   r#   r-   sub_maskr   r   r   r     s   /  r   c                    s  t |  \}}t|d  }tt|D ]i}tt|| }t|| }t|}	 fdd|	D }
t	
 }t	
 }tt|	d ddD ]5}|
| }||d  |ks`||d  |kraqJd||d |d f< ||d   d7  < ||d   d7  < qJqt|}d}td|d  D ]%}|  }td|d  D ]}|  }|| |||||f< |d7 }qq|d| jd d| jd f S )a  
    Greedily generate 2D `n:m` sparse pattern mask of the input matrix :attr:`mat`.
    This function would pad each dimension of :attr:`mat` by zero to be a multiples of :attr:`m` before mask generation.

    2D `n:m` sparse pattern: At least :math:`n \times n` zeros in every :math:`m \times m` block
    under the constraint of at least :attr:`n` zeros for each row and column.
    Greedily generating: For each :math:`m \times m` block, selecting values to keep in descent order.

    Args:
        mat (nparray): The input matrix.
        n (int): n of `n:m` sparse pattern.
        m (int): m of `n:m` sparse pattern.
    Returns:
        nparray: The 2D `n:m` sparse mask of :attr:`mat`.
    Examples:
        .. code-block:: python

          >>> import numpy as np
          >>> import paddle.incubate.asp as sparsity

          >>> mat = np.array([[9, 8, 3, 7],
          ...                 [9, 2, 1, 10],
          ...                 [5, 1, 3, 6],
          ...                 [2, 4, 6, 1]])
          >>> mask = sparsity.get_mask_2d_greedy(mat, 2, 4)
          >>> print(mask)
          [[1. 1. 0. 0.]
          [1. 0. 0. 1.]
          [0. 0. 1. 1.]
          [0. 1. 1. 0.]]
          >>> y = sparsity.check_mask_2d(mask, 2, 4)
          >>> print(y)
          True
    r!   c                    s    g | ]}t |  |  fqS r   )int).0r   r'   r   r   
<listcomp>q  s    z&get_mask_2d_greedy.<locals>.<listcomp>r    r   g      ?N)r=   r   Z
zeros_liker%   r/   r"   r1   r7   r0   collectionsCounterr6   r#   )r&   r+   r'   r)   r#   Zmask_paddedidxr-   r@   Zmin_order_1d_indicesZmin_order_2d_indicesZrow_counterZcol_counterr5   Zmatrix_entryr4   r8   r9   r:   r;   r<   r   rC   r   r   F  s<   #



 r   c                 C   s   | d|  }|t v rt | S t|}d|d| < ttt| }|| }tttt||}|jdd| kjdd|k	 d 
d}t|jd ||f}||dd  |dd< t  |t |< t  |S )a  
    Compute all vaild 2D `n:m` sparse patterns.

    2D `n:m` sparse pattern: At least :math:`n \times n` zeros in every :math:`m \times m` block
    under the constraint of at least :attr:`n` zeros for each row and column.

    Args:
        n (int): n of `n:m` sparse pattern.
        m (int): m of `n:m` sparse pattern.
    Returns:
        dictionary: A dictionary with key: *m_n* (string) and value: all vaild 2D `n:m` sparse patterns.
    _r    Nr>   r   r!   )_valid_2d_patternsr   r$   listsetr   r2   Zasarrayr?   r   r%   r6   r#   _valid_2d_patterns_lockacquirerelease)r+   r'   Z	valid_keypatternsvalidZvalid_patternsr   r   r   _compute_valid_2d_patterns  s&   
rQ   c              	   C   s   t ||}t| |\}}t|d||}tjt|||jd || jdd}||dd  |dd< t	|}d}	t
d|d |D ]%}
|
| }t
d|d |D ]}|| }||	 ||
|||f< |	d7 }	qTqF|d| jd d| jd f S )a  
    Generate 2D `n:m` sparse pattern mask of the input matrix :attr:`mat`
    to form sparse matrix with maximun L1 norm .This function would pad each
    dimension of :attr:`mat` by zero to be a multiples of :attr:`m` before mask generation.

    2D `n:m` sparse pattern: At least :math:`n \times n` zeros in every :math:`m \times m` block
    under the constraint of at least :attr:`n` zeros for each row and column.

    *Note*: L1 norm of sparse matrix from `Best` API is greater than or equal to the one from `Greedy`.

    Args:
        mat (nparray): The input matrix.
        n (int): n of `n:m` sparse pattern.
        m (int): m of `n:m` sparse pattern.
    Returns:
        nparray: The 1D `n:m` sparse mask of :attr:`mat`.
    Examples:
        .. code-block:: python

          >>> import numpy as np
          >>> import paddle.incubate.asp as sparsity

          >>> mat = np.array([[2, 8, 9, 9],
          ...                 [9, 1, 3, 9],
          ...                 [5, 6, 3, 9],
          ...                 [2, 4, 6, 9]])
          >>> mask_greedy = sparsity.get_mask_2d_greedy(mat, 2, 4)
          >>> mask_best = sparsity.get_mask_2d_best(mat, 2, 4)
          >>> print("L1 norm of `greedy` sparse matrix", np.multiply(mat, mask_greedy).sum())
          L1 norm of `greedy` sparse matrix 56.0
          >>> print("L1 norm of `best` sparse matrix", np.multiply(mat, mask_best).sum())
          L1 norm of `best` sparse matrix 61.0
    r!   r   r    r>   N)rQ   r=   r   r.   r%   Zargmaxmatmulr#   Tr6   r/   )r&   r+   r'   rO   r,   r#   r3   Zpmaxr4   r8   r9   r:   r;   r<   r   r   r   r     s$   
"

 r   r      c           	      C   sZ  | j }| j}| t}t|tsJ dt| ttj	t
 |jd}t|dkr2|d|d }nlt|dkrC||d |d }n[t|dkrX||d |d  |d }nFt|dkr|g d|d |d  |d  |d }||||d	}||d |d |d |d gg d|S td
t| ||||d	}|||S )aH  
    Create `n:m` sparse pattern mask of the input tensor via function given by :attr:`func_name`.
    Currently only support tensor with dimension less than or equal to 4.

    Args:
        tensor (nparray): The input tensor.
        func_name (MaskAlgo, optional): The function name to generate spase mask. Default is `MaskAlgo.MASK_1D`. All options please refer to `MaskAlgo`.
        n (int, optional): n of `n:m` sparse pattern. Default is 2.
        m (int, optional): m of `n:m` sparse pattern. Default is 4.
    Returns:
        nparray: The `n:m` sparse mask of :attr:`tensor` generated by :attr:`func_name`.
    Examples:
        .. code-block:: python

          >>> import numpy as np
          >>> import paddle.incubate.asp as sparsity

          >>> tensor = np.array([[2, 8, 9, 9],
          ...                    [9, 1, 3, 9],
          ...                    [5, 6, 3, 9],
          ...                    [2, 4, 6, 9]])
          >>> mask_1d = sparsity.create_mask(tensor, func_name=sparsity.MaskAlgo.MASK_1D)
          >>> print(mask_1d)
          [[0 0 1 1]
          [1 0 0 1]
          [0 1 0 1]
          [0 0 1 1]]
          >>> mask_2d = sparsity.create_mask(tensor, func_name=sparsity.MaskAlgo.MASK_2D_BEST)
          >>> print(mask_2d)
          [[0 1 1 0]
          [1 0 0 1]
          [1 1 0 0]
          [0 0 1 1]]
    zLfunc_name argumet of create_mask is only accepted as type MaskAlgo. But got Nr    r   r      rT   r   r    rU   r   r+   r'   gThe dimension of input tensor is not supported in create_mask, Only dimension < 4 is supported but got )r#   dtypeastyper   r   r   typegetattrsysmodulesr   valuer"   r%   	transpose
ValueError)	tensor	func_namer+   r'   r#   rY   tfuncr4   r   r   r   create_mask  s>   #
 
rf   c                 C   s
  | j }| t}t|tksJ dt| ttjt |j	d}t
|dkr0|d|d }nNt
|dkrA||d |d }n=t
|dkrV||d |d  |d }n(t
|dkru|g d|d |d  |d  |d g}n	td	t
| ||||d
S )a  
    Check if input tensor is in `n:m` sparse pattern via function given by :attr:`func_name`.
    Currently only support tensor with dimension less than or equal to 4.

    Args:
        tensor (nparray): The input tensor.
        func_name (CheckMethod, optional): The function name to generate spase mask. Default is `CheckMethod.CHECK_1D`. All options please refer to `CheckMethod`.
        n (int, optional): n of `n:m` sparse pattern. Default is 2.
        m (int, optional): m of `n:m` sparse pattern. Default is 4.
    Returns:
        bool: True if tensor pass checking of function given by :attr:`func_name`, else False.
    Examples:
        .. code-block:: python

          >>> import numpy as np
          >>> import paddle.incubate.asp as sparsity

          >>> tensor = np.array([[2, 8, 9, 9],
          ...                    [9, 1, 3, 9],
          ...                    [5, 6, 3, 9],
          ...                    [2, 4, 6, 9]])
          >>> mask_1d = sparsity.create_mask(tensor, func_name=sparsity.MaskAlgo.MASK_1D)
          >>> print(mask_1d)
          [[0 0 1 1]
          [1 0 0 1]
          [0 1 0 1]
          [0 0 1 1]]
          >>> y = sparsity.check_sparsity(mask_1d, func_name=sparsity.CheckMethod.CHECK_1D)
          >>> print(y)
          True
          >>> y = sparsity.check_sparsity(mask_1d, func_name=sparsity.CheckMethod.CHECK_2D)
          >>> print(y)
          True
    zRfunc_name argumet of check_sparsity is only accepted as type CheckMethod. But got Nr    r   r   rU   rT   rV   rX   rW   )r#   rZ   r   r[   r   r\   r]   r^   r   r_   r"   r%   r`   ra   )rb   rc   r+   r'   r#   rd   re   r   r   r   check_sparsity9  s0   #
rg   )r   rE   r]   	threadingenumr   	itertoolsr   numpyr   __all__r   r   r   r*   r   r   r=   r   r   LockrL   rI   rQ   r   r   rf   r   rg   r   r   r   r   <module>   s.   
&2*+9G)8G