o
    XipE                     @  s   d Z ddlmZ ddlZddlZddlZddlmZmZ ddl	m
  mZ ddlm
  mZ ddlmZ dddZG dd dejZG dd deZdS )z1Implementation of the pattern matching algorithm.    )annotationsN)IterableSequence)irmatched_nodesSequence[ir.Node]output_valuesSequence[ir.Value]returnboolc                 C  sX   | D ]'}|j D ]!}||v rq| r  dS | D ]\}}|| vr'   dS qqqdS )znCheck that values computed by the matched_nodes, except for output_values, are used only by the matched_nodes.FT)outputsis_graph_outputuses)r   r   nvconsumer_ r   P/home/ubuntu/.local/lib/python3.10/site-packages/onnxscript/rewriter/_matcher.py_valid_to_replace   s   

	r   c                   @  s:   e Zd ZdddZejddd	d
dddZdddZd	S ) PatternMatcherpattern_pattern_ir.GraphPatternr
   Nonec                 C  s
   || _ d S N)r   selfr   r   r   r   __init__*      
zPatternMatcher.__init__r   TNverboseremove_nodestracermodelir.Modelgraph_or_functionir.Graph | ir.Functionnodeir.Noder    intr!   r   r"   _basics.MatchingTracer | None_basics.MatchResultc                C  s   dS )z@Match the pattern against the subgraph ending at the given node.Nr   )r   r#   r%   r'   r    r!   r"   r   r   r   match-   s    zPatternMatcher.matchstrc                 C  s
   t | jS r   )r-   r   )r   r   r   r   __str__:   r   zPatternMatcher.__str__r   r   r
   r   r#   r$   r%   r&   r'   r(   r    r)   r!   r   r"   r*   r
   r+   )r
   r-   )__name__
__module____qualname__r   abcabstractmethodr,   r.   r   r   r   r   r   )   s    
r   c                      s   e Zd Zd= fddZd>d?ddZd@ddZdAddZdBddZdCd d!ZdDd$d%Z	dEd'd(Z
dFd/d0ZdGd3d4Zd5d6dd7dHd;d<Z  ZS )ISimplePatternMatcherr   r   r
   r   c                   s   t  | d | _d S r   )superr   _current_noder   	__class__r   r   r   ?   s   
zSimplePatternMatcher.__init__Nreasonr-   r'   ir.Node | Noner   c                 C  sD   | j r| j }|dkrtd| d|  | j||p| j dS )Nr   zMatch failed after z nodes: F)_verbose_matchnum_matched_nodesprintfailr8   )r   r;   r'   r?   r   r   r   rA   C   s   
zSimplePatternMatcher.failpattern_constant_pattern_ir.Constantvalueir.Valuec              	     s@  |j }|du r| d|j dj dS z|  W n ty.   | d|j d Y S w jttrqt	f} j
|krR| d|j d j
 d| dS t fd	d
tt	D so| d d  dS dS  jdkr| d|j d dS tj  jjds| d d   dS dS )aX  Match a Constant pattern against a value.

        If the constant value is produced by a Constant node, we do not include
        the constant node as part of the matched graph. Thus, it will not be deleted,
        if subgraph replacement happens. But subsequent DCE will remove the constant
        node if it is not used elsewhere.
        NValue z is not a constant, expecting .zConstant value of z not available.z has shape z, expecting c                 3  s0    | ]}t j || jjd V  qdS )rel_tolabs_tolN)mathiscloseitem_rel_tol_abs_tol).0inumpy_valuerB   pattern_constant_valuer   r   	<genexpr>f   s    
z7SimplePatternMatcher._match_constant.<locals>.<genexpr>zValue mismatch: expected , got Tr   z is not a scalar, expecting rH   z"Constant value mismatch: expected )const_valuerA   namerD   numpyFileNotFoundError_value
isinstancelistlenshapeallrangendimrK   rL   rM   rN   rO   )r   rB   rD   constant_valueexpected_shaper   rR   r   _match_constantK   sL   



	
z$SimplePatternMatcher._match_constantpattern_node_pattern_ir.NodePatternr(   c           
      C  sX  || _ | j|}|dur||ur| dS dS | j}|||s'| |jS | jr2td|j  |	|| t
|jt
|jkr_|jsW| dt
|j dt
|j dS t|j|j}n
tj|j|jdd}|D ]\}}|du r|du rxqk| d	  S | ||s d
S qkt|jD ]\}}	|t
|jkr d
S | j|	|j| s d
S qdS )z;Matches a pattern subgraph against subgraph rooted at node.Nz;Same pattern node is matched against different graph nodes.Tz	Matched: zNumber of inputs (z) is greater than expected ())	fillvaluez3(Optional) input is expected to be None but is not.F)r8   r>   lookup_noderA   matchesr;   r=   r@   op_type	bind_noder^   inputsallow_other_inputszip	itertoolszip_longest_match_value	enumerater   
bind_value)
r   rf   r'   matched_noder,   checked_inputs	arg_valuearg_patternrQ   output_value_patternr   r   r   _match_node   sH   

z SimplePatternMatcher._match_nodepattern_value_pattern_ir.ValuePatternir.Value | Nonec                 C  s  |dur$|j | jur$t|tjtjtjfs$| d|j d| jj dS t|tjr,dS | j	
||s5dS t|tjrJ|du rD| dS | ||S t|tjr_|du rY| dS | ||S t|tjrt|jD ],\}}| j	  | ||r|jdur| j	|j|j|  | j	   dS | j	  qj| d	S t|tjr|du r| d
S ||}|du r| dS |\}}| ||}|r|jdur| j	|j| |S |du r|js| d| dS dS )z2Match an IR value against a ValuePattern instance.NrF   z is not in the graph z>. Pattern matches crossing graph boundaries are not supported.TFz4Mismatch: Computed node pattern does not match None.z/Mismatch: Constant pattern does not match None.z!None of the alternatives matched.z.Mismatch: OrValue pattern does not match None.z/Mismatch: OrValue pattern does not match value.zMismatch: pattern variable z does not match None.)graph_graphr\   _pattern_irVarConstantAnyValuerA   rX   r>   ru   NodeOutputPattern_match_node_outputre   BacktrackingOrrt   _valuesenter_new_matchrs   tag_varbind_tag_valuesmerge_current_matchabandon_current_matchOpIdDispatchOrget_patterncan_match_none)r   r|   rD   rQ   pattern_choicealternativeresultr   r   r   rs      s\   










z!SimplePatternMatcher._match_value_pattern_ir.NodeOutputPatternc                 C  sV   |  }|du r| dS | |jkr#| d|j d|  dS | |  |S )z7Match an IR value against a NodeOutputPattern instance.NzCMismatch: Computed node pattern does not match uncomputed IR value.z%Node output index mismatch: expected rV   rG   )producerrA   indexoutput_index_output_indexr{   )r   r|   rD   r'   r   r   r   r      s   z'SimplePatternMatcher._match_node_outputr    r)   c                 C  s   || _ t | _d| _dS )z@Initialize the match state. Invoked before starting a new match.N)r=   _basicsMatchResultr>   r8   )r   r    r   r   r   _init_match  s   

z SimplePatternMatcher._init_matchlist[ir.Value] | Nonec                 C  s   g }g }t | jjD ]:\}}|jdur,|j| jjv r%|| jj|j  q
||j q
|| jjv r<|| jj|  q
|d|  q
|rR| jd|  dS |S )z8Get values bound to the output variables of the pattern.Noutput_z Error: Output values not found: )	rt   r   r   rX   r>   bindingsappendvalue_bindingsrA   )r   r   unbound_valuesjvalue_patternr   r   r   _get_output_values  s   
z'SimplePatternMatcher._get_output_valuesr#   r$   r%   r&   check_removabler+   c                 C  sp   ~~| j }| j}|js|dS | |j|s|S |  }|d u r#|S |r0t|j|s0|dS |j	
| |S )Nz`Internal Error: SimplePatternMatcher should not be used for patterns with multiple output nodes.5Matched nodes have other uses preventing replacement.)r   r>   has_single_output_noderA   r{   output_noder   r   nodesr   extend)r   r#   r%   r'   r   r   r,   r   r   r   r   _match_single_output_node   s"   
z.SimplePatternMatcher._match_single_output_node	candidateIterable[ir.Node]c                 C  sp   | j }t| jj|D ]\}}| ||s|  S q
|  }|du r#|S |r0t|j|s0|dS |j	
| |S )a  Find a match for a pattern with multiple output nodes.

        For a pattern with K output nodes, the input candidate should specify K nodes
        in the graph that will be matched against the pattern output nodes.

        Args:
            candidate: An iterable of nodes that will be matched against the pattern output nodes.
            check_removable: If True, check that the matched nodes can be removed (that is, that
                they are not used elsewhere in the graph).
        Nr   )r>   rp   r   output_nodesr{   r   r   r   rA   r   r   )r   r   r   r,   rf   r'   r   r   r   r   _multi_match@  s   
z!SimplePatternMatcher._multi_matchr   Tr   r!   r"   r*   c                  s   || _ t|tjr|| _n|j| _| jjr#| | | j	||||dS | jj
}i |D ]}| g | q+t|  fddt|ggfdd|dd D  }	d}
tj|	 D ]}| | | j||d}
|
rr|
  S q^|
du r~t dS |
S )	aa  Match the pattern against the subgraph ending at the given node.

        For patterns with multiple output nodes, the given node is matched
        against the first output node in the pattern. For the remaining
        output nodes in the pattern, we use a brute-force algorithm that
        enumerates all possible combinations of nodes from the graph (with
        a filter based on op-type).

        TODO: Consider omitting parameters model and graph_or_function. With
        the new IR, the graph can be obtained from the node, and the model is
        not used. But this is a shared abstract method of the Matcher interface,
        so other matcher implementation also needs to be updated. More importantly,
        matching in the presence of subgraphs (control-flow) can introduce some
        complications which require careful consideration.
        )r   c                   s    |   }|d u r
 S |g S r   )op_identifierget)rf   id)	all_nodesop_to_nodesr   r   	get_nodes  s   z-SimplePatternMatcher.match.<locals>.get_nodesc                   s   g | ]} |qS r   r   )rP   pn)r   r   r   
<listcomp>  s    z.SimplePatternMatcher.match.<locals>.<listcomp>   NzNo match found.)_tracerr\   r   Graphr   r   r   r   r   r   r   
setdefaultr   r   iterrq   productr   r   r   rA   )r   r#   r%   r'   r    r!   r"   pattern_output_nodesr   
candidatesr,   combinationr   )r   r   r   r   r,   [  s4   
&
zSimplePatternMatcher.matchr/   r   )r;   r-   r'   r<   r
   r   )rB   rC   rD   rE   r
   r   )rf   rg   r'   r(   r
   r   )r|   r}   rD   r~   r
   r   )r|   r   rD   rE   r
   r   )r    r)   r
   r   )r
   r   )
r#   r$   r%   r&   r'   r(   r   r   r
   r+   )r   r   r   r   r
   r+   r0   )r1   r2   r3   r   rA   re   r{   rs   r   r   r   r   r   r,   __classcell__r   r   r9   r   r6   >   s    

;
8
9



 !r6   )r   r   r   r	   r
   r   )__doc__
__future__r   r4   rq   rK   typingr   r   onnxscript.rewriter._basicsrewriterr   onnxscript.rewriter._pattern_irr   
onnxscriptr   r   ABCr   r6   r   r   r   r   <module>   s   
