U
    /e)                     @   s   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m	Z	 d dl
Zd dlmZ d dl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lmZmZ dZdd Zdd Zdd ZdddZ dS )    N)Counter)reduce)product)mul)config)Arraynormalize_chunks)meta_from_array)tokenize)flatten)HighLevelGraph)Mparse_bytesa  
Dask's reshape only supports operations that merge or split existing dimensions
evenly. For example:

>>> x = da.ones((6, 5, 4), chunks=(3, 2, 2))
>>> x.reshape((3, 2, 5, 4))  # supported, splits 6 into 3 & 2
>>> x.reshape((30, 4))       # supported, merges 6 & 5 into 30
>>> x.reshape((4, 5, 6))     # unsupported, existing dimensions split unevenly

To work around this you may call reshape in multiple passes, or (if your data
is small enough) call ``compute`` first and handle reshaping in ``numpy``
directly.
c                    sT  t dd D sttd }t|d }dd ttD }dd tt|D }|dksl|dkrD| || kr| ||< | ||< |d8 }|d8 }qZ| }|| }|dkrd||< |d8 }qZ|dkrd||< |d8 }qZ||k rZ|d }	|	dkr.tt|	|d  |k r.|	d8 }	 qtt|	|d  |krRttt fd	dt|D rt|d D ]}
|
 ||
< q|| t	t
t|	|  ||< nt|	d |d D ]}
|
 f||
< qttt
t|	d |d  }t|	 |||	< tt|	d |d  tfd
d||	 D ||< |d8 }|	d }qZ||krZ|d }|dkrtt|||d  |k r|d8 }qjtt|||d  |krtttt||d |d   t|  ||< t|d |d D ]}
||
 f||
< qt fdd|| D ||< |d }|d8 }qZt|t|fS )Nc                 s   s   | ]}t |tV  qd S N)
isinstancetuple.0c r   6/tmp/pip-unpacked-wheel-dbjnr7gq/dask/array/reshape.py	<genexpr>"   s     z"reshape_rechunk.<locals>.<genexpr>   c                 S   s   g | ]}d qS r   r   r   ir   r   r   
<listcomp>%   s     z#reshape_rechunk.<locals>.<listcomp>c                 S   s   g | ]}d qS r   r   r   r   r   r   r   &   s     r   r   c                 3   s"   | ]}t  | | kV  qd S r   )lenr   )inchunksinshaper   r   r   B   s     c                 3   s   | ]} | V  qd S r   r   r   )prodr   r   r   P   s    c                 3   s   | ]}|  V  qd S r   r   r   )csr   r   r   d   s     )allAssertionErrorr   ranger   r   NotImplementedError_not_implemented_messagemathr    mapexpand_tupler   contract_tuple)r   Zoutshaper   iiZoiZresult_inchunksZresult_outchunksdindoutZileftr   Zchunk_reductionZoleftr   )r!   r   r   r    r   reshape_rechunk!   sv    



 
&
r.   c                 C   s~   |dkr| S g }| D ]L}|}t || d}|d| krR|t| |t|8 }q*|r|| qt| t|ksvtt|S )z

    >>> expand_tuple((2, 4), 2)
    (1, 1, 2, 2)

    >>> expand_tuple((2, 4), 3)
    (1, 1, 1, 1, 2)

    >>> expand_tuple((3, 4), 2)
    (1, 2, 2, 2)

    >>> expand_tuple((7, 4), 3)
    (2, 2, 3, 1, 1, 2)
    r      )maxappendintsumr#   r   )chunksfactoroutr   xpartr   r   r   r)   l   s    r)   c                 C   s\   t | | dkstg }d}| D ]2}||7 }|| }|| }|| }|r || q t|S )zReturn simple chunks tuple such that factor divides all elements

    Examples
    --------

    >>> contract_tuple((2, 2, 8, 4), 4)
    (4, 8, 4)
    r   )r3   r#   r1   r   )r4   r5   r6   ZresidualchunkdivZgoodr   r   r   r*      s    	r*   Tc                    s>  ddl m} ddlm} tt||}dd |D }t|t|k rt|t| dkr`tdt|dkrz| jdkrz| S || j	t
t|d  t fdd	|D }tt| jrtd
t| j t
t|d| j	krtd| j|kr| S t| t|}dt| | }| jdkrztt|  }	|fdt|  tj|	|fi}
tdd	 |D }tj||
| gd}t||||dS t| j}t|}|s||kr| dd t|| D } t| j|| j\}}t
tdd |D | j j! }|dkrt"t#$d}t#$dd}nt"|}d}||kr|dkrDd}t%j&||dd nn|rt'|t'|@ }g }|D ]:}|| dkr|(| ||  d8  < n
|(d qbt)|||| j |d}| |}t*t+|j,gfdd |D  }t*t+|gfdd |D  }t*t+| }dd t-|||D }
tj||
|gd}t||||dS ) ab  Reshape array to new shape

    Parameters
    ----------
    shape : int or tuple of ints
        The new shape should be compatible with the original shape. If
        an integer, then the result will be a 1-D array of that length.
        One shape dimension can be -1. In this case, the value is
        inferred from the length of the array and remaining dimensions.
    merge_chunks : bool, default True
        Whether to merge chunks using the logic in :meth:`dask.array.rechunk`
        when communication is necessary given the input array chunking and
        the output shape. With ``merge_chunks==False``, the input array will
        be rechunked to a chunksize of 1, which can create very many tasks.
    limit: int (optional)
        The maximum block size to target in bytes. If no limit is provided,
        it defaults to using the ``array.chunk-size`` Dask config value.

    Notes
    -----
    This is a parallelized version of the ``np.reshape`` function with the
    following limitations:

    1.  It assumes that the array is stored in `row-major order`_
    2.  It only allows for reshapings that collapse or merge dimensions like
        ``(1, 2, 3, 4) -> (1, 6, 4)`` or ``(64,) -> (4, 4, 4)``

    .. _`row-major order`: https://en.wikipedia.org/wiki/Row-_and_column-major_order

    When communication is necessary this algorithm depends on the logic within
    rechunk.  It endeavors to keep chunk sizes roughly the same when possible.

    See :ref:`array-chunks.reshaping` for a discussion the tradeoffs of
    ``merge_chunks``.

    See Also
    --------
    dask.array.rechunk
    numpy.reshape
    r   )PerformanceWarning)sanitize_indexc                 S   s   g | ]}|d kr|qS )r   r   sr   r   r   r      s      zreshape.<locals>.<listcomp>r   z&can only specify one unknown dimensionc                 3   s   | ]}|d kr n|V  qdS )r=   Nr   r>   Zmissing_sizer   r   r      s     zreshape.<locals>.<genexpr>z_Array chunk size or shape is unknown. shape: %s

Possible solution with x.compute_chunk_sizes()z)total size of new array must be unchangedzreshape-)r   c                 s   s   | ]}|fV  qd S r   r   )r   dr   r   r   r      s     )Zdependencies)metac                 S   s   i | ]
}|d qS r   r   r   r   r   r   
<dictcomp>   s      zreshape.<locals>.<dictcomp>c                 S   s   g | ]}t |qS r   )r0   r   r   r   r   r      s     Nzarray.chunk-sizez array.slicing.split-large-chunksTa  Reshaping is producing a large chunk. To accept the large
chunk and silence this warning, set the option
    >>> with dask.config.set(**{'array.slicing.split_large_chunks': False}):
    ...     array.reshape(shape)

To avoid creating the large chunks, set the option
    >>> with dask.config.set(**{'array.slicing.split_large_chunks': True}):
    ...     array.reshape(shape)Explictly passing ``limit`` to ``reshape`` will also silence this warning
    >>> array.reshape(shape, limit='128 MiB')   )
stacklevelauto)shapelimitdtypeZprevious_chunksc                 S   s   g | ]}t t|qS r   r$   r   r   r   r   r   r   &  s     c                 S   s   g | ]}t t|qS r   rJ   r   r   r   r   r   '  s     c                 S   s    i | ]\}}}|t j||fqS r   )r   reshape)r   abrG   r   r   r   rC   )  s      ).dask.array.corer;   Zdask.array.slicingr<   r   r(   r   
ValueErrorndimsizer   r   npisnanr3   rG   strr	   r
   Znpartitionsnextr   Z__dask_keys__r   rK   r   Zfrom_collectionsr   Zrechunkr$   r.   r4   rI   itemsizer   r   getwarningswarnr   r1   r   listr   namezip)r7   rG   Zmerge_chunksrH   r;   r<   Zknown_sizesrB   r[   keyZdskr4   graphr,   r-   r   Z	outchunksZmax_chunksize_in_bytessplitmsgZmatching_chunksZ
chunk_planr6   Zx2Zin_keysZout_keysZshapesr   r@   r   rK      s    *






 rK   )TN)!r'   rX   collectionsr   	functoolsr   	itertoolsr   operatorr   ZnumpyrR   Zdaskr   rN   r   r   Zdask.array.utilsr	   Z	dask.baser
   Z	dask.corer   Zdask.highlevelgraphr   Z
dask.utilsr   r   r&   r.   r)   r*   rK   r   r   r   r   <module>   s$   K