a
    tDf&2                     @  s  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	 d dl
Zd dlmZ d dlmZ d d	lmZmZmZ d d
lmZmZ d dlmZmZ d dlmZ d dlmZmZmZ d dl m!Z! eeeefZ"eefZ#ddefdfddZ$dd Z%ddddZ&dd Z'dd Z(dd Z)dd Z*dS )     )annotations)Callable)zip_longest)Integral)AnyN)config)getitem)gettergetter_inlinegetter_nofancy)
fuse_rootsoptimize_blockwise)flattenreverse_dict)HighLevelGraph)SubgraphCallablefuseinline_functions)ensure_dictTc           	      K  s   t |ttfs|g}tt|}t | ts>tjt| | dd} t| |d} t| |d} | 	t|} t
ddu rv| S |  }t| } |dur|}t| |}t| || |pg  ||d\} }|rt| |||d} t| S )	zOptimize dask for array computation

    1.  Cull tasks not necessary to evaluate keys
    2.  Remove full slicing, e.g. x[:]
    3.  Inline fast functions like getitem and np.transpose
     )dependencies)keyszoptimization.fuse.activeFN)Zrename_keys)r   fast_functions)
isinstancelistsetr   r   Zfrom_collectionsidr   r   Zcullr   getZget_all_dependenciesr   	hold_keysr   r   optimize_slices)	dskr   Z	fuse_keysr   Zinline_functions_fast_functionsZrename_fused_keyskwargsr   Zholdr   r   d/nfs/NAS7/SABIOD/METHODE/ermites/ermites_venv/lib/python3.9/site-packages/dask/array/optimization.pyoptimize   s:    


r#   c                 C  s   t |}dd |  D }t|}|D ]}|| }|D ]|}| | }t|r6zFt|| dkrtt|| }	| |	 }
t|
s|
| v r|	}qLqqLW n ttfy   Y n0 |	| q6q&|S )a"  Find keys to avoid fusion

    We don't want to fuse data present in the graph because it is easier to
    serialize as a raw value.

    We don't want to fuse chains after getitem/GETTERS because we want to
    move around only small pieces of data, rather than the underlying arrays.
    c                 S  s$   h | ]\}}t |ttfvr|qS r   )typetuplestr).0kvr   r   r"   	<setcomp>^       zhold_keys.<locals>.<setcomp>   )
r   itemsr   _is_getter_tasklennextiter
IndexError	TypeErrorappend)r    r   Z
dependentsdatar   ZdatdepsdepZtaskZnew_depZnew_taskr   r   r"   r   T   s&    	r   z3tuple[Callable, Any, Any, bool, bool | None] | None)returnc                 C  s   t | turdS | d }d}|tv r*|}nVt|trt|jdkrtt|j	 }t |tu rt|dkr|d tv r|d }|du rdS t| }|dkr|| d | d |t
udfS |dkr|g| dd R S dS )a  Check if a value in a Dask graph looks like a getter.

    1. Is it a tuple with the first element a known getter.
    2. Is it a SubgraphCallable with a single element in its
       dsk which is a known getter.

    If a getter is found, it returns a tuple with (getter, array, index, asarray, lock).
    Otherwise it returns ``None``.

    TODO: the second check is a hack to allow for slice fusion between tasks produced
    from blockwise layers and slicing operations. Once slicing operations have
    HighLevelGraph layers which can talk to Blockwise layers this check *should* be
    removed, and we should not have to introspect SubgraphCallables.
    Nr   r,            )r$   r%   GETTERSr   r   r/   r    r0   r1   valuesr   )valuefirstr   r)   lengthr   r   r"   r.   z   s$    $r.   c              	     s  t tjf |  } |  D ]\}}t| }r|\}}}}}t| }	rd|	\}
}}}}|rj||urjqdt|tu t|tu krqdt|tu r|| }t|t|krt	dd |D rqd|
t
u rt	 fdd|D rqdn*|
t
u rt| v sdt| v rqdz t||}|
tu r(tn|
}W n tyH   Y qdY n0 |||  }}}||O }q>|tvrt|tu r|js|jdu r|jdu st|tu rtdd |D r|| |< q|tu s|r|s|||f| |< q|||||f| |< q| S )zOptimize slices

    1.  Fuse repeated slices, like x[5:][2:6] -> x[7:11]
    2.  Remove full slices, like         x[:] -> x

    See also:
        fuse_slice_dict
    c                 s  s   | ]}|d u V  qd S Nr   r'   ir   r   r"   	<genexpr>   r+   z"optimize_slices.<locals>.<genexpr>c                 3  s   | ]}t | V  qd S rA   )r   rB   Zfancy_ind_typesr   r"   rD      s   Nc                 s  s6   | ].}t |tu o,|j o,|jd u o,|jd u V  qd S rA   )r$   slicestartstopstep)r'   sr   r   r"   rD      s   )r   npZndarraycopyr-   r.   r$   r%   r/   anyr   
fuse_slicer
   r	   NotImplementedErrorGETNOREMOVErF   rG   rH   rI   allr   )r    r(   r)   Za_taskr   aZa_indexZ	a_asarrayZa_lockZb_taskf2bZb_indexZ	b_asarrayZb_lockindicesZc_indexr   rE   r"   r      sh    	
"







	
r   c                 C  s`   | j | j| j  }}}|du r"d}|du r.d}|dk sN|dk sN|durT|dk rTt t|||S )zrReplace Nones in slices with integers

    >>> normalize_slice(slice(None, None, None))
    slice(0, None, 1)
    Nr   r,   )rG   rH   rI   rO   rF   )rJ   rG   rH   rI   r   r   r"   normalize_slice   s     rV   c                 C  s>   t | |td dD ]&\}}t|turt|trtdqd S )N)	fillvaluezCan't handle normal indexing with integers and fancy indexing if the integers and fancy indices don't align with the same dimensions.)r   rF   r$   r   r   r   rO   )Zfancynormalfnr   r   r"   #check_for_nonfusible_fancy_indexing  s
    r[   c           
        s   du r$t |tr$|tddkr$dS t  tr6t  t |trHt|}t  trzt |trz|dk rjt  j| j  S t  trt |tr j j|j  }|jdur j j|j  }nd} jdur|durt j|}n j} j|j }|dkrd}t|||S t |t	r0 fdd|D S t  t	rTt |ttfrT | S t  t
rrt |t
sr|f}t  t
rt |t
rtdd  D }tdd |D }|r|rtd	n"|rt | n|rt|  d}t	 }tt D ]z}	t  |	 ts|t|kr0| |	  q|| du rT|d |d7 }q0|t |	 ||  |d7 }q|t|k r|||  |d7 }qxt
|S t dS )
a  Fuse stacked slices together

    Fuse a pair of repeated slices into a single slice:

    >>> fuse_slice(slice(1000, 2000), slice(10, 15))
    slice(1010, 1015, None)

    This also works for tuples of slices

    >>> fuse_slice((slice(100, 200), slice(100, 200, 10)),
    ...            (slice(10, 15), [5, 2]))
    (slice(110, 115, None), [150, 120])

    And a variety of other interesting cases

    >>> fuse_slice(slice(1000, 2000), 10)  # integers
    1010

    >>> fuse_slice(slice(1000, 2000, 5), slice(10, 20, 2))
    slice(1050, 1100, 10)

    >>> fuse_slice(slice(1000, 2000, 5), [1, 2, 3])  # lists
    [1005, 1010, 1015]

    >>> fuse_slice(None, slice(None, None))  # doctest: +SKIP
    None
    Nr   r,   c                   s   g | ]}t  |qS r   )rN   )r'   ZbbrR   r   r"   
<listcomp>N  r+   zfuse_slice.<locals>.<listcomp>c                 s  s   | ]}t |tV  qd S rA   r   r   r'   itemr   r   r"   rD   Y  r+   zfuse_slice.<locals>.<genexpr>c                 s  s   | ]}t |tV  qd S rA   r^   r_   r   r   r"   rD   Z  r+   z#Can't handle multiple list indexing)r   rF   rV   r   rO   rG   rI   rH   minr   r%   rM   r[   ranger/   r4   rN   )
rR   rT   rG   rH   rI   Za_has_listsZb_has_listsjresultrC   r   r\   r"   rN     sl     







rN   )+
__future__r   collections.abcr   	itertoolsr   Znumbersr   typingr   numpyrK   Zdaskr   Zdask.array.chunkr   Zdask.array.corer	   r
   r   Zdask.blockwiser   r   Z	dask.corer   r   Zdask.highlevelgraphr   Zdask.optimizationr   r   r   Z
dask.utilsr   r<   rP   r#   r   r.   r   rV   r[   rN   r   r   r   r"   <module>   s4   
9&+M