o
    ְi8                     @   s  d dl 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 d0dd	Z	d0d
dZ
d0ddZd0ddZdd Zdd ZedddZd1ddZdd ZdZdZdZejdded ee d!Zd"Zejd#d$d%e d& d'ee d!Zejd#d(d)e d& d*ee d!Zd2d,d-Zd.d/ ZdS )3    N)_core)fusion)_util)_routines_indexing)_routines_statisticsFc                 C      | j ||||dS )a  Returns the indices of the maximum along an axis.

    Args:
        a (cupy.ndarray): Array to take argmax.
        axis (int): Along which axis to find the maximum. ``a`` is flattened by
            default.
        dtype: Data type specifier.
        out (cupy.ndarray): Output array.
        keepdims (bool): If ``True``, the axis ``axis`` is preserved as an axis
            of length one.

    Returns:
        cupy.ndarray: The indices of the maximum of ``a`` along an axis.

    .. note::
       ``dtype`` and ``keepdim`` arguments are specific to CuPy. They are
       not in NumPy.

    .. note::
       ``axis`` argument accepts a tuple of ints, but this is specific to
       CuPy. NumPy does not support it.

    .. seealso:: :func:`numpy.argmax`

    axisdtypeoutkeepdims)argmaxar	   r
   r   r    r   H/home/ubuntu/.local/lib/python3.10/site-packages/cupy/_sorting/search.pyr   
      r   c                 C   0   | j jdv rt| ||||dS t| ||||S )a  Return the indices of the maximum values in the specified axis ignoring
    NaNs. For all-NaN slice ``-1`` is returned.
    Subclass cannot be passed yet, subok=True still unsupported

    Args:
        a (cupy.ndarray): Array to take nanargmax.
        axis (int): Along which axis to find the maximum. ``a`` is flattened by
            default.

    Returns:
        cupy.ndarray: The indices of the maximum of ``a``
        along an axis ignoring NaN values.

    .. note:: For performance reasons, ``cupy.nanargmax`` returns
            ``out of range values`` for all-NaN slice
            whereas ``numpy.nanargmax`` raises ``ValueError``
    .. seealso:: :func:`numpy.nanargmax`
    biur   )r
   kindr   _statistics
_nanargmaxr   r   r   r   	nanargmax(      r   c                 C   r   )a  Returns the indices of the minimum along an axis.

    Args:
        a (cupy.ndarray): Array to take argmin.
        axis (int): Along which axis to find the minimum. ``a`` is flattened by
            default.
        dtype: Data type specifier.
        out (cupy.ndarray): Output array.
        keepdims (bool): If ``True``, the axis ``axis`` is preserved as an axis
            of length one.

    Returns:
        cupy.ndarray: The indices of the minimum of ``a`` along an axis.

    .. note::
       ``dtype`` and ``keepdim`` arguments are specific to CuPy. They are
       not in NumPy.

    .. note::
       ``axis`` argument accepts a tuple of ints, but this is specific to
       CuPy. NumPy does not support it.

    .. seealso:: :func:`numpy.argmin`

    r   )argminr   r   r   r   r   A   r   r   c                 C   r   )a  Return the indices of the minimum values in the specified axis ignoring
    NaNs. For all-NaN slice ``-1`` is returned.
    Subclass cannot be passed yet, subok=True still unsupported

    Args:
        a (cupy.ndarray): Array to take nanargmin.
        axis (int): Along which axis to find the minimum. ``a`` is flattened by
            default.

    Returns:
        cupy.ndarray: The indices of the minimum of ``a``
        along an axis ignoring NaN values.

    .. note:: For performance reasons, ``cupy.nanargmin`` returns
            ``out of range values`` for all-NaN slice
            whereas ``numpy.nanargmin`` raises ``ValueError``
    .. seealso:: :func:`numpy.nanargmin`
    r   r   )r
   r   r   r   
_nanargminr   r   r   r   	nanargmin_   r   r   c                 C   s   t j| dd |  S )a  Return the indices of the elements that are non-zero.

    Returns a tuple of arrays, one for each dimension of a,
    containing the indices of the non-zero elements in that dimension.

    Args:
        a (cupy.ndarray): array

    Returns:
        tuple of arrays: Indices of elements that are non-zero.

    .. warning::

        This function may synchronize the device.

    .. seealso:: :func:`numpy.nonzero`

    r   arg_name)r   check_arraynonzeror   r   r   r   r    x   s   r    c                 C   s   t j| dd |   d S )a  Return indices that are non-zero in the flattened version of a.

    This is equivalent to a.ravel().nonzero()[0].

    Args:
        a (cupy.ndarray): input array

    Returns:
        cupy.ndarray: Output array,
        containing the indices of the elements of a.ravel() that are non-zero.

    .. warning::

        This function may synchronize the device.

    .. seealso:: :func:`numpy.flatnonzero`
    r   r   r   )r   r   ravelr    r!   r   r   r   flatnonzero   s   r#   
cupy_where)z???->?z?bb->bz?BB->Bz?hh->hz?HH->Hz?ii->iz?II->Iz?ll->lz?LL->Lz?qq->qz?QQ->Qz?ee->ez?ff->fz?hd->dz?Hd->dz?dd->dz?FF->Fz?DD->Dzout0 = in0 ? in1 : in2c                 C   s`   |du |du f d}|dkrtd|dkrt| S t r'tt| ||S t| d||S )a  Return elements, either from x or y, depending on condition.

    If only condition is given, return ``condition.nonzero()``.

    Args:
        condition (cupy.ndarray): When True, take x, otherwise take y.
        x (cupy.ndarray): Values from which to choose on ``True``.
        y (cupy.ndarray): Values from which to choose on ``False``.

    Returns:
        cupy.ndarray: Each element of output contains elements of ``x`` when
        ``condition`` is ``True``, otherwise elements of ``y``. If only
        ``condition`` is given, return the tuple ``condition.nonzero()``,
        the indices where ``condition`` is True.

    .. warning::

        This function may synchronize the device if both ``x`` and ``y`` are
        omitted.

    .. seealso:: :func:`numpy.where`

    NT   z)Must provide both 'x' and 'y' or neither.   ?)count
ValueErrorr    r   
_is_fusing_call_ufunc_where_ufuncastype)	conditionxymissingr   r   r   where   s   r2   c                 C   s   t j| dd t| S )a  Return the indices of the elements that are non-zero.

    Returns a (N, ndim) dimantional array containing the
    indices of the non-zero elements. Where `N` is number of
    non-zero elements and `ndim` is dimension of the given array.

    Args:
        a (cupy.ndarray): array

    Returns:
        cupy.ndarray: Indices of elements that are non-zero.

    .. seealso:: :func:`numpy.argwhere`

    r   r   )r   r   	_indexing_ndarray_argwherer!   r   r   r   argwhere   s   
r5   zO
template<typename T>
__device__ bool _isnan(T val) {
    return val != val;
}
a  
#ifdef __HIP_DEVICE_COMPILE__
  #define no_thread_divergence(do_work, to_return) \
    if (!is_done) {                                \
      do_work;                                     \
      is_done = true;                              \
    }
#else
  #define no_thread_divergence(do_work, to_return) \
    do_work;                                       \
    if (to_return) { return; }
#endif
a  
    #ifdef __HIP_DEVICE_COMPILE__
    bool is_done = false;
    #endif

    // Array is assumed to be monotonically
    // increasing unless a check is requested with the
    // `assume_increasing = False` parameter.
    // `digitize` allows increasing and decreasing arrays.
    bool inc = true;
    if (!assume_increasing && n_bins >= 2) {
        // In the case all the bins are nan the array is considered
        // to be decreasing in numpy
        inc = (bins[0] <= bins[n_bins-1])
              || (!_isnan<T>(bins[0]) && _isnan<T>(bins[n_bins-1]));
    }

    if (_isnan<S>(x)) {
        long long pos = (inc ? n_bins : 0);
        if (!side_is_right) {
            if (inc) {
                while (pos > 0 && _isnan<T>(bins[pos-1])) {
                    --pos;
                }
            } else {
                while (pos < n_bins && _isnan<T>(bins[pos])) {
                    ++pos;
                }
            }
        }
        no_thread_divergence( y = pos , true )
    }

    bool greater = false;
    if (side_is_right) {
        greater = inc && x >= bins[n_bins-1];
    } else {
        greater = (inc ? x > bins[n_bins-1] : x <= bins[n_bins-1]);
    }
    if (greater) {
        no_thread_divergence( y = n_bins , true )
    }

    long long left = 0;
    // In the case the bins is all NaNs, digitize
    // needs to place all the valid values to the right
    if (!inc) {
        while (_isnan<T>(bins[left]) && left < n_bins) {
            ++left;
        }
        if (left == n_bins) {
            no_thread_divergence( y = n_bins , true )
        }
        if (side_is_right
                && !_isnan<T>(bins[n_bins-1]) && !_isnan<S>(x)
                && bins[n_bins-1] > x) {
            no_thread_divergence( y = n_bins , true )
        }
    }

    long long right = n_bins-1;
    while (left < right) {
        long long m = left + (right - left) / 2;
        bool look_right = true;
        if (side_is_right) {
            look_right = (inc ? bins[m] <= x : bins[m] > x);
        } else {
            look_right = (inc ? bins[m] < x : bins[m] >= x);
        }
        if (look_right) {
            left = m + 1;
        } else {
            right = m;
        }
    }
    no_thread_divergence( y = right , false )
zIS x, raw T bins, int64 n_bins, bool side_is_right, bool assume_increasingzint64 ycupy_searchsorted_kernel)namepreambleaJ  
#ifdef __HIP_DEVICE_COMPILE__
  #define no_thread_divergence(do_work, to_return) \
    if (!is_done) {                                \
      do_work;                                     \
      is_done = true;                              \
    }
#else
  #define no_thread_divergence(do_work, to_return) \
    do_work;                                       \
    if (to_return) {                               \
      out = (y == n_bins ? false : bins[y] == x);  \
      if (invert) out = !out;                      \
      return;                                      \
    }
#endif
z*S x, raw T bins, int64 n_bins, bool invertzbool outze
    const bool assume_increasing = true;
    const bool side_is_right = false;
    long long y;
    zQ
    out = (y == n_bins ? false : bins[y] == x);
    if (invert) out = !out;
    cupy_exists_kernelzbool out, int64 yzT
    const bool assume_increasing = true;
    const bool side_is_right = false;
    #cupy_exists_and_searchsorted_kernelleftc                 C   s   t | |||dS )a  Finds indices where elements should be inserted to maintain order.

    Find the indices into a sorted array ``a`` such that,
    if the corresponding elements in ``v`` were inserted before the indices,
    the order of ``a`` would be preserved.

    Args:
        a (cupy.ndarray): Input array. If ``sorter`` is ``None``, then
            it must be sorted in ascending order,
            otherwise ``sorter`` must be an array of indices that sort it.
        v (cupy.ndarray): Values to insert into ``a``.
        side : {'left', 'right'}
            If ``left``, return the index of the first suitable location found
            If ``right``, return the last such index.
            If there is no suitable index, return either 0 or length of ``a``.
        sorter : 1-D array_like
            Optional array of integer indices that sort array ``a`` into
            ascending order. They are typically the result of
            :func:`~cupy.argsort`.

    Returns:
        cupy.ndarray: Array of insertion points with the same shape as ``v``.

    .. note:: When a is not in ascending order, behavior is undefined.

    .. seealso:: :func:`numpy.searchsorted`

    T)_searchsorted)r   vsidesorterr   r   r   searchsorted  s   r@   c                 C   s  t | tjs
tdt |tjstd| jdkrtd| jdk r&td| jdkr4tj|jtj	dS | j
jdk}|j
jdk}|rK|sK|| j
}n
|rU|sU| |j
} |d	urr|j
jd
vrctd|j| jkrmtd| |} tj|jtj	d}t|| | j|dk|| |S )z`assume_increasing` is used in the kernel to
    skip monotonically increasing or decreasing verification
    inside the cuda kernel.
    z'Only int or ndarray are supported for az'Only int or ndarray are supported for vr%   z!object too deep for desired arrayz+object of too small depth for desired arrayr   )r
   cN)iuzsorter must be of integer typezsorter.size must equal a.sizeright)
isinstancecupyndarrayNotImplementedErrorndimr)   sizezerosshapeint64r
   r   r-   	TypeErrortake_searchsorted_kernel)r   r=   r>   r?   assume_increasinga_iscomplexv_iscomplexr0   r   r   r   r<     s2   



r<   )NNNF)NN)r;   N)rF   r   
cupy._corer   r   r   r3   r   r   r   r   r   r   r    r#   create_ufuncr,   r2   r5   	_preamble_hip_preamble_searchsorted_codeElementwiseKernelrP   _exists_kernel_exists_and_searchsorted_kernelr@   r<   r   r   r   r   <module>   sh    




%O
 