a
    MSicE                     @   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mZmZmZmZmZ ddlZe	d	d
G dd deZG dd dZeejjddddZe	d	d
eeeee dddZdS )   )GraphModule)Graph)Node)symbolic_trace)compatibility    N)CallableDictList
NamedTupleOptionalSetT)is_backward_compatiblec                   @   s&   e Zd ZU eed< eeef ed< dS )Matchanchor	nodes_mapN)__name__
__module____qualname__r   __annotations__r	    r   r   V/var/www/html/django/DPS/env/lib/python3.9/site-packages/torch/fx/subgraph_rewriter.pyr      s   
r   c                   @   s>   e Zd ZeddddZeedddZeeedd	d
ZdS )_SubgraphMatcherN)patternreturnc                 C   sR   || _ t|jdkrtdttt|j| _t| jjdksHJ di | _	d S )Nr   z<_SubgraphMatcher cannot be initialized with an empty patternr   z5Pattern matching on multiple outputs is not supported)
r   lennodes
ValueErrornextiterreversedpattern_anchorall_input_nodesr   )selfr   r   r   r   __init__   s    z_SubgraphMatcher.__init__)r   r   c                 C   s   i | _ | | j|S )z
        Checks if the whole pattern can be matched starting from
        ``anchor`` in the larger graph.

        Pattern matching is done by recursively comparing the pattern
        node's use-def relationships against the graph node's.
        )r   _match_nodesr!   )r#   r   r   r   r   matches_subgraph_from_anchor!   s    z-_SubgraphMatcher.matches_subgraph_from_anchorpngnr   c                    s    j v rj   |kS tttddd}| |s8dS |j  <  jdkrPdS  jdkrrt jt|jkrrdS  jdkrt fdd	|jD }n4t jt|jkotfd
d	t j|jD }|sj 	  dS dS )Nr'   c                 S   s:   | j dks| j dkr"|j dkr"dS | j |j ko8| j|jkS )NplaceholderoutputT)optarget)r(   r)   r   r   r   attributes_are_equal4   s    
z;_SubgraphMatcher._match_nodes.<locals>.attributes_are_equalFr*   Tr+   c                 3   s    | ]}  jd  |V  qdS )r   N)r%   r"   ).0gn_r(   r#   r   r   	<genexpr>L   s   z0_SubgraphMatcher._match_nodes.<locals>.<genexpr>c                 3   s   | ]\}}  ||V  qd S N)r%   )r/   Zpn_r0   )r#   r   r   r2   P       )
r   r   boolr,   r   r"   anyallzippop)r#   r(   r)   r.   Zmatch_foundr   r1   r   r%   -   s2    







z_SubgraphMatcher._match_nodes)	r   r   r   r   r$   r   r5   r&   r%   r   r   r   r   r      s   r   )gmreplacementr   c                 C   s   |    t|tr|j  tjjtt	tjj ddd}| jj
D ]~}|jdksZ|jdkrB|| |j}|||j}|d ur~qBqB|d urtt||j}| |j| qBtd|jd|j dqB| j  d S )	N)modr-   r   c                 S   s*   z|  |}|W S  ty$   Y d S 0 d S r3   )get_submoduleAttributeError)r<   r-   Z	mod_matchr   r   r   try_get_submodule_   s
    
z._replace_submodules.<locals>.try_get_submodulecall_moduleget_attrzAttempted to create a "z-" node during subgraph rewriting with target z, but the referenced submodule does not exist in either the original GraphModule `gm` or the replacement GraphModule `replacement`)delete_all_unused_submodules
isinstancer   graphlinttorchnnModulestrr   r   r,   r-   copydeepcopygetattradd_submoduleRuntimeError)r:   r;   r?   nodeZ	gm_submodZreplacement_submodZ
new_submodr   r   r   _replace_submodulesY   s&    

rP   )r:   r   r;   r   c           !   
      sJ  | j }t|j }t|j }t|}g }|jD ]X}||r,tttf tddd}	|	|jr,|	t
|tdd |j D d q,t t }
t
tdfdd	}|D ]v|rqi }d
d |jD }t|dksJ dd |jD }t|t|ksJ dd t||D }j}tdd fdd |jD ]} | q<|D ].}|| }|
j| j| }|||< qP|| |||}W d   n1 s0    Y  |jdkrdd |jD }t|dksJ dd |jD }t|t|ksJ dd t||D }j D ]~\}}|jdkrBq*|jdkrRq*||ks`J || }t|j|jD ].\}}j| }|| }|| ||
|< qvq*|jdksJ n|f|_t|tr|di|_t|tsJ t|jD ],} t| jdkr| jdkr||  qq|   t|tj j!rFt"| | |S )a  
    Matches all possible non-overlapping sets of operators and their
    data dependencies (``pattern``) in the Graph of a GraphModule
    (``gm``), then replaces each of these matched subgraphs with another
    subgraph (``replacement``).

    Args:
        ``gm``: The GraphModule that wraps the Graph to operate on
        ``pattern``: The subgraph to match in ``gm`` for replacement
        ``replacement``: The subgraph to replace ``pattern`` with

    Returns:
        List[Match]: A list of ``Match`` objects representing the places
        in the original graph that ``pattern`` was matched to. The list
        is empty if there are no matches. ``Match`` is defined as:

        .. code-block:: python

            class Match(NamedTuple):
                # Node from which the match was found
                anchor: Node
                # Maps nodes in the pattern subgraph to nodes in the larger graph
                nodes_map: Dict[Node, Node]

    Examples:

    .. code-block:: python

        import torch
        from torch.fx import symbolic_trace, subgraph_rewriter

        class M(torch.nn.Module):
            def __init__(self):
                super().__init__()

            def forward(self, x, w1, w2):
                m1 = torch.cat([w1, w2]).sum()
                m2 = torch.cat([w1, w2]).sum()
                return x + torch.max(m1) + torch.max(m2)

        def pattern(w1, w2):
            return torch.cat([w1, w2]).sum()

        def replacement(w1, w2):
            return torch.stack([w1, w2])

        traced_module = symbolic_trace(M())

        subgraph_rewriter.replace_pattern(traced_module, pattern, replacement)

    The above code will first match ``pattern`` in the ``forward``
    method of ``traced_module``. Pattern-matching is done based on
    use-def relationships, not node names. For example, if you had
    ``p = torch.cat([a, b])`` in ``pattern``, you could match
    ``m = torch.cat([a, b])`` in the original ``forward`` function,
    despite the variable names being different (``p`` vs ``m``).

    The ``return`` statement in ``pattern`` is matched based on its
    value only; it may or may not match to the ``return`` statement in
    the larger graph. In other words, the pattern doesn't have to extend
    to the end of the larger graph.

    When the pattern is matched, it will be removed from the larger
    function and replaced by ``replacement``. If there are multiple
    matches for ``pattern`` in the larger function, each non-overlapping
    match will be replaced. In the case of a match overlap, the first
    found match in the set of overlapping matches will be replaced.
    ("First" here being defined as the first in a topological ordering
    of the Nodes' use-def relationships. In most cases, the first Node
    is the parameter that appears directly after ``self``, while the
    last Node is whatever the function returns.)

    One important thing to note is that the parameters of the
    ``pattern`` Callable must be used in the Callable itself,
    and the parameters of the ``replacement`` Callable must match
    the pattern. The first rule is why, in the above code block, the
    ``forward`` function has parameters ``x, w1, w2``, but the
    ``pattern`` function only has parameters ``w1, w2``. ``pattern``
    doesn't use ``x``, so it shouldn't specify ``x`` as a parameter.
    As an example of the second rule, consider replacing

    .. code-block:: python

        def pattern(x, y):
            return torch.neg(x) + torch.relu(y)

    with

    .. code-block:: python

        def replacement(x, y):
            return torch.relu(x)

    In this case, ``replacement`` needs the same number of parameters
    as ``pattern`` (both ``x`` and ``y``), even though the parameter
    ``y`` isn't used in ``replacement``.

    After calling ``subgraph_rewriter.replace_pattern``, the generated
    Python code looks like this:

    .. code-block:: python

        def forward(self, x, w1, w2):
            stack_1 = torch.stack([w1, w2])
            sum_1 = stack_1.sum()
            stack_2 = torch.stack([w1, w2])
            sum_2 = stack_2.sum()
            max_1 = torch.max(sum_1)
            add_1 = x + max_1
            max_2 = torch.max(sum_2)
            add_2 = add_1 + max_2
            return add_2
    )r   r   c                 S   s   dd |   D }| D ]l}|jdkr*q|| jdkr:qt|| jdkrjt|| j d jdkrjq|jD ]}||vrp  dS qpqdS )	Nc                 S   s   i | ]\}}||qS r   r   )r/   kvr   r   r   
<dictcomp>  r4   zAreplace_pattern.<locals>.pattern_is_contained.<locals>.<dictcomp>r*   r+   r   r   FT)itemskeysr,   r   userslist)r   lookupnuserr   r   r   pattern_is_contained  s    

z-replace_pattern.<locals>.pattern_is_containedc                 S   s   i | ]\}}||qS r   r   )r/   keyvaluer   r   r   rS   +  s   z#replace_pattern.<locals>.<dictcomp>)r   r   )matchr   c                    s<   | j  D ],\}}|jdv rq
| v r
|jdkr
 dS q
dS )N)r*   r+   r*   TF)r   rT   r,   )r^   r(   r)   )replaced_nodesr   r   overlaps_with_prev_match8  s    
z1replace_pattern.<locals>.overlaps_with_prev_matchc                 S   s   g | ]}|j d kr|qS r*   r,   r/   rY   r   r   r   
<listcomp>H  s   
z#replace_pattern.<locals>.<listcomp>r   c                 S   s   g | ]}|j d kr|qS ra   rb   rc   r   r   r   rd   K  s   
c                 S   s   i | ]\}}||qS r   r   r/   rpr   r   r   rS   N  r4   N)rY   r   c                    s4   | j  vrd S | jD ]} | q|  d S r3   )r   valuesr"   add)rY   n_mark_node_as_replacedr^   r_   r   r   rl   U  s
    

z.replace_pattern.<locals>.mark_node_as_replacedr+   c                 S   s   g | ]}|j d kr|qS r+   rb   rc   r   r   r   rd   w  s   
c                 S   s   g | ]}|j d kr|qS rm   rb   rc   r   r   r   rd   z  s   
c                 S   s   i | ]\}}||qS r   r   re   r   r   r   rS   }  r4   r*   )#rD   r   r   r   r&   r	   r   r5   r   appendr   rJ   rT   setdictr   r8   r   r"   getinserting_before
graph_copyr,   replace_all_uses_withargsrC   _input_nodesr    rV   
erase_node	recompilerF   rG   rH   rP   )!r:   r   r;   original_graphZpattern_graphZreplacement_graphmatchermatchesr   r[   Zmatch_changed_noder`   val_mapZpattern_placeholdersZreplacement_placeholdersZplaceholder_mapZsubgraph_output
input_nodeZreplacement_nodeZpattern_nodeZoriginal_graph_nodeZcopied_outputZpattern_outputsZreplacement_outputsZoutputs_mapr(   r)   rnZpn_inputZrn_inputZgn_inputZrn_input_in_original_graphrO   r   rk   r   replace_pattern   s    t



 




$




r   )graph_moduler   rD   r   rO   r   _symbolic_tracer   _compatibilityr   rJ   typingr   r	   r
   r   r   r   rF   r   r   rG   rH   rP   r   r   r   r   r   <module>   s    G-