
    g.                    D    d dl mZ d dlmZ d dlZddlmZ  G d d      Zy)    )annotations)dequeN   )	ONNXModelc                  d   e Zd ZdZddZ	 	 	 	 	 	 ddZddZd Ze	 	 	 	 	 	 	 	 	 	 dd       Z	edd       Z
edd       Zedd	       Zdd
ZdddZdddZddZdg f	 	 	 	 	 	 	 	 	 d dZddg df	 	 	 	 	 	 	 	 	 	 	 	 	 d!dZ	 	 	 d"	 	 	 	 	 	 	 	 	 	 	 d#dZ	 	 	 	 	 	 	 	 d$dZ	 	 d%	 	 	 	 	 	 	 	 	 d&dZy)'Fusionz!
    Base class for fusions.
    c                    || _         || _        || _        g | _        g | _        | j                  dz   | j                   z   dz   | _        d | _        y )N_fused__)search_op_typefused_op_typemodelnodes_to_removenodes_to_add_new_node_name_prefix_new_node_name_suffix)selfr   r   r   s       \/var/www/openai/venv/lib/python3.12/site-packages/onnxruntime/quantization/fusions/fusion.py__init__zFusion.__init__   sU    #1"/ %
%'"$%)%7%7)%CdFYFY%Y\_%_"%)"    c                    t         )z
        Interface function for derived fusion classes. Tries to fuse a node sequence containing
        the specified node.
        )NotImplementedError)r   nodeinput_name_to_nodesoutput_name_to_nodes       r   fusezFusion.fuse   s
     "!r   c                   | j                   j                         }| j                   j                         }| j                   j                         D ]/  }|j                  | j
                  k(  s| j                  |||       1 | j                   j                  | j                         | j                   j                  | j                         t        | j                  xs | j                        }|r| j                   j                          |S )z?
        Apply graph fusion on the entire model graph.
        )r   r   r   nodesop_typer   r   remove_nodesr   	add_nodesr   boolremove_unused_constant)r   r   r   r   graph_updateds        r   applyzFusion.apply*   s     #jj<<>"jj<<>JJ$$&D||t222		$ 35HI ' 	

 4 45

T../T11FT5F5FGJJ--/r   c                    | j                   }| j                  %| j                  j                  |      }|dz   | _        | | j                  }| xj                  dz  c_        |S )N   )r   r   r   get_largest_node_name_suffix)r   prefixlargest_suffixnew_names       r   create_unique_node_namezFusion.create_unique_node_name?   se    ++%%-"&**"I"I&"QN)7!);D&Xd88;<""a'"r   c                l    | D ]/  }|j                   D ]  }||v r||v s||   D ]
  }|| vs   y   1 yNFT)output)r   keep_outputsr   r   node_to_removeoutput_to_removeimpacted_nodes          r   is_safe_to_fuse_nodeszFusion.is_safe_to_fuse_nodesK   sT     .N$2$9$9 #|3#'::)<=M)N(?#( *O %: . r   c                    | j                   D ]4  }|j                  |k(  st        j                  j	                  |      }|c S  y )N)	attributenameonnxhelperget_attribute_value)r   attribute_nameattrvalues       r   get_node_attributezFusion.get_node_attribute^   s:    NNDyyN*77= # r   c                P    t        |j                        D ]  \  }}|| k(  s|c S  y)N)	enumerateinput)node_output
child_nodeindex
input_names       r   input_indexzFusion.input_indexf   s.    !*:+;+;!<E:[( "= r   c                   g }| j                   j                  D ]m  }|j                  d      r|j                  |j                         0|j                  d      r|j                  |j
                         ]|j                  d       o |S )N	dim_value	dim_param?)shapedimHasFieldappendrI   rJ   )tensor_type
shape_listds      r   tensor_shape_to_listzFusion.tensor_shape_to_listm   so    
""&&Azz+&!!!++.K(!!!++.!!#& ' r   c                    t        |j                        D ](  \  }}| j                  j                  |      }|$||fc S  y)NNN)rA   rB   r   get_constant_value)r   r   iinpr=   s        r   get_constant_inputzFusion.get_constant_inputy   sA    

+FAsJJ11#6E %x ,
 r   c                t    | j                  |      \  }}|"|j                  dk(  rt        ||z
        |k  r|S y)Nr'   r@   )rY   sizeabs)r   r   expected_valuedeltarW   r=   s         r   find_constant_inputzFusion.find_constant_input   s@    **405qS9O5PSX5XHr   c                .    | j                  |||      dk\  S Nr   )r_   )r   r   r]   r^   s       r   has_constant_inputzFusion.has_constant_input   s    ''neDIIr   c                r    | j                   j                  |      }|yt        |j                        |k7  ryyr.   )r   rV   lenrL   )r   output_namerankr=   s       r   is_constant_with_specified_rankz&Fusion.is_constant_with_specified_rank   s5    

--k:=u{{t#r   Nc                    || j                   j                         }t        |j                        D ])  \  }}||v s||   }|j                  |k(  s ||vs%||fc S  y)a  
        Find parent node based on constraints on op_type.

        Args:
            node: current node.
            parent_op_type (str): constraint of parent node op_type.
            output_name_to_node (dict): dictionary with output name as key, and node as value.
            exclude (list): list of nodes that are excluded (not allowed to match as parent).

        Returns:
            parent: The matched parent node. None if not found.
            index: The input index of matched parent node. None if not found.
        rU   )r   r   rA   rB   r   )r   r   parent_op_typer   excluderW   rX   parents           r   match_first_parentzFusion.match_first_parent   si    ( &"&**"@"@"B

+FAs)),S1>>^3g8M!19$	 , r   c                L   |J ||dk\  sJ || j                   j                         }|,| j                  ||||      \  }}||j                  |       |S |t	        |j
                        k\  ry| j                   j                  |||      }||j                  |k(  r||vr|S y)a*  
        Find parent node based on constraints on op_type and index.
        When input_index is None, we will find the first parent node based on constraints,
        and return_indice will be appended the corresponding input index.

        Args:
            node (str): current node name.
            parent_op_type (str): constraint of parent node op_type.
            input_index (int or None): only check the parent given input index of current node.
            output_name_to_node (dict): dictionary with output name as key, and node as value.
            exclude (list): list of nodes that are excluded (not allowed to match as parent).
            return_indice (list): a list to append the input index when input_index is None.

        Returns:
            parent: The matched parent node.
        Nr   )r   r   rl   rO   rd   rB   
get_parentr   )	r   r   ri   rG   r   rj   return_indicerk   rE   s	            r   match_parentzFusion.match_parent   s    2 "kQ&666&"&**"@"@"B 33D.J]_fgMFE($$U+M#djj/)&&t[:MN&..N"BvU\G\Mr   c           	        |t        |      t        |      k(  sJ || j                  j                         }|}g }t        |      D ]:  \  }}	| j	                  ||	|||   nd|g |      }
|
 y|j                  |
       |
}< |S )aJ  
        Find a sequence of input edges based on constraints on parent op_type and index.
        When input_index is None, we will find the first parent node based on constraints,
        and return_indice will be appended the corresponding input index.

        Args:
            node (str): current node name.
            parent_op_types (str): constraint of parent node op_type of each input edge.
            parent_input_index (list): constraint of input index of each input edge. None means no constraint.
            output_name_to_node (dict): dictionary with output name as key, and node as value.
            return_indice (list): a list to append the input index
                                  When there is no constraint on input index of an edge.

        Returns:
            parents: a list of matched parent node.
        N)rj   ro   )rd   r   r   rA   rp   rO   )r   r   parent_op_typesparent_input_indexr   ro   current_nodematched_parentsrW   r   matched_parents              r   match_parent_pathzFusion.match_parent_path   s    0 ))*c/.BBBB&"&**"@"@"B#O4JAw!..);)G"1%T#+ / N %"">2)L 5 r   c                v    t        |      D ]+  \  }}g }| j                  ||d   |d   ||      }|s&|||fc S  y)z@
        Find a matching parent path to the given node.
        r   r'   )r@   NN)rA   rw   )r   r   pathsr   rW   pathro   matcheds           r   match_parent_pathszFusion.match_parent_paths  sS     !'GAtM,,T47DGEXZghG'=00	 (
 r   c                :   | j                   j                  ||      }t        |      }t        |      dkD  rf|j	                         }|j
                  |k(  r|S |r4| j                   j                  ||      }|D ]  }|j                  |        t        |      dkD  rfy ra   )r   get_childrenr   rd   popr   
appendleft)	r   r   
child_typer   	recursivechildrendqrt   childs	            r   find_first_child_by_typezFusion.find_first_child_by_type$  s     ::**41DE8_"gk668L##z1##::22<ATU%EMM%( & "gk r   )r   r   r   strr   r   )r   onnx.NodeProtor   dict[str, list[onnx.NodeProto]]r   dict[str, onnx.NodeProto])returnr"   )
r   list[onnx.NodeProto]r0   	list[str]r   r   r   r   r   r"   )r   r   r;   r   )rC   r   rD   r   r   int)r   z	list[int])r   r   )gư>)r   r   r]   floatr^   r   r   r   )r   r   r]   r   r^   r   r   r"   )re   r   rf   r   r   r"   )
r   r   ri   r   r    dict[str, onnx.NodeProto] | Nonerj   r   r   z(tuple[onnx.NodeProto | None, int | None])r   r   ri   r   rG   z
int | Noner   r   rj   r   ro   list[int] | Noner   onnx.NodeProto | None)NNN)r   r   rr   r   rs   r   r   r   ro   r   r   zlist[onnx.NodeProto] | None)r   r   ry   z!list[tuple[list[str], list[int]]]r   r   r   z9tuple[int, list[onnx.NodeProto] | None, list[int] | None])NT)
r   r   r   r   r   z&dict[str, list[onnx.NodeProto]] | Noner   r"   r   r   )__name__
__module____qualname____doc__r   r   r%   r,   staticmethodr4   r>   rG   rS   rY   r_   rb   rg   rl   rp   rw   r|   r    r   r   r   r      s   *
"
" =
" 7	
"*
 - = 7	
 
 $     	 	J AE(*  >	
 & 
2F #'@D(**.-- -  	-
 >- &- (- 
-f 04@D*.// #/ -	/
 >/ (/ 
%/b 1 7	
 
C( GK  D	
  
r   r   )
__future__r   collectionsr   r8   
onnx_modelr   r   r   r   r   <module>r      s    #   "h hr   