o
    Nrf                     @  s4  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mZmZ d dlmZmZ d dlmZmZmZmZmZmZmZ d d	lmZmZ d
d Zdd Zd'ddZdd Zd(ddZ 	d)ddZ!dd Z"dd Z#d*ddZ$G dd  d eZ%e%j&Z'dde'e'e'e'e'e'fd!d"Z(d#d$ Z)G d%d& d&Z*dS )+    )annotationsN)Iterable)Enum)Any)configcoreutils)normalize_tokentokenize)flattenget_dependencies
ishashableistaskreverse_dictsubstoposort)GraphKeyc           
      C  s   t |ttfs
|g}t }t }i }ttt|}|rKg }|D ]&}t| |dd}| | ||< |||< |D ]}	|	|vrE||	 ||	 q5q |}|s||fS )a<  Return new dask with only the tasks required to calculate keys.

    In other words, remove unnecessary tasks from dask.
    ``keys`` may be a single key or list of keys.

    Examples
    --------
    >>> def inc(x):
    ...     return x + 1

    >>> def add(x, y):
    ...     return x + y

    >>> d = {'x': 1, 'y': (inc, 'x'), 'out': (add, 'x', 10)}
    >>> dsk, dependencies = cull(d, 'out')
    >>> dsk                                                     # doctest: +ELLIPSIS
    {'out': (<function add at ...>, 'x', 10), 'x': 1}
    >>> dependencies                                            # doctest: +ELLIPSIS
    {'out': ['x'], 'x': []}

    Returns
    -------
    dsk: culled dask graph
    dependencies: Dict mapping {key: [deps]}.  Useful side effect to accelerate
        other optimizations, notably fuse.
    Tas_list)
isinstancelistsetdictr   r   addappend)
dskkeysseendependenciesoutworknew_workkZdependencies_kd r%   Z/var/www/html/software/conda/envs/catlas/lib/python3.10/site-packages/dask/optimization.pycull   s*   

r'   c                 C  s   t | d }|tu r"dd | ddd D }|| d  d|S |tu rZt| d dkrZt| d d trZdd | ddd D }|| d d  d|f| d dd  S dS )	zCreate new keys for fused tasksr   c                 S     g | ]}t |qS r%   r   	key_split.0xr%   r%   r&   
<listcomp>N       z5default_fused_linear_keys_renamer.<locals>.<listcomp>N-c                 S  r(   r%   r)   r+   r%   r%   r&   r.   R   r/      )typestrr   jointuplelenr   )r   typnamesr%   r%   r&   !default_fused_linear_keys_renamerJ   s   
*r:   Tc                   s:  |durt |tst |ts|g}tt|}|du r$ fdd D }i }t } D ]<}|| }t|dk}|D ]-}	|durI|	|v rI||	 q9|	|v rV||	= ||	 q9|r^||	 q9|	|vrf|||	< q9q+g }
ttt|	 }|r|
 \}	}|	|g}||v r||}||= || ||v s|  |	|v r||	}	||	= ||	 |	|v s|
| |sudd |	 D }|du rt}n	|du rd}n|}i }t }t }d}|
D ]l}|dur||}|duo| vo||v}| }	 |	 }|r | }|| ||	 || |	 t | |	|}||	 |}	|s||	 |rA|||< |||	< ||	 ||< |h||	< ||	 q|||	< qو 	 D ]\}}||vrW|||< qJ|r|	 D ]%\}}||@ D ]}|| }|| || t|| ||||< qhq`|dur|| D ]	}||= ||= q||fS )a  Return new dask graph with linear sequence of tasks fused together.

    If specified, the keys in ``keys`` keyword argument are *not* fused.
    Supply ``dependencies`` from output of ``cull`` if available to avoid
    recomputing dependencies.

    **This function is mostly superseded by ``fuse``**

    Parameters
    ----------
    dsk: dict
    keys: list
    dependencies: dict, optional
        {key: [list-of-keys]}.  Must be a list to provide count of each key
        This optional input often comes from ``cull``
    rename_keys: bool or func, optional
        Whether to rename fused keys with ``default_fused_linear_keys_renamer``
        or not.  Renaming fused keys can keep the graph more understandable
        and comprehensive, but it comes at the cost of additional processing.
        If False, then the top-most key will be used.  For advanced usage, a
        func is also accepted, ``new_key = rename_keys(fused_key_list)``.

    Examples
    --------
    >>> def inc(x):
    ...     return x + 1

    >>> def add(x, y):
    ...     return x + y

    >>> d = {'a': 1, 'b': (inc, 'a'), 'c': (inc, 'b')}
    >>> dsk, dependencies = fuse(d)
    >>> dsk # doctest: +SKIP
    {'a-b-c': (inc, (inc, 1)), 'c': 'a-b-c'}
    >>> dsk, dependencies = fuse(d, rename_keys=False)
    >>> dsk # doctest: +ELLIPSIS
    {'c': (<function inc at ...>, (<function inc at ...>, 1))}
    >>> dsk, dependencies = fuse(d, keys=['b'], rename_keys=False)
    >>> dsk  # doctest: +ELLIPSIS
    {'b': (<function inc at ...>, 1), 'c': (<function inc at ...>, 'b')}

    Returns
    -------
    dsk: output graph with keys fused
    dependencies: dict mapping dependencies after fusion.  Useful side effect
        to accelerate other downstream optimizations.
    Nc                      i | ]
}|t  |d dqS Tr   r   r,   r#   r   r%   r&   
<dictcomp>       zfuse_linear.<locals>.<dictcomp>r2   c                 S     i | ]	\}}|t |qS r%   r   r,   r#   vr%   r%   r&   r@          TF)r   r   r   r   r7   r   r   mapreverseditemspopitempopr   reverser:   updateremover   )r   r   r   rename_keyschild2parent	unfusibleparentdepshas_many_childrenchildchainsparent2childchainkey_renamerrvZfusedaliasesZ
is_renamedZnew_keyvalkeyold_keyr%   r?   r&   fuse_linearY   s   0














r_   c                 C  s8   | d u rt  S t| t r| S t| tt fs| g} t | S N)r   r   r   )r-   r%   r%   r&   	_flat_set   s   
ra   c                   s0   rt tt  trdd   D  t|} du r'fddD  |r8| fdd D  tfdd|D  d}i }|D ]&}| }| | @ D ]}||v r`|| }	n| }	t	|||	}qU|||< qI|
 }
 D ]\}}||
vr| | @ D ]
}t	|||| }q||
|< qx|
S )	a  Return new dask with the given keys inlined with their values.

    Inlines all constants if ``inline_constants`` keyword is True. Note that
    the constant keys will remain in the graph, to remove them follow
    ``inline`` with ``cull``.

    Examples
    --------
    >>> def inc(x):
    ...     return x + 1

    >>> def add(x, y):
    ...     return x + y

    >>> d = {'x': 1, 'y': (inc, 'x'), 'z': (add, 'x', 'y')}
    >>> inline(d)       # doctest: +ELLIPSIS
    {'x': 1, 'y': (<function inc at ...>, 1), 'z': (<function add at ...>, 1, 'y')}

    >>> inline(d, keys='y') # doctest: +ELLIPSIS
    {'x': 1, 'y': (<function inc at ...>, 1), 'z': (<function add at ...>, 1, (<function inc at ...>, 1))}

    >>> inline(d, keys='y', inline_constants=False) # doctest: +ELLIPSIS
    {'x': 1, 'y': (<function inc at ...>, 'x'), 'z': (<function add at ...>, 'x', (<function inc at ...>, 'x'))}
    c                 S  rB   r%   rC   rD   r%   r%   r&   r@     rF   zinline.<locals>.<dictcomp>Nc                      i | ]}|t  |qS r%   r=   r>   r?   r%   r&   r@         c                 3  s8    | ]\}}t |r|v s | st|s|V  qd S r`   )r   r   rD   r   r   r%   r&   	<genexpr>  s    zinline.<locals>.<genexpr>c                   s   i | ]}| v r| | qS r%   r%   r>   r?   r%   r&   r@     s    )r   )r   nextitervaluesr   rI   ra   rM   r   r   copy)r   r   inline_constantsr   ZreplaceorderZkeysubsr]   r\   depreplaceZdsk2itemr%   rd   r&   inline   s:   

rn   Fc                   s   sS t t |du rfddD }t| fdd fdd D }|rBt|||d|D ]}|= q<S )	a  Inline cheap functions into larger operations

    Examples
    --------
    >>> inc = lambda x: x + 1
    >>> add = lambda x, y: x + y
    >>> double = lambda x: x * 2
    >>> dsk = {'out': (add, 'i', 'd'),  # doctest: +SKIP
    ...        'i': (inc, 'x'),
    ...        'd': (double, 'y'),
    ...        'x': 1, 'y': 1}
    >>> inline_functions(dsk, [], [inc])  # doctest: +SKIP
    {'out': (add, (inc, 'x'), 'd'),
     'd': (double, 'y'),
     'x': 1, 'y': 1}

    Protect output keys.  In the example below ``i`` is not inlined because it
    is marked as an output key.

    >>> inline_functions(dsk, ['i', 'out'], [inc, double])  # doctest: +SKIP
    {'out': (add, 'i', (double, 'y')),
     'i': (inc, 'x'),
     'x': 1, 'y': 1}
    Nc                   rb   r%   r=   r>   r?   r%   r&   r@   Y  rc   z$inline_functions.<locals>.<dictcomp>c                   s&   zt |  W S  ty   Y dS w )NF)functions_ofissubset	TypeError)rE   )fast_functionsr%   r&   	inlinable\  s
   z#inline_functions.<locals>.inlinablec                   s4   g | ]\}}t |r | r|vr|r|qS r%   )r   rD   )
dependentsrs   outputr%   r&   r.   b  s    z$inline_functions.<locals>.<listcomp>)rj   r   )r   r   rI   rn   )r   ru   rr   rj   r   r   r#   r%   )rt   r   rr   rs   ru   r&   inline_functions6  s$   rv   c                 C  s   t | dr| j} t | ds| S )Nfunc)hasattrrw   )rw   r%   r%   r&   unwrap_partialq  s   

ry   c                 C  sv   t  }| g}tth}|r9g }|D ]$} t| |v r4t| r/|t| d  || dd  q||  q|}|s|S )a1  Set of functions contained within nested task

    Examples
    --------
    >>> inc = lambda x: x + 1
    >>> add = lambda x, y: x + y
    >>> mul = lambda x, y: x * y
    >>> task = (add, (mul, 1, 2), (inc, 3))  # doctest: +SKIP
    >>> functions_of(task)  # doctest: +SKIP
    set([add, mul, inc])
    r   r2   N)r   r   r6   r3   r   r   ry   extend)taskfuncsr!   Zsequence_typesr"   r%   r%   r&   ro   w  s   
ro   x   c           	        s  t | }t|}t|} r d8   fdd}|tu r?t|}dd |D }|| t|}|| d	|}||S |t
u r|t|dkr~t|d trt|}dd |D }|| t|}||d  d	|}||f|d	d
  S d
S d
S d
S )zCreate new keys for ``fuse`` tasks.

    The optional parameter `max_fused_key_length` is used to limit the maximum string length for each renamed key.
    If this parameter is set to `None`, there is no limit.
       c                   s>    rt |  krt| dd d }| d    d| } | S )Nr-      r1   )r7   hash)Zkey_nameZ	name_hashmax_fused_key_lengthr%   r&   _enforce_max_key_limit  s   z:default_fused_keys_renamer.<locals>._enforce_max_key_limitc                 S     h | ]}t |qS r%   r)   r>   r%   r%   r&   	<setcomp>  r/   z-default_fused_keys_renamer.<locals>.<setcomp>r1   r   c                 S  r   r%   r)   r>   r%   r%   r&   r     r/   r2   N)rH   rf   r3   r4   r   r*   discardsortedr   r5   r6   r7   r   )	r   r   itZ	first_keyr8   r   Z
first_namer9   Zconcatenated_namer%   r   r&   default_fused_keys_renamer  s.   



"


r   c                   @  s   e Zd ZdZdddZdS )Defaultr   returnr4   c                 C  s   dS )Nz	<default>r%   selfr%   r%   r&   __repr__  s   zDefault.__repr__Nr   r4   )__name__
__module____qualname__tokenr   r%   r%   r%   r&   r     s    r   c	           >   
     s  t ddu r |fS |dur"t|ts"t|ts|g}tt|}|tu r1t d}|tus1J |tu r@t d}|tus@J |tu rOt d}|tusOJ |du rW|d }|tu rft d}|tusfJ |du rud|t|d	   }|tu rt d
}|tusJ |du rd}|r|s |fS |tu rt d}|tusJ |du rt	}	n|du rd}	n
t
|std|}	|	du}|du rˇ fdd D }
n fdd| D }
i }|
 D ] \}}|D ]}||vr|g||< q|| | qt||
|< qdd | D }|r||8 }  D ]\}}t|tur*t|tjtfs*|| q|sB|r>tdd | D rB |
fS   }i }g }g }|
j}|j}|j}|j}|j}|j}|j}|j}|j}|j}|r| }|| ||v r|| d }||v sy|| |||
| @  	 |d }||kr||
| @ } | r||  |}|d }||
| @ } | s|  |||| |r|gndd	d	d	d|
| | f n@|  |
| }!|!| }"|!|" } t| }#|#d	kr| \}$}%}&}'}(})}*}+t|+},|*|,d	   krdkrn n|,d	 }*|"|+O }"t|"|,k}-|-s|*d	7 }*|)|* |' |kr|-s0|'|k rt | |$|%}.|!|$ |!||$O }!||$= ||$ |r[|&| |&||< ||$d |r|-ro|||.|&|'|(|)|*|"f n|||.|&|'d	 |(|)d	 |*|"f n|.||< n|%||$< ||$ |r|*t|d	 krt|d	 }*|||| |r|gndd	|(d	|*|"f nVn\g }&d	}'d}(d}/d})d}*t }+d}0||# d }1||# d= |1D ]7\}2}2}2}3}4}5}6}7|3d	kr|/d	7 }/n|3|'kr|3}'|(|47 }(|)|57 })|*|67 }*t|7|0krt|7}0|+|7O }+qt|+},|*t|#d	 td|,|0 7 }*|*|,d	   kr1dkr7n n|,d	 }*|"|+O }"t|"|,k}-|-sH|*d	7 }*|)|* |' |kr|/|kr|(|kr|'|kr|-sh|'|k rʈ | }.t }8|1D ]+}9|9d }:t|.|:|9d	 }.||:= |8||:O }8||: |r||:d |&|9d  qq|!| 8 }!|!|8O }!|r|&| |&||< |r|||.|&|'d	 |(|)d	 |*|"f nH|.||< nK|1D ]}9|9d	 ||9d < ||9d  q|r|(|kr|}(|*t|d	 krt|d	 }*|||| |r|gndd	|(d	|*|"f nn|| d }q|sm|r#t |||
|| |	rS| D ](\};}<|	|<}=|=durQ|=|vrQ||; ||=< |=||;< |
|; |
|=< |=h|
|;< q*||
fS )am  Fuse tasks that form reductions; more advanced than ``fuse_linear``

    This trades parallelism opportunities for faster scheduling by making tasks
    less granular.  It can replace ``fuse_linear`` in optimization passes.

    This optimization applies to all reductions--tasks that have at most one
    dependent--so it may be viewed as fusing "multiple input, single output"
    groups of tasks into a single task.  There are many parameters to fine
    tune the behavior, which are described below.  ``ave_width`` is the
    natural parameter with which to compare parallelism to granularity, so
    it should always be specified.  Reasonable values for other parameters
    will be determined using ``ave_width`` if necessary.

    Parameters
    ----------
    dsk: dict
        dask graph
    keys: list or set, optional
        Keys that must remain in the returned dask graph
    dependencies: dict, optional
        {key: [list-of-keys]}.  Must be a list to provide count of each key
        This optional input often comes from ``cull``
    ave_width: float (default 1)
        Upper limit for ``width = num_nodes / height``, a good measure of
        parallelizability.
        dask.config key: ``optimization.fuse.ave-width``
    max_width: int (default infinite)
        Don't fuse if total width is greater than this.
        dask.config key: ``optimization.fuse.max-width``
    max_height: int or None (default None)
        Don't fuse more than this many levels. Set to None to dynamically
        adjust to ``1.5 + ave_width * log(ave_width + 1)``.
        dask.config key: ``optimization.fuse.max-height``
    max_depth_new_edges: int or None (default None)
        Don't fuse if new dependencies are added after this many levels.
        Set to None to dynamically adjust to ave_width * 1.5.
        dask.config key: ``optimization.fuse.max-depth-new-edges``
    rename_keys: bool or func, optional (default True)
        Whether to rename the fused keys with ``default_fused_keys_renamer``
        or not.  Renaming fused keys can keep the graph more understandable
        and comprehensive, but it comes at the cost of additional processing.
        If False, then the top-most key will be used.  For advanced usage, a
        function to create the new name is also accepted.
        dask.config key: ``optimization.fuse.rename-keys``
    fuse_subgraphs : bool or None, optional (default None)
        Whether to fuse multiple tasks into ``SubgraphCallable`` objects.
        Set to None to let the default optimizer of individual dask collections decide.
        If no collection-specific default exists, None defaults to False.
        dask.config key: ``optimization.fuse.subgraphs``

    Returns
    -------
    dsk
        output graph with keys fused
    dependencies
        dict mapping dependencies after fusion.  Useful side effect to accelerate other
        downstream optimizations.
    zoptimization.fuse.activeFNzoptimization.fuse.ave-widthzoptimization.fuse.max-heightz%optimization.fuse.max-depth-new-edgesg      ?zoptimization.fuse.max-widthr2   zoptimization.fuse.subgraphszoptimization.fuse.rename-keysTz)rename_keys must be a boolean or callablec                   r;   r<   r=   r>   r?   r%   r&   r@   ?  rA   zfuse.<locals>.<dictcomp>c                   s.   i | ]\}}|t |tr|nt |d dqS r<   )r   r   r   rD   r?   r%   r&   r@   A  s    c                 S  s    h | ]\}}t |d kr|qS )r2   )r7   )r,   r#   valsr%   r%   r&   r   O  s     zfuse.<locals>.<setcomp>c                 s  s     | ]}t t|d kV  qdS )r2   N)r7   r   )r,   rE   r%   r%   r&   re   X  s    zfuse.<locals>.<genexpr>r   r0      )!r   getr   r   r   r   _defaultmathlogr   callablerq   rI   r   r3   r6   numbersNumberr4   r   allrh   ri   rK   r   rN   rz   r7   r   intminmax_inplace_fuse_subgraphs)>r   r   r   Z	ave_width	max_width
max_heightZmax_depth_new_edgesrO   Zfuse_subgraphsrY   rS   Zrdepsr#   r   rE   Z	reduciblerZ   fused_treesZ
info_stackZchildren_stackZdeps_popZreducible_addZreducible_popZreducible_removeZfused_trees_popZinfo_stack_appendZinfo_stack_popZchildren_stack_appendZchildren_stack_extendZchildren_stack_poprR   rU   childrenZdeps_parentedgesZnum_childrenZ	child_keyZ
child_taskZ
child_keysheightwidthZ	num_nodesZfudgeZchildren_edgesZnum_children_edgesZno_new_edgesr\   Znum_single_nodesZmax_num_edgesZchildren_info_Z
cur_heightZ	cur_widthZcur_num_nodesZ	cur_fudgeZ	cur_edgesZchildren_depsZ
child_infoZ	cur_childZroot_keyZ
fused_keysaliasr%   r?   r&   fuse  s^  H







 






 







 






  y
r   c                   s  i }t  } D ]<}|| }t|dk}	|D ]-}
|dur%|
|v r%||
 q|
|v r2||
= ||
 q|	r:||
 q|
|vrB|||
< qqg }dd | D }|r| \}
}|
|g}||v rp||}||= || ||v s_|  |
|v r||
}
||
= ||
 |
|v sxd}|D ]}|t | 7 }|dkr||  nq|sQ|D ]W} fdd|D }|d }||d   }||< |dd D ]}||=  |= qt	|}t
|||f|  |< |rg }|D ]}||d}|r|| q|| q|||< qdS )	zKSubroutine of fuse.

    Mutates dsk, dependencies, and fused_trees inplacer2   Nc                 S  s   i | ]\}}||qS r%   r%   rD   r%   r%   r&   r@     r/   z+_inplace_fuse_subgraphs.<locals>.<dictcomp>r   c                   s   i | ]}| | qS r%   r%   r>   r?   r%   r&   r@     r/   r0   F)r   r7   r   rI   rJ   rK   r   rL   r   r6   SubgraphCallablerz   )r   r   r   r   rO   rP   rQ   rR   rS   rT   rU   rV   rW   rX   Zntasksr]   ZsubgraphoutkeyZ
inkeys_setr#   inkeysZchain2Zsubchainr%   r?   r&   r   u  sx   




r   c                   @  s   e Zd ZU dZded< ded< ded< ded	< eeZ	
d#d$ddZd%ddZd&ddZ	d'ddZ
d(ddZd)ddZd*d!d"Zd
S )+r   aD  Create a callable object from a dask graph.

    Parameters
    ----------
    dsk : dict
        A dask graph
    outkey : Dask key
        The output key from the graph
    inkeys : list
        A list of keys to be used as arguments to the callable.
    name : str, optional
        The name to use for the function.
    r   r   r   r   ztuple[Key, ...]r   r4   nameNIterable[Key]
str | Nonec                 C  s:   || _ || _t|| _|d u rdt||| j }|| _d S )Nzsubgraph_callable-)r   r   r6   r   r
   r   )r   r   r   r   r   r%   r%   r&   __init__  s   

zSubgraphCallable.__init__r   c                 C  s   | j S r`   )r   r   r%   r%   r&   r     s   zSubgraphCallable.__repr__otherr   boolc                 C  s<   t | t |u o| j|jko| j|jkot| jt|jkS r`   )r3   r   r   r   r   )r   r   r%   r%   r&   __eq__  s   

zSubgraphCallable.__eq__argsc                 G  sJ   t |t | jkstdt | jt |f t| j| jtt| j|S )NzExpected %d args, got %d)	r7   r   
ValueErrorr   r   r   r   r   zip)r   r   r%   r%   r&   __call__  s   zSubgraphCallable.__call__r6   c                 C  s   t | j| j| j| jffS r`   )r   r   r   r   r   r   r%   r%   r&   
__reduce__     zSubgraphCallable.__reduce__r   c                 C  s   t | jt| j| jfS r`   )r   r   	frozensetr   r   r   r%   r%   r&   __hash__  r   zSubgraphCallable.__hash__objectc                 C  s   dt | j| j| j| jfS )Nr   )r	   r   r   r   r   r   r%   r%   r&   __dask_tokenize__  s   z"SubgraphCallable.__dask_tokenize__r`   )r   r   r   r   r   r   r   r   r   )r   r   r   r   )r   r   r   r   )r   r6   )r   r   )r   r   )r   r   r   __doc____annotations__r6   	__slots__r   r   r   r   r   r   r   r%   r%   r%   r&   r     s   
 





r   )NNT)NTN)NFN)r}   )+
__future__r   r   r   collections.abcr   enumr   typingr   Zdaskr   r   r   Z	dask.baser	   r
   Z	dask.corer   r   r   r   r   r   r   Zdask.typingr   r   r'   r:   r_   ra   rn   rv   ry   ro   r   r   r   r   r   r   r   r%   r%   r%   r&   <module>   sJ    $	3
 

C
;
'
   1G