o
    װi*                     @  s  U d dl mZ d dlZd dl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mZ d dlZd dlZd dlZd dlZd dlmZ d dlmZ e rYd dlZejjZded	< nejZd4ddZd5ddZd6ddZeejdfddZeejfddZeejdd dfddZ ej!j"ejdd d fd!d"Z#eejfd#d$Z$eejfdd%d&d'Z%ej&d(d) Z'G d*d+ d+ej(Z)G d,d- d-e)Z*G d.d/ d/e)Z+ej&d0d1d2d3Z,e,Z-dS )7    )annotationsN)Callable)PackageNotFoundError)mock)internal)is_availablez-Callable[..., Callable[[Callable], Callable]]_skipifrequirementsstrreturnCallable[[Callable], Callable]c                  G  s"   dd |  }tt|   |dS )a  Run a test case only when given requirements are satisfied.

    .. admonition:: Example

       This test case runs only when `numpy>=1.18` is installed.

       >>> from cupy import testing
       ...
       ...
       ... class Test(unittest.TestCase):
       ...     @testing.with_requires("numpy>=1.18")
       ...     def test_for_numpy_1_18(self):
       ...         pass

    Args:
        requirements: A list of string representing requirement condition to
            run a given test case.

    z
requires: ,)reason)joinr   	installed)r	   msg r   H/home/ubuntu/.local/lib/python3.10/site-packages/cupy/testing/_helper.pywith_requires   s   r   
specifiersboolc               	   G  sj   ddl m} | D ]*}||}z	tj|j}W n ty"   Y  dS w |j}|r2|j|dds2 dS qdS )zReturns True if the current environment satisfies the specified
    package requirement.

    Args:
        specifiers: Version specifiers (e.g., `numpy>=1.20.0`).
    r   )RequirementFT)prereleases)	packaging.requirementsr   	importlibmetadataversionnamer   	specifiercontains)r   r   specreqfoundexpectedr   r   r   r   4   s   r   version_rangec                 C  s   t d|  S )zReturns True if numpy version satisfies the specified criteria.

    Args:
        version_range: A version specifier (e.g., `>=1.13.0`).
    numpy)r   )r$   r   r   r   numpy_satisfiesK   s   r&   Cc                 C  sh   t |}t dt| d d}|dkr|d dk}n|jdkr'||d  }|j||| |dS )av  Returns an array with given shape, array module, and dtype.

    Args:
         shape(tuple of int): Shape of returned ndarray.
         xp(numpy or cupy): Array module to use.
         dtype(dtype): Dtype of returned ndarray.
         order({'C', 'F'}): Order of returned ndarray.

    Returns:
         numpy.ndarray or cupy.ndarray:
         The array filled with :math:`1, \cdots, N` with specified dtype
         with given shape, array module. Here, :math:`N` is
         the size of the returned array.
         If ``dtype`` is ``numpy.bool_``, evens (resp. odds) are converted to
         ``True`` (resp. ``False``).

       ?   r   c              ?)order)	r%   dtypearanger   prodkindarrayastypereshape)shapexpr.   r-   ar   r   r   shaped_arangeT   s   

r8   c                 C  sd   t |}t| }t |dd}|dkr|d dk}n|jdkr'||d  }|||| S )a3  Returns an array filled with decreasing numbers.

    Args:
         shape(tuple of int): Shape of returned ndarray.
         xp(numpy or cupy): Array module to use.
         dtype(dtype): Dtype of returned ndarray.

    Returns:
         numpy.ndarray or cupy.ndarray:
         The array filled with :math:`N, \cdots, 1` with specified dtype
         with given shape, array module.
         Here, :math:`N` is the size of the returned array.
         If ``dtype`` is ``numpy.bool_``, evens (resp. odds) are converted to
         ``True`` (resp. ``False``).
    r   r)   r*   r+   r,   )	r%   r.   r   r0   r/   r1   r2   r3   r4   )r5   r6   r.   sizer7   r   r   r   shaped_reverse_arangeo   s   


r;   
   c                 C  s   t j| t |}|dkrt jjd| d}n |jdkr0t jj|  dt jj|    }||9 }nt jj|  | }|j|||dS )a  Returns an array filled with random values.

    Args:
         shape(tuple): Shape of returned ndarray.
         xp(numpy or cupy): Array module to use.
         dtype(dtype): Dtype of returned ndarray.
         scale(float): Scaling factor of elements.
         seed(int): Random seed.

    Returns:
         numpy.ndarray or cupy.ndarray: The array with
         given shape, array module,

    If ``dtype`` is ``numpy.bool_``, the elements are
    independently drawn from ``True`` and ``False``
    with same probabilities.
    Otherwise, the array is filled with samples
    independently and identically drawn
    from uniform distribution over :math:`[0, scale)`
    with specified dtype.
    r)   r*   )r:   r+   r,   )r.   r-   )r%   randomseedr.   randintr1   randasarray)r5   r6   r.   scaler>   r-   r7   r   r   r   shaped_random   s   


rC   g{Gz?cooc           
      C  sp   ddl }| \}}tj| |j||||}	|tjju r'tjj|	}	n||jur3t	d
||	|S )a  Returns an array filled with random values.

    Args:
        shape (tuple): Shape of returned sparse matrix.
        sp (scipy.sparse or cupyx.scipy.sparse): Sparce matrix module to use.
        dtype (dtype): Dtype of returned sparse matrix.
        density (float): Density of returned sparse matrix.
        format (str): Format of returned sparse matrix.
        seed (int): Random seed.

    Returns:
        The sparse matrix with given shape, array module,
    r   NzUnknown module: {})scipy.sparser%   r=   r>   sparser3   cupyxscipy
coo_matrix
ValueErrorformatasformat)
r5   spr.   densityrK   r>   rH   n_rowsn_colsr7   r   r   r   shaped_sparse_random   s   

rQ   c                 C  sj   t |}t |}|dkrt| d} t|d}n
|jdkr#t| d} t | ||}|||	|S )ah  Returns an array with given shape, array module, and dtype.

    Args:
        start (int): The starting value.
        stop (int): The end value.
        shape (tuple of int): Shape of returned ndarray.
        xp (numpy or cupy): Array module to use.
        dtype (dtype): Dtype of returned ndarray.

    Returns:
        numpy.ndarray or cupy.ndarray:
    r)   r   r(   u)
r%   r.   r0   maxminr1   linspacer2   r3   r4   )startstopr5   r6   r.   r:   r7   r   r   r   shaped_linspace   s   




rX   )singular_valuesc          	      C  s   t | dkrtd| |du rtd||}t|}|jdvr+td|||s4td|dk 	 r>td	|j
j|  }|jd
krS|d|j
j|    }|jj|dd\}}}|||j}|d|||}||S )a  Returns a matrix with specified singular values.

    Generates a random matrix with given singular values.
    This function generates a random NumPy matrix (or a stack of matrices) that
    has specified singular values. It can be used to generate the inputs for a
    test that can be instable when the input value behaves bad.
    Notation: denote the shape of the generated array by :math:`(B..., M, N)`,
    and :math:`K = min\{M, N\}`. :math:`B...` may be an empty sequence.

    Args:
        shape (tuple of int): Shape of the generated array, i.e.,
            :math:`(B..., M, N)`.
        xp (numpy or cupy): Array module to use.
        dtype: Dtype of the generated array.
        singular_values (array-like): Singular values of the generated
            matrices. It must be broadcastable to shape :math:`(B..., K)`.

    Returns:
        numpy.ndarray or cupy.ndarray: A random matrix that has specific
        singular values.
    r(   z.shape {} is invalid for matrices: too few axesNzsingular_values is not givenfczdtype {} is not supportedzsingular_values is not realr   z negative singular value is givenr+   r,   F)full_matricesz...ik,...k,...kj->...ij)lenrJ   rK   	TypeErrorrA   r%   r.   r1   	isrealobjanyr=   randnlinalgsvdbroadcast_tor5   einsumr3   )	r5   r6   r.   rY   r7   rR   svhsvr   r   r   generate_matrix   s*   





rh   c                 #  s    t jdd}t d d V  W d    n1 sw   Y  t fdd|D r,d S z j}W n ty>   t }Y nw td| )NT)recordalwaysc                 3  s    | ]	}t |j V  qd S N)
isinstancemessage).0mr#   r   r   	<genexpr>  s    zassert_warns.<locals>.<genexpr>z%s not triggerred)warningscatch_warningssimplefilterr_   __name__AttributeErrorr
   AssertionError)r#   wexc_namer   rp   r   assert_warns  s   

rz   c                   @  s0   e Zd Zedd Zedd Zedd ZdS )NumpyAliasTestBasec                 C  s   t  rk   )NotImplementedErrorselfr   r   r   func*  s   zNumpyAliasTestBase.funcc                 C     t t| jS rk   )getattrcupyr   r}   r   r   r   	cupy_func.     zNumpyAliasTestBase.cupy_funcc                 C  r   rk   )r   r%   r   r}   r   r   r   
numpy_func2  r   zNumpyAliasTestBase.numpy_funcN)ru   
__module____qualname__propertyr   r   r   r   r   r   r   r{   (  s    

r{   c                   @  s   e Zd Zdd Zdd ZdS )NumpyAliasBasicTestBasec                 C  s"   t j}|| j|| jksJ d S rk   )inspect	signaturer   r   )r~   fr   r   r   test_argspec9  s   z$NumpyAliasBasicTestBase.test_argspecc                 C  sJ   | j }| j}t|dsJ |jd usJ |jdksJ |j|jus#J d S )N__doc__ )r   r   hasattrr   )r~   r   r   r   r   r   test_docstring=  s   z&NumpyAliasBasicTestBase.test_docstringN)ru   r   r   r   r   r   r   r   r   r   7  s    r   c                   @  s   e Zd Zdd ZdS )NumpyAliasValuesTestBasec                 C  s    | j | j | j| j ksJ d S rk   )r   argsr   r}   r   r   r   test_valuesH  s    z$NumpyAliasValuesTestBase.test_valuesN)ru   r   r   r   r   r   r   r   r   F  s    r   r(   )times_calledc                 o  sL    t j|i |}dV  |j| ksJ W d   dS 1 sw   Y  dS )a   A handy wrapper for unittest.mock to check if a function is called.

    Args:
        *args: Arguments of `mock.patch`.
        times_called (int): The number of times the function should be
            called. Default is ``1``.
        **kwargs: Keyword arguments of `mock.patch`.

    N)r   patch
call_count)r   r   kwargshandler   r   r   assert_function_is_calledL  s
   "r   )r	   r
   r   r   )r   r
   r   r   )r$   r
   r   r   ).
__future__r   
contextlibimportlib.metadatar   r   unittestrr   collections.abcr   r   r   r%   r   rG   cupyx.scipy.sparse
cupy._corer   cupy.testing._pytest_implr   pytestmarkskipifr   __annotations__skipIfr   r   r&   float32r8   r;   rC   rH   rF   rQ   rX   rh   contextmanagerrz   TestCaser{   r   r   r   AssertFunctionIsCalledr   r   r   r   <module>   sT    


	

$
6
