
    >ie51                       d dl mZ d dlmZ d dlmZmZ d Zd Z G d d          Z	 G d d	          Z
 e
d
          Z e
d          Z G d de          Z G d d          Z G d d          Zd Zd ZeedZd Zd ZdS )    )annotations)deque)istasksubsc                l    t          |           r| d         S t          | t                    rt          S | S )z#Return the top level node of a taskr   r   
isinstancelisttasks    ,lib/python3.11/site-packages/dask/rewrite.pyheadr      s7     d|| Aw	D$		     c                f    t          |           r
| dd         S t          | t                    r| S dS )z&Get the arguments for the current task   N r   r   s    r   argsr      s;     d|| ABBx	D$		 rr   c                  H    e Zd ZdZd	dZd Zd Zd Zed             Z	d Z
dS )
	Traversera  Traverser interface for tasks.

    Class for storing the state while performing a preorder-traversal of a
    task.

    Parameters
    ----------
    term : task
        The task to be traversed

    Attributes
    ----------
    term
        The current element in the traversal
    current
        The head of the current element in the traversal. This is simply `head`
        applied to the attribute `term`.
    Nc                ^    || _         |st          t          g          | _        d S || _        d S N)termr   END_stack)selfr   stacks      r   __init__zTraverser.__init__2   s/    	 	 ,,DKKKDKKKr   c              #     K   | j         t          ur-| j         V  |                                  | j         t          u+d S d S r   )currentr   nextr   s    r   __iter__zTraverser.__iter__9   sI      l#%%,IIKKK l#%%%%%%r   c                P    t          | j        t          | j                            S )zCopy the traverser in its current state.

        This allows the traversal to be pushed onto a stack, for easy
        backtracking.)r   r   r   r   r!   s    r   copyzTraverser.copy>   s      E$+$6$6777r   c                    t          | j                  }|s | j                                        | _        dS |d         | _        | j                            t          |dd                              dS )z3Proceed to the next term in the preorder traversal.r   r   N)r   r   r   popextendreversed)r   subtermss     r   r    zTraverser.nextF   sg     	?? 	7))DIII DIKx5566666r   c                *    t          | j                  S r   )r   r   r!   s    r   r   zTraverser.currentQ   s    DIr   c                B    | j                                         | _        dS )z<Skip over all subterms of the current level in the traversalN)r   r&   r   r!   s    r   skipzTraverser.skipU   s    KOO%%			r   r   )__name__
__module____qualname____doc__r   r"   r$   r    propertyr   r,   r   r   r   r   r      s         &         
8 8 8	7 	7 	7   X& & & & &r   r   c                      e Zd ZdZd Zd ZdS )Tokenz[A token object.

    Used to express certain objects in the traversal of a task or pattern.c                    || _         d S r   name)r   r6   s     r   r   zToken.__init___   s    			r   c                    | j         S r   r5   r!   s    r   __repr__zToken.__repr__b   s
    yr   N)r-   r.   r/   r0   r   r8   r   r   r   r3   r3   Z   s>        N N      r   r3   ?endc                  J    e Zd ZdZdZddZed             Zed             ZdS )NodezA Discrimination Net node.r   Nc                T    |r|ni }|r|ng }t                               | ||f          S r   )tuple__new__)clsedgespatternss      r   r?   zNode.__new__r   s7    &B'/88R}}S5("3444r   c                    | d         S )z@A dictionary, where the keys are edges, and the values are nodesr   r   r!   s    r   rA   z
Node.edgesw        Awr   c                    | d         S )z8A list of all patterns that currently match at this noder   r   r!   s    r   rB   zNode.patterns|   rD   r   )NN)	r-   r.   r/   r0   	__slots__r?   r1   rA   rB   r   r   r   r<   r<   m   si        $$I5 5 5 5
   X   X  r   r<   c                  ,    e Zd ZdZddZd Zd Zd ZdS )	RewriteRulea  A rewrite rule.

    Expresses `lhs` -> `rhs`, for variables `vars`.

    Parameters
    ----------
    lhs : task
        The left-hand-side of the rewrite rule.
    rhs : task or function
        The right-hand-side of the rewrite rule. If it's a task, variables in
        `rhs` will be replaced by terms in the subject that match the variables
        in `lhs`. If it's a function, the function will be called with a dict
        of such matches.
    vars: tuple, optional
        Tuple of variables found in the lhs. Variables can be represented as
        any hashable object; a good convention is to use strings. If there are
        no variables, this can be omitted.

    Examples
    --------
    Here's a `RewriteRule` to replace all nested calls to `list`, so that
    `(list, (list, 'x'))` is replaced with `(list, 'x')`, where `'x'` is a
    variable.

    >>> import dask.rewrite as dr
    >>> lhs = (list, (list, 'x'))
    >>> rhs = (list, 'x')
    >>> variables = ('x',)
    >>> rule = dr.RewriteRule(lhs, rhs, variables)

    Here's a more complicated rule that uses a callable right-hand-side. A
    callable `rhs` takes in a dictionary mapping variables to their matching
    values. This rule replaces all occurrences of `(list, 'x')` with `'x'` if
    `'x'` is a list itself.

    >>> lhs = (list, 'x')
    >>> def repl_list(sd):
    ...     x = sd['x']
    ...     if isinstance(x, list):
    ...         return x
    ...     else:
    ...         return (list, x)
    >>> rule = dr.RewriteRule(lhs, repl_list, variables)
    r   c                X   t          t                    st          d          || _        t	          |          r|| _        n| j        | _        || _        fdt          |          D             | _	        t          t          t          | j	                                      | _        d S )Nz!vars must be a tuple of variablesc                    g | ]}|v |	S r   r   ).0tvarss     r   
<listcomp>z(RewriteRule.__init__.<locals>.<listcomp>   s    @@@qa4iiiiir   )r	   r>   	TypeErrorlhscallabler   _applyrhsr   _varlistsortedsetrM   )r   rP   rS   rM   s      `r   r   zRewriteRule.__init__   s    $&& 	A?@@@C== 	$DIIDI@@@@IcNN@@@&T]!3!34455			r   c                j    | j         }|                                D ]\  }}t          |||          }|S r   )rS   itemsr   )r   sub_dictr   keyvals        r   rR   zRewriteRule._apply   s>    x (( 	( 	(HCc3''DDr   c                8    d| j          d| j         d| j         dS )NzRewriteRule(z, ))rP   rS   rM   r!   s    r   __str__zRewriteRule.__str__   s)    BdhBB$(BBdiBBBBr   c                     t          |           S r   )strr!   s    r   r8   zRewriteRule.__repr__   s    4yyr   N)r   )r-   r.   r/   r0   r   rR   r^   r8   r   r   r   rH   rH      sc        + +Z6 6 6 6  C C C    r   rH   c                  2    e Zd ZdZd Zd Zd Zd Zd	dZdS )
RuleSeta%  A set of rewrite rules.

    Forms a structure for fast rewriting over a set of rewrite rules. This
    allows for syntactic matching of terms to patterns for many patterns at
    the same time.

    Examples
    --------

    >>> import dask.rewrite as dr
    >>> def f(*args): pass
    >>> def g(*args): pass
    >>> def h(*args): pass
    >>> from operator import add

    >>> rs = dr.RuleSet(
    ...         dr.RewriteRule((add, 'x', 0), 'x', ('x',)),
    ...         dr.RewriteRule((f, (g, 'x'), 'y'),
    ...                        (h, 'x', 'y'),
    ...                        ('x', 'y')))

    >>> rs.rewrite((add, 2, 0))
    2

    >>> rs.rewrite((f, (g, 'a', 3)))    # doctest: +ELLIPSIS
    (<function h at ...>, 'a', 3)

    >>> dsk = {'a': (add, 2, 0),
    ...        'b': (f, (g, 'a', 3))}

    >>> from toolz import valmap
    >>> valmap(rs.rewrite, dsk)         # doctest: +ELLIPSIS
    {'a': 2, 'b': (<function h at ...>, 'a', 3)}

    Attributes
    ----------
    rules : list
        A list of `RewriteRule`s included in the `RuleSet`.
    c                n    t                      | _        g | _        |D ]}|                     |           dS )zCreate a `RuleSet` for a number of rules

        Parameters
        ----------
        rules
            One or more instances of RewriteRule
        N)r<   _netrulesadd)r   re   ps      r   r   zRuleSet.__init__   s@     FF	
 	 	AHHQKKKK	 	r   c                   t          |t                    st          d          |j        }| j        }t          | j                  }t          |j                  D ]I}|}||v rt          }||j
        v r|j
        |         }&t                      |j
        |<   |j
        |         }J|j
        |         j                            |           | j                            |           dS )zeAdd a rule to the RuleSet.

        Parameters
        ----------
        rule : RewriteRule
        z$rule must be instance of RewriteRuleN)r	   rH   rO   rM   rd   lenre   r   rP   VARrA   r<   rB   append)r   rulerM   	curr_nodeindrL   	prev_nodes          r   rf   zRuleSet.add   s     $,, 	DBCCCyI	$*oo48$$ 	/ 	/A!IDyyIO##%OA.		%)VV	"%OA.		#**3///
$r   c              #     K   t          |          }t          || j                  D ]/\  }}|D ]'}| j        |         }t	          ||          }|||fV  (0dS )al  A generator that lazily finds matchings for term from the RuleSet.

        Parameters
        ----------
        term : task

        Yields
        ------
        Tuples of `(rule, subs)`, where `rule` is the rewrite rule being
        matched, and `subs` is a dictionary mapping the variables in the lhs
        of the rule to their matching values in the term.N)r   _matchrd   re   _process_match)r   r   Smsymsirl   r   s           r   iter_matcheszRuleSet.iter_matches  s       dOOa++ 	% 	%GAt % %z!}%dD11#*$$$	%	% 	%r   c                f    |                      |          D ]\  }}|                    |          } |S )z7Apply the rewrite rules in RuleSet to top level of term)rw   r   )r   r   rl   sds       r   _rewritezRuleSet._rewrite0  s>     ))$// 	 	HD" 99R==Dr   	bottom_upc                .    t          |         | |          S )ae  Apply the `RuleSet` to `task`.

        This applies the most specific matching rule in the RuleSet to the
        task, using the provided strategy.

        Parameters
        ----------
        term: a task
            The task to be rewritten
        strategy: str, optional
            The rewriting strategy to use. Options are "bottom_up" (default),
            or "top_level".

        Examples
        --------
        Suppose there was a function `add` that returned the sum of 2 numbers,
        and another function `double` that returned twice its input:

        >>> add = lambda x, y: x + y
        >>> double = lambda x: 2*x

        Now suppose `double` was *significantly* faster than `add`, so
        you'd like to replace all expressions `(add, x, x)` with `(double,
        x)`, where `x` is a variable. This can be expressed as a rewrite rule:

        >>> rule = RewriteRule((add, 'x', 'x'), (double, 'x'), ('x',))
        >>> rs = RuleSet(rule)

        This can then be applied to terms to perform the rewriting:

        >>> term = (add, (add, 2, 2), (add, 2, 2))
        >>> rs.rewrite(term)  # doctest: +SKIP
        (double, (double, 2))

        If we only wanted to apply this to the top level of the term, the
        `strategy` kwarg can be set to "top_level".

        >>> rs.rewrite(term)  # doctest: +SKIP
        (double, (add, 2, 2))
        )
strategies)r   r   strategys      r   rewritezRuleSet.rewrite;  s    R (#D$///r   N)r{   )	r-   r.   r/   r0   r   rf   rw   rz   r   r   r   r   rb   rb      so        & &P       6% % %*	 	 	)0 )0 )0 )0 )0 )0r   rb   c                ,    |                      |          S r   )rz   netr   s     r   
_top_levelr   g  s    <<r   c                     t          |          r:t          |          ft           fdt          |          D                       z   }n0t	          |t
                    r fdt          |          D             }                     |          S )Nc              3  8   K   | ]}t          |          V  d S r   
_bottom_uprK   rL   r   s     r   	<genexpr>z_bottom_up.<locals>.<genexpr>m  s-      $L$LAZQ%7%7$L$L$L$L$L$Lr   c                0    g | ]}t          |          S r   r   r   s     r   rN   z_bottom_up.<locals>.<listcomp>o  s#    777q
3""777r   )r   r   r>   r   r	   r
   rz   r   s   ` r   r   r   k  s    d|| 8T

}u$L$L$L$Ld$L$L$LLLL	D$		 87777DJJ777<<r   )	top_levelr{   c              #  6  K   t                      }d}d}	 | j        t          u r|j        |fV  	 |j                            | j        d          }|rC|sA|                    |                                 ||f           |}|                                  n# t          $ r Y nw xY w|j                            t          d          }|r$d}|| j        fz   }|                                  |}	 |                                \  } }}d}n# t          $ r Y dS w xY w)z;Structural matching of term S to discrimination net node N.Fr   TN)r   r   r   rB   rA   getrk   r$   r    rO   rj   r   r,   r&   	Exception)rs   Nr   restore_state_flagmatchesns         r   rq   rq   v  sV      GGE G9*g%%%%	 AIt,,A + affhh73444 	 	 	D	GKKT"" 	!&	)GFFHHHA	#iikkOQ7!% 	 	 	FF	5s$   A$B 
B#"B#-D 
DDc                    i }| j         }t          |          t          |          k    st          d          t          ||          D ]\  }}||v r||         |k    r dS |||<   |S )a  Process a match to determine if it is correct, and to find the correct
    substitution that will convert the term into the pattern.

    Parameters
    ----------
    rule : RewriteRule
    syms : iterable
        Iterable of subterms that match a corresponding variable.

    Returns
    -------
    A dictionary of {vars : subterms} describing the substitution to make the
    pattern equivalent with the term. Returns `None` if the match is
    invalid.z/length of varlist doesn't match length of syms.N)rT   ri   RuntimeErrorzip)rl   ru   r   varlistvss         r   rr   rr     s      DmGw<<3t99$$LMMMGT""  199aA44DGGKr   N)
__future__r   collectionsr   	dask.corer   r   r   r   r   r3   rj   r   r>   r<   rH   rb   r   r   r}   rq   rr   r   r   r   <module>r      s   " " " " " "       " " " " " " " "    9& 9& 9& 9& 9& 9& 9& 9&x	 	 	 	 	 	 	 	 eCjj eEll    5   *E E E E E E E EPZ0 Z0 Z0 Z0 Z0 Z0 Z0 Z0z     &J??
# # #L    r   