o
    Nrf&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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 r;| S |  }t| } |durI|}t| |}t| || |pVg  ||d\} }|rht| |||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   `/var/www/html/software/conda/envs/catlas/lib/python3.10/site-packages/dask/array/optimization.pyoptimize   s:   


r#   c                 C  s   t |}dd |  D }t|}|D ]N}|| }|D ]E}| | }t|r`z*t|| dkrNtt|| }	| |	 }
t|
sB|
| v rE|	}nnt|| dks.W n ttfyZ   Y nw |	| qq|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>^   s   $ zhold_keys.<locals>.<setcomp>   )
r   itemsr   _is_getter_tasklennextiter
IndexError	TypeErrorappend)r    r   Z
dependentsdatar   ZdatdepsdeptaskZnew_depnew_taskr   r   r"   r   T   s0   		
r   return3tuple[Callable, Any, Any, bool, bool | None] | Nonec                 C  s   t | turdS | d }d}|tv r|}n+t|tr@t|jdkr@tt|j	 }t |tu r@t|dkr@|d tv r@|d }|du rFdS t| }|dkr[|| d | d |t
udfS |dkri|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    r/   r0   valuesr   )valuefirstr   r)   lengthr   r   r"   r-   z   s$   $r-   c              	     s  t tjf |  } |  D ]\}}t| }r|\}}}}}t| }	r|	\}
}}}}|r2||ur2nvt|tu t|tu kr?nit|tu rl|| }t|t|kr[t	dd |D r[nM|
t
u rkt	 fdd|D rkn=n|
t
u r}t| v s|t| v r}n+zt||}|
tu rtn|
}W n	 ty   Y nw |||}}}||O }t| }	s$|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>   s    z"optimize_slices.<locals>.<genexpr>c                 3  s    | ]}t | V  qd S rC   )r   rD   Zfancy_ind_typesr   r"   rF      s    

Nc                 s  s8    | ]}t |tu o|j o|jd u o|jd u V  qd S rC   )r$   slicestartstopstep)r'   sr   r   r"   rF      s    
)r   npZndarraycopyr,   r-   r$   r%   r.   anyr   
fuse_slicer
   r	   NotImplementedErrorGETNOREMOVErH   rI   rJ   rK   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   rG   r"   r      sb   
	"




r   c                 C  s`   | j | j| j}}}|du rd}|du rd}|dk s'|dk s'|dur*|dk r*t t|||S )zrReplace Nones in slices with integers

    >>> normalize_slice(slice(None, None, None))
    slice(0, None, 1)
    Nr   r+   )rI   rJ   rK   rQ   rH   )rL   rI   rJ   rK   r   r   r"   normalize_slice   s    rX   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   rH   r$   r   r   r   rQ   )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rt  t |tr$t|}t  tr=t |tr=|dk r5t  j| j  S t  trt |tr j j|j  }|jdur_ j j|j  }nd} jdurt|durqt j|}n j} j|j }|dkrd}t|||S t |t	r fdd|D S t  t	rt |ttfr | S t  t
rt |t
s|f}t  t
rOt |t
rOtdd  D }tdd |D }|r|rtd	|rt | n|rt|  d}t	 }tt D ]@}	t  |	 ts|t|kr
| |	  q|| du r!|d |d7 }|| du s|t |	 ||  |d7 }q|t|k rK|||  |d7 }|t|k s9t
|S t )
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   )rP   )r'   ZbbrT   r   r"   
<listcomp>N  s    zfuse_slice.<locals>.<listcomp>c                 s      | ]}t |tV  qd S rC   r   r   r'   itemr   r   r"   rF   Y      zfuse_slice.<locals>.<genexpr>c                 s  ra   rC   rb   rc   r   r   r"   rF   Z  re   z#Can't handle multiple list indexing)r   rH   rX   r   rQ   rI   rK   rJ   minr   r%   rO   r^   ranger.   r3   rP   )
rT   rV   rI   rJ   rK   Za_has_listsZb_has_listsjresultrE   r   r_   r"   rP     sp    







rP   )r9   r:   )+
__future__r   collections.abcr   	itertoolsr   numbersr   typingr   numpyrM   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>   rR   r#   r   r-   r   rX   r^   rP   r   r   r   r"   <module>   s6    
9
&+M