
    Lg51                        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y)    )annotations)deque)istasksubsc                R    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.12/site-packages/dask/rewrite.pyheadr      s(     d|Aw	D$	    c                H    t        |       r| dd S t        | t              r| S y)z&Get the arguments for the current task   N r   r   s    r   argsr      s(     d|ABx	D$	r   c                  @    e Zd ZdZd	dZd Zd Zd Zed        Z	d Z
y)
	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                P    || _         |st        t        g      | _        y || _        y N)termr   END_stack)selfr   stacks      r   __init__zTraverser.__init__2   s     	,DKDKr   c              #     K   | j                   t        ur2| j                    | j                          | j                   t        ur1y y wr   )currentr   nextr   s    r   __iter__zTraverser.__iter__9   s3     ll#%,,IIK ll#%s   AAAc                T    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77r   c                    t        | j                        }|s | j                  j                         | _        y|d   | _        | j                  j	                  t        |dd              y)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   sN     		?)DI DIKKx56r   c                ,    t        | j                        S r   )r   r   r!   s    r   r   zTraverser.currentQ   s    DIIr   c                B    | j                   j                         | _        y)z<Skip over all subterms of the current level in the traversalN)r   r&   r   r!   s    r   skipzTraverser.skipU   s    KKOO%	r   r   )__name__
__module____qualname____doc__r   r"   r$   r    propertyr   r,   r   r   r   r   r      s4    & 
8	7  &r   r   c                      e Zd ZdZd Zd Zy)Tokenz[A token object.

    Used to express certain objects in the traversal of a task or pattern.c                    || _         y 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    yyr   N)r-   r.   r/   r0   r   r8   r   r   r   r3   r3   Z   s    Nr   r3   ?endc                  <    e Zd ZdZdZddZed        Zed        Zy)NodezA Discrimination Net node.r   Nc                J    |r|ni }|r|ng }t         j                  | ||f      S r   )tuple__new__)clsedgespatternss      r   r?   zNode.__new__r   s*    B'8R}}S5("3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   s7    $I5
    r   r<   c                  *    e Zd ZdZddZd Zd Zd Zy)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)
    c                F   t        |t              st        d      || _        t	        |      r|| _        n| j                  | _        || _        t        |      D cg c]	  }||v s| c}| _	        t        t        t        | j                                    | _        y c c}w )Nz!vars must be a tuple of variables)r	   r>   	TypeErrorlhscallabler   _applyrhsr   _varlistsortedsetvars)r   rK   rN   rR   ts        r   r   zRewriteRule.__init__   s    $&?@@C=DIDI$-cN@Nqa4iN@&T]]!345	 As   	B%Bc                h    | j                   }|j                         D ]  \  }}t        |||      } |S r   )rN   itemsr   )r   sub_dictr   keyvals        r   rM   zRewriteRule._apply   s3    xx (HCc3'D )r   c                V    d| j                    d| j                   d| j                   dS )NzRewriteRule(z, ))rK   rN   rR   r!   s    r   __str__zRewriteRule.__str__   s)    dhhZr$((2dii[BBr   c                    t        |       S r   )strr!   s    r   r8   zRewriteRule.__repr__   s    4yr   N)r   )r-   r.   r/   r0   r   rM   r[   r8   r   r   r   rH   rH      s    +Z6Cr   rH   c                  0    e Zd ZdZd Zd Zd Zd ZddZy)	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                `    t               | _        g | _        |D ]  }| j                  |        y)zCreate a `RuleSet` for a number of rules

        Parameters
        ----------
        rules
            One or more instances of RewriteRule
        N)r<   _netrulesadd)r   rb   ps      r   r   zRuleSet.__init__   s)     F	
AHHQK r   c                   t        |t              st        d      |j                  }| j                  }t        | j                        }t        |j                        D ]R  }|}||v rt        }||j                  v r|j                  |   }-t               |j                  |<   |j                  |   }T j                     j                  j                  |       | j                  j                  |       y)zeAdd a rule to the RuleSet.

        Parameters
        ----------
        rule : RewriteRule
        z$rule must be instance of RewriteRuleN)r	   rH   rJ   rR   ra   lenrb   r   rK   VARrA   r<   rB   append)r   rulerR   	curr_nodeindrS   	prev_nodes          r   rc   zRuleSet.add   s     $,BCCyyII	$**o488$A!IDyIOO#%OOA.	%)V	"%OOA.	 % 	##**3/

$r   c              #     K   t        |      }t        || j                        D ]0  \  }}|D ]&  }| j                  |   }t	        ||      }|!||f ( 2 yw)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   _matchra   rb   _process_match)r   r   Smsymsiri   r   s           r   iter_matcheszRuleSet.iter_matches  s]      dOa+GAtzz!}%dD1#*$	  ,s   A
AAc                ^    | j                  |      D ]  \  }}|j                  |      } |S  |S )z7Apply the rewrite rules in RuleSet to top level of term)rt   r   )r   r   ri   sds       r   _rewritezRuleSet._rewrite0  s;     ))$/HD" 99R=D 0 r   c                     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)	bottom_up)	r-   r.   r/   r0   r   rc   rt   rw   r{   r   r   r   r_   r_      s!    &P 6%*	)0r   r_   c                $    | j                  |      S r   )rw   )netr   s     r   
_top_levelr   g  s    <<r   c                     t        |      r+t        |      ft         fdt        |      D              z   }n2t	        |t
              r"t        |      D cg c]  }t         |       }} j                  |      S c c}w )Nc              3  6   K   | ]  }t        |        y wr   )
_bottom_up).0rS   r~   s     r   	<genexpr>z_bottom_up.<locals>.<genexpr>m  s     $LAZQ%7s   )r   r   r>   r   r	   r
   r   rw   )r~   r   rS   s   `  r   r   r   k  sf    d|T
}u$Ld$LLL	D$	,0J7Jq
3"J7<< 8s   A;)	top_levelr|   c              #  &  K   t               }d}d}	 | j                  t        u r|j                  |f 	 |j                  j                  | j                  d      }|r7|s5|j                  | j                         ||f       |}| j                          |j                  j                  t        d      }|r%d}|| j                  fz   }| j                          |}	 |j                         \  } }}d}# t        $ r Y jw xY w# t        $ r Y yw xY ww)z;Structural matching of term S to discrimination net node N.Fr   TN)r   r   r   rB   rA   getrh   r$   r    rJ   rg   r   r,   r&   	Exception)rp   Nr   restore_state_flagmatchesns         r   rn   rn   v  s     GE G
99**g%%	 AIIt,A+affh734 GGKKT"!&	)GFFHA	#iikOQ7!%3   		  		sN   2DAC3 ADD 2D3	C?<D>C??D	DDDDc                    i }| j                   }t        |      t        |      k(  st        d      t        ||      D ]  \  }}||v r
||   |k7  r y|||<    |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)rO   rf   RuntimeErrorzip)ri   rr   r   varlistvss         r   ro   ro     sg      DmmGw<3t9$LMMGT"19aADG	 #
 Kr   N)
__future__r   collectionsr   	dask.corer   r   r   r   r   r3   rg   r   r>   r<   rH   r_   r   r   ry   rn   ro   r   r   r   <module>r      s    "  "9& 9&x	 	 Cj El5 *E EPZ0 Z0z &J?
#Lr   