o
    XiVE                     @  s   d Z ddlmZ ddlZddlZddlmZ ddlmZm	Z	m
Z
mZmZ ddlmZ er>ddlm  mZ ddlm  mZ G dd dZG d	d
 d
eeZG dd dZG dd dZG dd dejZejG dd dZG dd dZG dd dZdS )z6Basic types for the pattern matching and rewriter API.    )annotationsN)defaultdict)TYPE_CHECKINGAnyMutableSequenceSequenceUnion)irc                   @  s&   e Zd ZdZ	ddddZd	d
 ZdS )MatchFailureInfoz7Encapsulates information about a pattern match failure. reasonstrfailure_sourceir.Node | ir.Valuec                 G  s:   || _ || _tdd |D sJ ddd |D  d S )Nc                 s  s"    | ]}t |tjtjfV  qd S N)
isinstancer	   NodeValue.0item r   O/home/ubuntu/.local/lib/python3.10/site-packages/onnxscript/rewriter/_basics.py	<genexpr>   s     z,MatchFailureInfo.__init__.<locals>.<genexpr>z=All items in failure_source must be ir.Node or ir.Value, got c                 S  s   g | ]}t |qS r   )typer   r   r   r   
<listcomp>   s    z-MatchFailureInfo.__init__.<locals>.<listcomp>)r   failure_sourcesallselfr   r   r   r   r   __init__   s
   zMatchFailureInfo.__init__c                 C  s   d| j d| jdS )NzMatchFailureInfo(reason=z, failure_sources=))r   r   r   r   r   r   __str__!   s   zMatchFailureInfo.__str__Nr   r   r   r   r   )__name__
__module____qualname____doc__r    r#   r   r   r   r   r
      s
    r
   c                   @  s   e Zd ZdZ	d
dddZd	S )MatchFailureErrora;  Exception raised when a pattern match fails.

    This makes it easier to handle match failures in a compositional way,
    for example, during the condition-checking phase of a pattern match.
    It allows us to define utility functions without having to check for
    and propagate match failures explicitly.
    r   r   r   r   r   c                 G  s$   t j| |g|R   t| | d S r   )r
   r    	Exceptionr   r   r   r   r    .   s   zMatchFailureError.__init__Nr$   r%   )r&   r'   r(   r)   r    r   r   r   r   r*   %   s    
r*   c                   @  s  e Zd ZdZdGddZdHddZedId
dZdGddZdIddZ	dGddZ
dJddZ		dKdLddZedHddZedMdd ZdNd%d&ZdOd'd(ZdPd-d.ZdQd0d1ZedRd3d4ZedSd6d7ZedTd9d:ZedUd<d=ZedVd?d@ZdWdBdCZdXdEdFZdS )YMatchResultak  The state object used by the pattern-matching algorithm.

    A match can either succeed or fail.
    If it succeeds, it returns a list of nodes that matched the pattern
    and a set of bindings for the variables in the pattern.

    Example:
    ::
        def pattern(x, shape1, shape2):
            t1 = op.Reshape(x, shape1)
            t2 = op.Reshape(t1, shape2)
            return t2
    The above pattern matches a sequence of two Reshape ops.
    The matched_nodes will contain the two Reshape ops, and the bindings will
    contain the values that are bound to the variables `x`, `shape1`, and `shape2`.
    returnNonec                 C  s   t  g| _d S r   )PartialMatchResult_partial_matchesr"   r   r   r   r    I   s   zMatchResult.__init__r   c                 C  s*   | j sdS dt|  d| jd| jdS )z4Returns a string representation of the match result.zMatchResult()zMatchResult(success=z	, reason=z, nodes=r!   )r0   boolr   nodesr"   r   r   r   __repr__M   s   zMatchResult.__repr__r/   c                 C  s
   | j d S )z!Returns the current match result.)r0   r"   r   r   r   _current_matchU   s   
zMatchResult._current_matchc                 C  s   t  }| j| dS )z?Starts a new sub-match to try out one of multiple alternatives.N)r/   r0   append)r   matchr   r   r   enter_new_matchZ   s   zMatchResult.enter_new_matchc                 C  s    t | jdk rtd| j S )z0Abandons the current alternative due to failure.   zNo match to abandon.)lenr0   
ValueErrorpopr"   r   r   r   abandon_current_match_   s   
z!MatchResult.abandon_current_matchc                 C  sD   t | jdk rtd| j }| jd }|std|| dS )EMerges a successful sub-match for an alternative with the parent one.r9   zNo match to merge.r4   z Current match is not successful.N)r:   r0   r;   r<   merge)r   current_matchprevious_matchr   r   r   merge_current_matche   s   

zMatchResult.merge_current_matchr1   c                 C  
   t | jS )z0Returns True if the current match is successful.)r1   r5   r"   r   r   r   __bool__p      
zMatchResult.__bool__r   Nr   r   ?Union[ir.Node, ir.Value, list[Union[ir.Node, ir.Value]]] | Nonec                 C  s   | j || | S r   )r5   failr   r   r   r   rG   t   s   zMatchResult.failc                 C     | j jS )z#Returns the reason for the failure.)r5   r   r"   r   r   r   r   |      zMatchResult.reasonSequence[ir.Node]c                 C  rH   )z3Returns the list of nodes that matched the pattern.)r5   r2   r"   r   r   r   r2      rI   zMatchResult.nodespattern_node_pattern_ir.NodePatternnodeir.Nodec                 C  s   |  | || jj|< dS )z'Binds a pattern node to a matched node.N)add_noder5   node_bindings)r   rK   rM   r   r   r   	bind_node   s   
zMatchResult.bind_nodec                 C     | j | dS z)Adds a node to the list of matched nodes.N)r5   rO   r   rM   r   r   r   rO         zMatchResult.add_nodepattern_value_pattern_ir.ValuePatternvaluer   c                 C  sz   |j }|d u r7| jD ]$}||jv r.|j| |kr dS | jd| d|j| |g  dS q
|| jj|< dS | ||S NTzBinding failure: z bound to two different values.F)namer0   value_bindingsr5   rG   bind)r   rV   rX   var_namer7   r   r   r   
bind_value   s   


	zMatchResult.bind_valuevarc                 C  s`   | j D ]$}||jv r'|j| |kr dS | jd| d|j| |g  dS q|| jj|< dS rY   )r0   bindingsr5   rG   )r   r_   rX   r7   r   r   r   r\      s   


	zMatchResult.binddict[str, Any]c                 C     t | jdkrtd| jjS )z/Returns the bindings for the pattern variables.   z5Bindings can be accessed only at the top-level match.)r:   r0   r;   r5   r`   r"   r   r   r   r`         zMatchResult.bindings(dict[_pattern_ir.ValuePattern, ir.Value]c                 C  rb   )z-Returns the bindings for the value variables.rc   z;Value bindings can be accessed only at the top-level match.)r:   r0   r;   r5   r[   r"   r   r   r   r[      rd   zMatchResult.value_bindings&dict[_pattern_ir.NodePattern, ir.Node]c                 C  rb   )z,Returns the bindings for the node variables.rc   z:Node bindings can be accessed only at the top-level match.)r:   r0   r;   r5   rP   r"   r   r   r   rP      rd   zMatchResult.node_bindingsMutableSequence[ir.Value]c                 C  rb   )z;Returns the list of output values that matched the pattern.rc   z4Outputs can be accessed only at the top-level match.)r:   r0   r;   r5   outputsr"   r   r   r   rh      rd   zMatchResult.outputslist[Union[ir.Node, ir.Value]]c                 C  rH   )z5Returns the nodes and values that caused the failure.)r5   _failure_nodes_and_valuesr"   r   r   r   failure_nodes_and_values   rI   z$MatchResult.failure_nodes_and_valuesir.Node | Nonec                 C  s(   | j D ]}||jv r|j|   S qdS )z6Looks up the node that matched the given pattern node.N)r0   rP   )r   rK   r7   r   r   r   lookup_node   s
   

zMatchResult.lookup_nodeintc                 C  s   t dd | jD S )z+Returns the number of nodes matched so far.c                 s  s    | ]}t |jV  qd S r   )r:   rP   )r   r7   r   r   r   r      s    z0MatchResult.num_matched_nodes.<locals>.<genexpr>)sumr0   r"   r   r   r   num_matched_nodes   s   zMatchResult.num_matched_nodesr-   r.   r-   r   )r-   r/   )r-   r1   r   N)r   r   r   rF   r-   r,   r-   rJ   )rK   rL   rM   rN   rM   rN   r-   r.   )rV   rW   rX   r   r-   r1   )r_   r   rX   r   r-   r1   r-   ra   r-   re   r-   rf   r-   rg   )r-   ri   )rK   rL   r-   rl   r-   rn   )r&   r'   r(   r)   r    r3   propertyr5   r8   r=   rB   rD   rG   r   r2   rQ   rO   r^   r\   r`   r[   rP   rh   rk   rm   rp   r   r   r   r   r,   7   sB    










r,   c                   @  s   e Zd ZdZd(ddZdd Z			d)d*ddZed+ddZed,ddZ	d-ddZ
ed.ddZed/ddZed0d d!Zed1d#d$Zd2d&d'Zd	S )3r/   zHThe state object used by the pattern-matching algorithm for a sub-match.r-   r.   c                 C  s4   d| _ g | _i | _i | _i | _g | _d| _g | _d S )NTr   )_success_matched_nodes	_bindings_value_bindings_node_bindings_outputs_reasonrj   r"   r   r   r   r       s   
zPartialMatchResult.__init__c                 C     | j S r   )r|   r"   r   r   r   rD      s   zPartialMatchResult.__bool__r   Nr   r   r   rF   c                 C  sB   d| _ || _|d urt|tr| j| d S | j| d S d S )NF)r|   r   r   listrj   extendr6   r   r   r   r   rG      s   
zPartialMatchResult.failc                 C  r   r   )r   r"   r   r   r   r        zPartialMatchResult.reasonrJ   c                 C  rC   r   )tupler}   r"   r   r   r   r2     rE   zPartialMatchResult.nodesrM   rN   c                 C  rR   rS   )r}   r6   rT   r   r   r   rO     rU   zPartialMatchResult.add_nodera   c                 C  r   r   )r~   r"   r   r   r   r`     r   zPartialMatchResult.bindingsre   c                 C  r   r   )r   r"   r   r   r   r[     r   z!PartialMatchResult.value_bindingsrg   c                 C  r   r   )r   r"   r   r   r   rh     r   zPartialMatchResult.outputsrf   c                 C  r   r   )r   r"   r   r   r   rP     r   z PartialMatchResult.node_bindingsotherc                 C  s>   | j r|j r| j|j | j|j |jrJ dS td)r>   z,Merging failed matches is not yet supported.N)r|   r~   updater}   r   r2   r   NotImplementedError)r   r   r   r   r   r?      s
   zPartialMatchResult.mergerq   rs   )r   r   r   rF   r-   r.   rr   rt   ru   rv   rw   ry   rx   )r   r/   r-   r.   )r&   r'   r(   r)   r    rD   rG   r{   r   r2   rO   r`   r[   rh   rP   r?   r   r   r   r   r/      s*    

r/   c                   @  s    e Zd ZdZdZdZdZdZdS )MatchStatusz+The status of a pattern-matching operation.r   rc   r9      N)r&   r'   r(   r)   NO_MATCHCONDITION_FAILEDREPLACEMENT_FAILEDSUCCESSr   r   r   r   r   /  s    r   c                   @  sD   e Zd ZU dZded< ded< ded< ded	< dddZdd ZdS )	MatchInfozHThe status of a pattern-matching operation. An extension of MatchResult.r,   match_resultrN   	root_nodeir.Graph | ir.Function	containerr   statusr-   rn   c                 C  s   t | jjt| jjd  S )zReturn a score for the match.d   )r:   r   r2   rn   r   rX   r"   r   r   r   scoreA  s   zMatchInfo.scorec                 C  s   d}t | t d| jj  | jtjkrH| jj}|r1| jtjkr)t d|  nt d|  nt d | jj}t d |rH|D ]}|	  qAt d dd l
m  m} || jj t | d S )	NzP--------------------------------------------------------------------------------zStatus: z7Graph matching failed due to failing check condition : zGraph matching failed: zGraph matching failed.z"Failure at or around nodes/values:zMatched nodes:r   )printr   rZ   r   r   r   r   r   rk   displayonnxscript.rewriter._ir_utilsrewriter	_ir_utilsdisplay_nodesr2   )r   	separatorr   rk   failure_causeir_utilsr   r   r   r   E  s&   
zMatchInfo.printNrz   )r&   r'   r(   r)   __annotations__r   r   r   r   r   r   r   8  s   
 
r   c                   @  sp   e Zd ZdZd!ddZed"ddZed#ddZed$ddZed%ddZ	ed&ddZ
ddd'ddZd S )(MatchContexta  A read-only context containing information about a pattern match.

    This class captures information about the context describing a match to a given pattern,
    providing access to the model, graph/function, root node, output values, and all
    nodes of the matching subgraph.
    modelir.Modelgraph_or_functionr   rootrN   r   r,   r-   r.   c                 C  s   || _ || _|| _|| _dS )a8  Initialize the pattern match context.

        Args:
            model: The model being matched.
            graph_or_function: The graph or function being matched.
            root: The root node of the matching subgraph.
            match_result: The match result containing matched nodes and outputs.
        N)_model_graph_or_function_root_match_result)r   r   r   r   r   r   r   r   r    f  s   
zMatchContext.__init__c                 C  r   )zThe model being matched.)r   r"   r   r   r   r   z     zMatchContext.modelc                 C  r   )z$The graph or function being matched.)r   r"   r   r   r   r     r   zMatchContext.graph_or_functionc                 C  r   )z'The root node of the matching subgraph.)r   r"   r   r   r   r     r   zMatchContext.rootSequence[ir.Value]c                 C  rH   )z+The output values of the matching subgraph.)r   rh   r"   r   r   r   output_values  rI   zMatchContext.output_valuesrJ   c                 C  rH   )z'All the nodes of the matching subgraph.)r   r2   r"   r   r   r   r2     rI   zMatchContext.nodesT)in_graph_orderr   r1   c                C  sH   | j }|sdS |r| jD ]
}||v r|  qdS |D ]}|  qdS )a  Display the nodes in the pattern match context.

        Args:
            in_graph_order: If True, display nodes in the order they appear in the
                graph/function. If False, display nodes in the order they appear
                in the match result.
        N)r2   r   r   )r   r   r2   rM   r   r   r   r     s   

zMatchContext.displayN)
r   r   r   r   r   rN   r   r,   r-   r.   )r-   r   )r-   r   )r-   rN   )r-   r   rt   )r   r1   r-   r.   )r&   r'   r(   r)   r    r{   r   r   r   r   r2   r   r   r   r   r   r   ^  s    
r   c                   @  s<   e Zd ZdZdddZedddZdddZdddZdS )MatchingTracerzA debugging helper class to trace the matching of a pattern against a graph.

    This is used to track the best matches found for each rule, and to report the
    results at the end of the matching.
    r-   r.   c                 C  s   t t| _d S r   )r   r   _best_matches_mapr"   r   r   r   r      s   
zMatchingTracer.__init__0dict[_rewrite_rule.RewriteRule, list[MatchInfo]]c                 C  r   r   )r   r"   r   r   r   best_matches_map  r   zMatchingTracer.best_matches_maprule_rewrite_rule.RewriteRuler   r   rM   rN   r   r,   r   r   c           	      C  sj   t ||||}| }|dkrd S | j| }|r.||d  k r"d S ||d  kr.|  || d S )Nr   )r   r   r   clearr6   )	r   r   r   rM   r   r   
this_match
this_scorebest_matchesr   r   r   log  s   
zMatchingTracer.logc                 C  st   d}| j  D ]\}}|sq|d  |kr"|d  }|d }|}q|dkr4td|  |  d S td d S )Nr   zRule: zNo matches found.)r   itemsr   r   )r   
best_scorer   matches
best_match	best_ruler   r   r   report  s   zMatchingTracer.reportNrq   )r-   r   )r   r   r   r   rM   rN   r   r,   r   r   r-   r.   )	r&   r'   r(   r)   r    r{   r   r   r   r   r   r   r   r     s    

r   )r)   
__future__r   dataclassesenumcollectionsr   typingr   r   r   r   r   
onnxscriptr	   onnxscript.rewriter._pattern_irr   _pattern_ir!onnxscript.rewriter._rewrite_rule_rewrite_ruler
   r+   r*   r,   r/   IntEnumr   	dataclassr   r   r   r   r   r   r   <module>   s(    (Q	%L