U
    /e/                  	   @   s  d Z ddlZddlmZmZmZ ddlmZ ddlm	Z	 ddl
ZddlmZ ddlmZ dd	 ZejZejZejZejZeejZeejZeejZeejZejZejZejZejZejZejZejZej Z ej!Z!e"e# ej$Z$W 5 Q R X ej%Z%e"e# ej&Z&W 5 Q R X ej'Z'e"e# ej(Z(W 5 Q R X d)ddZ)d*ddZ*dd Z+dd Z,dd Z-dd Z.dd Z/d+ddZ0d,ddZ1d-ddZ2d.d!d"Z3d#d$ Z4d%d& Z5d'd( Z6dS )/z- A set of NumPy functions to apply per chunk     N)	ContainerIterableSequencewraps)Integral)concat)flattenc                    s   t  d fdd	}|S )zU
    A wrapper for functions that don't provide keepdims to ensure that they do.
    Nc           	         s    | f|d|i|}|s |S |}|d kr6t | j}t|tttfsL|g}t }t | jD ]$}||krr|d7 }q\|td f7 }q\|| }|S )NaxisN)rangendim
isinstancer   r   r   tupleslice)	xr
   keepdimsargskwargsraxesZr_sliceZ	each_axis
a_callable 4/tmp/pip-unpacked-wheel-dbjnr7gq/dask/array/chunk.pykeepdims_wrapped_callable   s    

z3keepdims_wrapper.<locals>.keepdims_wrapped_callable)NNr   )r   r   r   r   r   keepdims_wrapper   s    r   Fc                    s   t jD ]}| kr
d |< q
|rHt fddtjD }| tt fddt jD }| |fdtt djd di|S )a  Coarsen array by applying reduction to fixed size neighborhoods

    Parameters
    ----------
    reduction: function
        Function like np.sum, np.mean, etc...
    x: np.ndarray
        Array to be coarsened
    axes: dict
        Mapping of axis to coarsening factor

    Examples
    --------
    >>> x = np.array([1, 2, 3, 4, 5, 6])
    >>> coarsen(np.sum, x, {0: 2})
    array([ 3,  7, 11])
    >>> coarsen(np.max, x, {0: 3})
    array([3, 6])

    Provide dictionary of scale per dimension

    >>> x = np.arange(24).reshape((4, 6))
    >>> x
    array([[ 0,  1,  2,  3,  4,  5],
           [ 6,  7,  8,  9, 10, 11],
           [12, 13, 14, 15, 16, 17],
           [18, 19, 20, 21, 22, 23]])

    >>> coarsen(np.min, x, {0: 2, 1: 3})
    array([[ 0,  3],
           [12, 15]])

    You must avoid excess elements explicitly

    >>> x = np.array([1, 2, 3, 4, 5, 6, 7, 8])
    >>> coarsen(np.min, x, {0: 3}, trim_excess=True)
    array([1, 4])
       c                 3   s<   | ]4\}}| |  r*t d | |   nt ddV  qdS )r   Nr   ).0idr   r   r   	<genexpr>   s   zcoarsen.<locals>.<genexpr>c                    s&   g | ]}j |  |   | fqS r   )shaper   r    r   r   r   r   
<listcomp>   s     zcoarsen.<locals>.<listcomp>r
      )r   r   r   	enumerater$   r   Zreshape)Z	reductionr   r   Ztrim_excessr   r    indZnewshaper   r&   r   coarsenR   s    (
"r+   c                    sN   t  tr g| j  t  tr8 fddt| jD  | tdd  D  S )aC  Trim boundaries off of array

    >>> x = np.arange(24).reshape((4, 6))
    >>> trim(x, axes={0: 0, 1: 1})
    array([[ 1,  2,  3,  4],
           [ 7,  8,  9, 10],
           [13, 14, 15, 16],
           [19, 20, 21, 22]])

    >>> trim(x, axes={0: 1, 1: 1})
    array([[ 7,  8,  9, 10],
           [13, 14, 15, 16]])
    c                    s   g | ]}  |d qS )r   )getr%   r"   r   r   r'      s     ztrim.<locals>.<listcomp>c                 s   s"   | ]}t ||r| nd V  qd S r   r   )r   Zaxr   r   r   r#      s     ztrim.<locals>.<genexpr>)r   r   r   dictr   r   )r   r   r   r"   r   trim   s
    

r.   c                    s|   |dkst  d  t|| j  kr*| S tj| |  d} |dkrPt| dnt| | t fddt| jD  S )a  Chunk and combine function of topk

    Extract the k largest elements from a on the given axis.
    If k is negative, extract the -k smallest elements instead.
    Note that, unlike in the parent function, the returned elements
    are not sorted internally.
    Tr   r
   Nc                 3   s"   | ]}| krnt d V  qd S r   r   r%   r
   Zk_slicer   r   r#      s     ztopk.<locals>.<genexpr>)	AssertionErrorabsr$   np	partitionr   r   r   r   akr
   r   r   r0   r   topk   s    r8   c                    s\   |dkst t| | |}  d  tj|  d} |dk r<| S | t fddt| jD  S )zmFinal aggregation function of topk

    Invoke topk one final time and then sort the results internally.
    Tr   r/   c                 3   s*   | ]"}| krt d d dnt d V  qd S Nr   r%   r/   r   r   r#      s    z!topk_aggregate.<locals>.<genexpr>)r1   r8   r3   sortr   r   r   r5   r   r/   r   topk_aggregate   s    r<   c                 C   s   | |fS )z^Preparatory step for argtopk

    Put data together with its original indices in a tuple.
    r   )r6   idxr   r   r   argtopk_preprocess   s    r>   c                    s   |dkst  d  t| trXtt| } tdd | D  }tdd | D  }n| \}}t||j  krv| S tj||  d}|dkrt	| dnt	| |t
 fdd	t|jD  }t|| t|| fS )
a)  Chunk and combine function of argtopk

    Extract the indices of the k largest elements from a on the given axis.
    If k is negative, extract the indices of the -k smallest elements instead.
    Note that, unlike in the parent function, the returned elements
    are not sorted internally.
    Tr   c                 S   s   g | ]\}}|qS r   r   )r   ai_r   r   r   r'      s     zargtopk.<locals>.<listcomp>c                 S   s   g | ]\}}t ||jqS r   )r3   Zbroadcast_tor$   )r   r?   Zidxir   r   r   r'      s     r/   Nc                 3   s"   | ]}| krnt d V  qd S r   r   r%   r0   r   r   r#      s     zargtopk.<locals>.<genexpr>)r1   r   listr	   r3   Zconcatenater2   r$   Zargpartitionr   r   r   r   take_along_axisZ
a_plus_idxr7   r
   r   r6   r=   Zidx2r   r0   r   argtopk   s     
 "rD   c                    s   |dkst t| dkr| n| d } t| | |\}} d  tj| d}t|| }|dk rf|S |t fddt|jD  S )zFinal aggregation function of argtopk

    Invoke argtopk one final time, sort the results internally, drop the data
    and return the index only.
    Tr   r   r/   c                 3   s*   | ]"}| krt d d dnt d V  qd S r9   r   r%   r/   r   r   r#      s    z$argtopk_aggregate.<locals>.<genexpr>)	r1   lenrD   r3   ZargsortrB   r   r   r   rC   r   r/   r   argtopk_aggregate   s    rF   c                 C   s:   ddl m} || ||||d}t||kr6|d d S |S )Nr   )arange_safeliker:   )dask.array.utilsrG   rE   )startstopsteplengthdtyperI   rG   resr   r   r   arange   s    rQ   Tc                 C   sD   ddl m} t| |r|  } t||r0| }tj| ||||dS )Nr   )Array)endpointrO   )Zdask.array.corerR   r   Zcomputer3   linspace)rK   rL   numrS   rO   rR   r   r   r   rT     s    

rT   c                 K   s   | j |f|S r   )astype)r   Zastype_dtyper   r   r   r   rV     s    rV   Cc                 C   s   |dkrDzt j| | d} W n tk
r8   t | } Y nX | |S zt j| | d} W n tk
rt   t | } Y nX | j|jS d S )NrW   rH   )r3   Zascontiguousarray	TypeErrorviewZasfortranarrayT)r   rO   orderr   r   r   rY     s    
rY   c                    s   ddl m}m} ||| dtjtdk | | dk| j  k @ }| | t fddt	| j
D  S )a  Chunk function of `slice_with_int_dask_array_on_axis`.
    Slice one chunk of x by one chunk of idx.

    Parameters
    ----------
    x: ndarray, any dtype, any shape
        i-th chunk of x
    idx: ndarray, ndim=1, dtype=any integer
        j-th chunk of idx (cartesian product with the chunks of x)
    offset: ndarray, shape=(1, ), dtype=int64
        Index of the first element along axis of the current chunk of x
    x_size: int
        Total size of the x da.Array along axis
    axis: int
        normalized axis to take elements from (0 <= axis < x.ndim)

    Returns
    -------
    x sliced along axis, using only the elements of idx that fall inside the
    current chunk.
    r   )asarray_safemeta_from_arrayrH   c                 3   s"   | ]}| krnt d V  qd S r   r   r%   r
   r=   r   r   r#   Q  s     z,slice_with_int_dask_array.<locals>.<genexpr>)rJ   r\   r]   rV   r3   int64wherer$   r   r   r   )r   r=   offsetZx_sizer
   r\   r]   
idx_filterr   r^   r   slice_with_int_dask_array&  s    rc   c           	         s   |  tj} t| dk | t| | } d}d}t| |D ]Z}| |k| || k @ }t|}t||d | d7 ||7 }|jdkr<||d 7 }q<|t fddt	|j
D  S )aS  Final aggregation function of `slice_with_int_dask_array_on_axis`.
    Aggregate all chunks of x by one chunk of idx, reordering the output of
    `slice_with_int_dask_array`.

    Note that there is no combine function, as a recursive aggregation (e.g.
    with split_every) would not give any benefit.

    Parameters
    ----------
    idx: ndarray, ndim=1, dtype=any integer
        j-th chunk of idx
    chunk_outputs: ndarray
        concatenation along axis of the outputs of `slice_with_int_dask_array`
        for all chunks of x and the j-th chunk of idx
    x_chunks: tuple
        dask chunks of the x da.Array along axis, e.g. ``(3, 3, 2)``
    axis: int
        normalized axis to take elements from (0 <= axis < x.ndim)

    Returns
    -------
    Selection from all chunks of x for the j-th chunk of idx, in the correct
    order
    r   r   r:   c                 3   s"   | ]}| krnt d V  qd S r   r   r%   r
   Z	idx_finalr   r   r#     s    z6slice_with_int_dask_array_aggregate.<locals>.<genexpr>)rV   r3   r_   r`   sumZ
zeros_likeZcumsumsizer   r   r   )	r=   Zchunk_outputsZx_chunksr
   Zx_chunk_offsetZchunk_output_offsetZx_chunkrb   Zidx_cumr   rd   r   #slice_with_int_dask_array_aggregateT  s"    


rg   c              
   C   sx   z| | }W n, t k
r8 } ztd|W 5 d}~X Y nX z$|jjs\| jd|j kr\| }W n tk
rr   Y nX |S )af  Getitem function

    This function creates a copy of the desired selection for array-like
    inputs when the selection is smaller than half of the original array. This
    avoids excess memory usage when extracting a small portion from a large array.
    For more information, see
    https://numpy.org/doc/stable/reference/arrays.indexing.html#basic-slicing-and-indexing.

    Parameters
    ----------
    obj: ndarray, string, tuple, list
        Object to get item from.
    index: int, list[int], slice()
        Desired selection to extract from obj.

    Returns
    -------
    Selection obj[index]

    zTArray chunk size or shape is unknown. Possible solution with x.compute_chunk_sizes()Nr(   )
IndexError
ValueErrorflagsZowndatarf   copyAttributeError)objindexresulter   r   r   getitem  s    rq   )F)N)N)TN)N)rW   )7__doc__
contextlibcollections.abcr   r   r   	functoolsr   Znumbersr   Znumpyr3   Ztlzr   Z	dask.corer	   r   re   prodminmaxZargminZ	nanargminZargmaxZ	nanargmaxanyallZnansumZnanprodZ
nancumprodZ	nancumsumZnanminZnanmaxZmeansuppressrl   ZnanmeanvarZnanvarZstdZnanstdr+   r.   r8   r<   r>   rD   rF   rQ   rT   rV   rY   rc   rg   rq   r   r   r   r   <module>   s^   #




9




.8