B
    T\D                 @   sN  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mZmZmZ d dlmZ ddlmZmZ dd	lmZmZ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 Z!d3ddZ"dd Z#d4ddZ$d5ddZ%dd Z&dd Z'dd Z(d d! Z)d"d# Z*d$d% Z+d6d&d'Z,d(d) Z-d*d+ Z.d7d-d.Z/d/d0 Z0d1d2 Z1dS )8    )absolute_importdivisionprint_function)getitem)product)Integral)mergepipeconcatpartial)map   )chunkwrap)Array
map_blocksconcatenateconcatenate3reshapelist   )HighLevelGraph)tokenize)flatten)concretec             C   s   | d ft dd | dd D  }g }xtt| dd |dd D ]\}\}}||d}||kr||tddd qH||k r|td| qH||kr|dkr|tdd qH|t| d qHW t |}tdd |D r| S t||fS dS )a  

    >>> fractional_slice(('x', 5.1), {0: 2})  # doctest: +SKIP
    (getitem, ('x', 6), (slice(0, 2),))

    >>> fractional_slice(('x', 3, 5.1), {0: 2, 1: 3})  # doctest: +SKIP
    (getitem, ('x', 3, 5), (slice(None, None, None), slice(-3, None)))

    >>> fractional_slice(('x', 2.9, 5.1), {0: 2, 1: 3})  # doctest: +SKIP
    (getitem, ('x', 3, 5), (slice(0, 2), slice(-3, None)))
    r   c             s   s   | ]}t t|V  qd S )N)intround).0i r   1lib/python3.7/site-packages/dask/array/overlap.py	<genexpr>   s    z#fractional_slice.<locals>.<genexpr>r   Nc             s   s   | ]}|t d d d kV  qd S )N)slice)r   indr   r   r   r    .   s    )tuple	enumeratezipgetappendr!   allr   )ZtaskaxesZroundedindexr   trdepthr   r   r   fractional_slice   s    $,r.   Nc                s   fddg }xRt | dd D ]>\}}d}|dkr>|d7 }|| d k rV|d7 }|| q"W  fddt | dd D }|dk	r|gg| }tt| }	 fddt |D }
t|
|	}|S )	a   Get all neighboring keys around center

    Parameters
    ----------
    k: tuple
        They key around which to generate new keys
    dims: Sequence[int]
        The number of chunks in each dimension
    name: Option[str]
        The name to include in the output keys, or none to include no name
    axes: Dict[int, int]
        The axes active in the expansion.  We don't expand on non-active axes

    Examples
    --------
    >>> expand_key(('x', 2, 3), dims=[5, 5], name='y', axes={0: 1, 1: 1})  # doctest: +NORMALIZE_WHITESPACE
    [[('y', 1.1, 2.1), ('y', 1.1, 3), ('y', 1.1, 3.9)],
     [('y',   2, 2.1), ('y',   2, 3), ('y',   2, 3.9)],
     [('y', 2.9, 2.1), ('y', 2.9, 3), ('y', 2.9, 3.9)]]

    >>> expand_key(('x', 0, 4), dims=[5, 5], name='y', axes={0: 1, 1: 1})  # doctest: +NORMALIZE_WHITESPACE
    [[('y',   0, 3.1), ('y',   0,   4)],
     [('y', 0.9, 3.1), ('y', 0.9,   4)]]
    c                sN   g }|d dkr| |d  | | |d  |  d k rJ| |d  |S )Ng?r   r   )r'   )r   r"   rv)dimsr   r   indsM   s    
zexpand_key.<locals>.indsr   Nr   c                s,   g | ]$\}}  |d r"||n|gqS )r   )r&   )r   r   r"   )r)   r1   r   r   
<listcomp>_   s    zexpand_key.<locals>.<listcomp>c                s$   g | ]\}}  |d r|ndqS )r   r   )r&   )r   r   d)r)   r   r   r2   c   s    )r$   r'   listr   r   )kr0   namer)   shaper   r"   ZnumargsseqZshape2resultr   )r)   r0   r1   r   
expand_key4   s     	 
r;   c          	   C   s  t tt| j}tt||d}t|  tt|ttt	t }dt
| | }dt
| | }i }i }xv|D ]n}	t| jf|	 |}
| jf|	 |
kr|
||f|	 < qf| jf|	 ||f|	 < tt|d|	 |dff||f|	 < qfW g }xt| jD ]\}}t|dkr
|| q|d ||d g}|d ||d g}g }x0|dd D ] }||||dd	   qHW ||| |  qW t||}tj||| gd
}t|||| jdS )aK   Share boundaries between neighboring blocks

    Parameters
    ----------

    x: da.Array
        A dask array
    axes: dict
        The size of the shared boundary per axis

    The axes input informs how many cells to overlap between neighboring blocks
    {0: 2, 2: 5} means share two cells in 0 axis, 5 cells in 2 axis
    )r0   r)   zoverlap-zgetitem-)N)r6   r   r   r   )Zdependencies)dtype)r4   r   lenchunksr   r;   r	   Z__dask_keys__r   r
   r   r.   r6   r   r   r$   r'   r&   r   r   Zfrom_collectionsr   r=   )xr)   r0   Zexpand_key2Zinterior_keysr6   Zgetitem_nameZinterior_slicesZoverlap_blocksr5   Z
frac_slicer?   r   ZbdsleftrightZmidbdZdskZgraphr   r   r   overlap_internalh   s8    
$ 
rD   c             C   s&   t | j|}t| j|}t| ||dS )zTrim sides from each block.

    This couples well with the ``map_overlap`` operation which may leave
    excess data on each block.

    See also
    --------
    dask.array.overlap.map_overlap

    )r)   boundary)coerce_depthndimcoerce_boundarytrim_internal)r@   r-   rE   r)   	boundary2r   r   r   trim_overlap   s    rK   c             C   s   t | j|}g }xt| jD ]\}}||d}g }x|t|D ]p\}}	|dkrd|	||dd  }	n@|dkr||	||d n|	}	|t|d kr|	||d n|	}	||	 q>W |t| qW t|}
tt	t
||d| |
| jdS )z Trim sides from each block

    This couples well with the overlap operation, which may leave excess data on
    each block

    See also
    --------
    dask.array.chunk.trim
    dask.array.map_blocks
    noner   r   r   )r)   rE   )r?   r=   )rH   rG   r$   r?   r&   r>   r'   r#   r   r   _trimr=   )r@   r)   rE   Zolistr   rC   ZbdyZilistjr3   r?   r   r   r   rI      s    $rI   c                s    fddt | jD  dd  D }fddtt|d d  D }fddtt|d d	 |d d |D }| td
d t||D  S )zSimilar to dask.array.chunk.trim but requires one to specificy the
    boundary condition.

    ``axes``, and ``boundary`` are assumed to have been coerced.

    c                s   g | ]}  |d qS )r   )r&   )r   r   )r)   r   r   r2      s    z_trim.<locals>.<listcomp>c             s   s   | ]}|r| nd V  qd S )Nr   )r   axr   r   r   r       s    z_trim.<locals>.<genexpr>c             3   s6   | ].\}\}}|d kr*  |ddkr*d n|V  qdS )r   rL   N)r&   )r   r   chunk_locationrO   )rE   r   r   r       s   r   zchunk-locationc             3   s<   | ]4\}\}}}||d  kr0  |ddkr0dn|V  qdS )r   rL   N)r&   )r   r   r?   rP   rO   )rE   r   r   r       s   z
num-chunksc             s   s   | ]\}}t ||V  qd S )N)r!   )r   frontZbackr   r   r   r       s   )rangerG   r$   r%   r#   )r@   r)   rE   Z
block_infoZ	axes_backZ
trim_frontZ	trim_backr   )r)   rE   r   rM      s    




rM   c             C   s   t dddf| t d|f t dddf| j| d   }t dddf| t | df t dddf| j| d   }| | }| | }t||||\}}t|| |g|dS )zv Copy a slice of an array around to its other side

    Useful to create periodic boundary conditions for overlap
    Nr   r   )axis)r!   rG   _remove_overlap_boundariesr   )r@   rS   r-   rA   rB   lr,   r   r   r   periodic   s    rV   c             C   s   |dkrDt dddf| t ddf t dddf| j| d   }n@t dddf| t |d ddf t dddf| j| d   }t dddf| t d| d df t dddf| j| d   }| | }| | }t||||\}}t|| |g|dS )z\ Reflect boundaries of array on the same side

    This is the converse of ``periodic``
    r   Nr   r<   )rS   )r!   rG   rT   r   )r@   rS   r-   rA   rB   rU   r,   r   r   r   reflect   s     "$rW   c             C   s   t dddf| t ddf t dddf| j| d   }t dddf| t dddf t dddf| j| d   }t| | g| |d}t| | g| |d}t||||\}}t|| |g|dS )z Each reflect each boundary value outwards

    This mimics what the skimage.filters.gaussian_filter(... mode="nearest")
    does.
    Nr   r   r<   )rS   )r!   rG   r   rT   )r@   rS   r-   rA   rB   rU   r,   r   r   r   nearest  s    rY   c             C   sH   t | j}|f||< tjttt||t|| jd}t|| |g|dS )z, Add constant slice to either side of array )r?   r=   )rS   )	r4   r?   r   Zfullr#   r   sumr=   r   )r@   rS   r-   valuer?   cr   r   r   constant*  s
    

r]   c             C   sL   t | j}|f||< t |j}|f||< | t|} |t|}| |fS )N)r4   r?   rechunkr#   )rU   r,   rS   r-   ZlchunksZrchunksr   r   r   rT   5  s    



rT   c                s   t ts&tfddt| jD t  tsLt fddt| jD  xt| jD ]} |d}|dkrrqX|d}|dkrqXqX|dkrt| ||} qX|dkrt| ||} qX|dkrt| ||} qX|krXt| ||| } qXW | S )	zp Add boundary conditions to an array before overlaping

    See Also
    --------
    periodic
    constant
    c             3   s   | ]}| fV  qd S )Nr   )r   r   )kindr   r   r    I  s    zboundaries.<locals>.<genexpr>c             3   s   | ]}| fV  qd S )Nr   )r   r   )r-   r   r   r    K  s    r   rL   rV   rW   rY   )	
isinstancedictrR   rG   r&   rV   rW   rY   r]   )r@   r-   r_   r   r3   Z	this_kindr   )r-   r_   r   
boundaries@  s(    

rb   c       
         s   t | j|t| j| fddt| jD }x8t|| jD ](\}}|t|kr>td|t|f q>W t|  }t	|}t
 fdd D }t||}	|	S )ao   Share boundaries between neighboring blocks

    Parameters
    ----------

    x: da.Array
        A dask array
    depth: dict
        The size of the shared boundary per axis
    boundary: dict
        The boundary condition on each axis. Options are 'reflect', 'periodic',
        'nearest', 'none', or an array value.  Such a value will fill the
        boundary with that value.

    The depth input informs how many cells to overlap between neighboring
    blocks ``{0: 2, 2: 5}`` means share two cells in 0 axis, 5 cells in 2 axis.
    Axes missing from this input will not be overlapped.

    Examples
    --------
    >>> import numpy as np
    >>> import dask.array as da

    >>> x = np.arange(64).reshape((8, 8))
    >>> d = da.from_array(x, chunks=(4, 4))
    >>> d.chunks
    ((4, 4), (4, 4))

    >>> g = da.overlap.overlap(d, depth={0: 2, 1: 1},
    ...                       boundary={0: 100, 1: 'reflect'})
    >>> g.chunks
    ((8, 8), (6, 6))

    >>> np.array(g)
    array([[100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100],
           [100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100],
           [  0,   0,   1,   2,   3,   4,   3,   4,   5,   6,   7,   7],
           [  8,   8,   9,  10,  11,  12,  11,  12,  13,  14,  15,  15],
           [ 16,  16,  17,  18,  19,  20,  19,  20,  21,  22,  23,  23],
           [ 24,  24,  25,  26,  27,  28,  27,  28,  29,  30,  31,  31],
           [ 32,  32,  33,  34,  35,  36,  35,  36,  37,  38,  39,  39],
           [ 40,  40,  41,  42,  43,  44,  43,  44,  45,  46,  47,  47],
           [ 16,  16,  17,  18,  19,  20,  19,  20,  21,  22,  23,  23],
           [ 24,  24,  25,  26,  27,  28,  27,  28,  29,  30,  31,  31],
           [ 32,  32,  33,  34,  35,  36,  35,  36,  37,  38,  39,  39],
           [ 40,  40,  41,  42,  43,  44,  43,  44,  45,  46,  47,  47],
           [ 48,  48,  49,  50,  51,  52,  51,  52,  53,  54,  55,  55],
           [ 56,  56,  57,  58,  59,  60,  59,  60,  61,  62,  63,  63],
           [100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100],
           [100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100]])
    c                s   g | ]}  |d qS )r   )r&   )r   r   )depth2r   r   r2     s    zoverlap.<locals>.<listcomp>zThe overlapping depth %d is larger than your
smallest chunk size %d. Rechunk your array
with a larger chunk size or a chunk size that
more evenly divides the shape of your array.c             3   s2   | ]*\}}|  |d d kr$|d ndfV  qdS )rL   r   r   N)r&   )r   r5   v)rJ   r   r   r      s   zoverlap.<locals>.<genexpr>)rF   rG   rH   rR   r%   r?   min
ValueErrorrb   rD   ra   itemsr   trim)
r@   r-   rE   Zdepth_valuesr3   r\   Zx2Zx3rh   Zx4r   )rJ   rc   r   overlapa  s    4
ri   c             C   s   x|  D ]\}}||d}|dkr
|dkr
t| j}|||< t| j}|f||< tj||| jd}t| j}	t|	| }
|
d  |7  < |
d  |7  < t|
|	|< t	|| |g|d} | 
|	} q
W | S )a?  
    Pads an array which has 'none' as the boundary type.
    Used to simplify trimming arrays which use 'none'.

    >>> import dask.array as da
    >>> x = da.arange(6, chunks=3)
    >>> add_dummy_padding(x, {0: 1}, {0: 'none'}).compute()  # doctest: +NORMALIZE_WHITESPACE
    array([..., 0, 1, 2, 3, 4, 5, ...])
    r   rL   )r?   r=   r<   )rS   )rg   r&   r4   r7   r?   r   emptyr=   r#   r   r^   )r@   r-   rE   r5   rd   r3   Zempty_shapeZempty_chunksrj   Z
out_chunksZ	ax_chunksr   r   r   add_dummy_padding  s     




rk   Tc       
      K   s   t | j|}t| j|}tdd | jD s0tt| ||d}tdd |jD sVt|j|f|}	tdd |	jD s|t|rt|	||S |	S dS )aU   Map a function over blocks of the array with some overlap

    We share neighboring zones between blocks of the array, then map a
    function, then trim away the neighboring strips.

    Parameters
    ----------
    func: function
        The function to apply to each extended block
    depth: int, tuple, or dict
        The number of elements that each block should share with its neighbors
        If a tuple or dict then this can be different per axis
    boundary: str, tuple, dict
        How to handle the boundaries.
        Values include 'reflect', 'periodic', 'nearest', 'none',
        or any constant value like 0 or np.nan
    trim: bool
        Whether or not to trim ``depth`` elements from each block after
        calling the map function.
        Set this to False if your mapping function already does this for you
    **kwargs:
        Other keyword arguments valid in ``map_blocks``

    Examples
    --------
    >>> import numpy as np
    >>> import dask.array as da

    >>> x = np.array([1, 1, 2, 3, 3, 3, 2, 1, 1])
    >>> x = da.from_array(x, chunks=5)
    >>> def derivative(x):
    ...     return x - np.roll(x, 1)

    >>> y = x.map_overlap(derivative, depth=1, boundary=0)
    >>> y.compute()
    array([ 1,  0,  1,  1,  0,  0, -1, -1,  0])

    >>> x = np.arange(16).reshape((4, 4))
    >>> d = da.from_array(x, chunks=(2, 2))
    >>> d.map_overlap(lambda x: x + x.size, depth=1).compute()
    array([[16, 17, 18, 19],
           [20, 21, 22, 23],
           [24, 25, 26, 27],
           [28, 29, 30, 31]])

    >>> func = lambda x: x + x.size
    >>> depth = {0: 1, 1: 1}
    >>> boundary = {0: 'reflect', 1: 'none'}
    >>> d.map_overlap(func, depth, boundary).compute()  # doctest: +NORMALIZE_WHITESPACE
    array([[12,  13,  14,  15],
           [16,  17,  18,  19],
           [20,  21,  22,  23],
           [24,  25,  26,  27]])
    c             s   s$   | ]}|D ]}t |tkV  q
qd S )N)typer   )r   ccr\   r   r   r   r      s    zmap_overlap.<locals>.<genexpr>)r-   rE   c             s   s$   | ]}|D ]}t |tkV  q
qd S )N)rl   r   )r   rm   r\   r   r   r   r      s    c             s   s$   | ]}|D ]}t |tkV  q
qd S )N)rl   r   )r   rm   r\   r   r   r   r      s    N)	rF   rG   rH   r(   r?   AssertionErrorri   r   rI   )
r@   funcr-   rE   rh   kwargsrc   rJ   gZg2r   r   r   map_overlap  s    7rr   c             C   s4   t |tr|f|  }t |tr0ttt| |}|S )N)r`   r   r#   ra   r%   rR   )rG   r-   r   r   r   rF     s
    


rF   c             C   sD   |d krd}t |ttfs$|f|  }t |tr@ttt| |}|S )NrW   )r`   r#   ra   r%   rR   )rG   rE   r   r   r   rH     s    

rH   )NN)N)N)NN)NT)2Z
__future__r   r   r   operatorr   	itertoolsr   Znumbersr   Ztoolzr   r	   r
   r   Ztoolz.curriedr    r   r   Zcorer   r   r   r   r   Zhighlevelgraphr   baser   r   Zutilsr   r.   r;   rD   rK   rI   rM   rV   rW   rY   r]   rT   rb   ri   rk   rr   rF   rH   r   r   r   r   <module>   s8   "
44

 
!H 
E	