a
    tDf*                     @  s   d dl m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
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 )    )annotationsN)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J 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   _/nfs/NAS7/SABIOD/METHODE/ermites/ermites_venv/lib/python3.9/site-packages/dask/array/reshape.py	<genexpr>$       z"reshape_rechunk.<locals>.<genexpr>   c                 S  s   g | ]}d qS r   r   r   ir   r   r   
<listcomp>'   r   z#reshape_rechunk.<locals>.<listcomp>c                 S  s   g | ]}d qS r   r   r   r   r   r   r   (   r   r   r   c                 3  s"   | ]}t  | | kV  qd S r   )lenr   )inchunksinshaper   r   r   D   r   c                 3  s   | ]} | V  qd S r   r   r   )prodr   r   r   R   s   c                 3  s   | ]}|  V  qd S r   r   r   )csr   r   r   f   r   )allr   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svJ 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   )chunksfactoroutr   xpartr   r   r   r*   n   s    r*   c                 C  s\   t | | dksJ 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   )r4   r2   r   )r5   r6   r7   ZresidualchunkdivZgoodr   r   r   r+      s    	r+   Tc                   sB  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u rt"t#$d}t#$dd}nt"|}d}||kr|du rDd}t%j&||dd nn|rt'|t'|@ }g }|D ]:}|| dkr|(| ||  d8  < n
|(d qbt)|||| j |d}| |}t*t+|j,ggdd |D R  }t*t+|ggdd |D R  }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      r   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      r   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      r   )Zdependencies)metac                 S  s   i | ]
}|d qS r   r   r   r   r   r   
<dictcomp>   r   zreshape.<locals>.<dictcomp>c                 S  s   g | ]}t |qS r   )r1   r   r   r   r   r      r   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)Explicitly 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   (  r   c                 S  s   g | ]}t t|qS r   rK   r   r   r   r   r   )  r   c                 S  s    i | ]\}}}|t j||fqS r   )r   reshape)r   abrH   r   r   r   rD   +  r   ).dask.array.corer<   Zdask.array.slicingr=   r   r)   r   
ValueErrorndimsizer   r   npisnanr4   rH   strr
   r   Znpartitionsnextr   Z__dask_keys__r   rL   r   Zfrom_collectionsr   Zrechunkr%   r/   r5   rJ   itemsizer   r   getwarningswarnr   r2   r	   listr   namezip)r8   rH   Zmerge_chunksrI   r<   r=   Zknown_sizesrC   r\   keyZdskr5   graphr-   r.   r    Z	outchunksZmax_chunksize_in_bytessplitmsgZmatching_chunksZ
chunk_planr7   Zx2Zin_keysZout_keysZshapesr   rA   r   rL      s    *






" rL   )TN)#
__future__r   r(   rY   collectionsr   	functoolsr   	itertoolsr   operatorr   numpyrS   Zdaskr   rO   r   r	   Zdask.array.utilsr
   Z	dask.baser   Z	dask.corer   Zdask.highlevelgraphr   Z
dask.utilsr   r   r'   r/   r*   r+   rL   r   r   r   r   <module>   s&   K