
    h.                    D    S SK Jr  S SKJr  S SKrSSKJr   " S S5      rg)    )annotations)dequeN   )	ONNXModelc                     \ rS rSrSrSS jr      SS jrSS jrS r\	          SS j5       r
\	SS j5       r\	SS	 j5       r\	SS
 j5       rSS jrSSS jjrSS S jjrS!S jrS/ 4         S"S jjrSS/ S4             S#S jjr   S$           S%S jjr        S&S jr  S'         S(S jjrSrg))Fusion   z
Base class for fusions.
c                    X0l         X l        Xl        / U l        / U l        U R                  S-   U R                   -   S-   U l        S U l        g )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       a/var/www/fran/franai/venv/lib/python3.13/site-packages/onnxruntime/quantization/fusions/fusion.py__init__Fusion.__init__   sO    #1"/ %
%'"$%)%7%7)%CdFYFY%Y\_%_"%)"    c                    [         e)zm
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   fuseFusion.fuse   s
     "!r   c                2   U R                   R                  5       nU R                   R                  5       nU R                   R                  5        H1  nUR                  U R
                  :X  d  M  U R                  X1U5        M3     U R                   R                  U R                  5        U R                   R                  U R                  5        [        U R                  =(       d    U R                  5      nU(       a  U R                   R                  5         U$ )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   applyFusion.apply*   s     #jj<<>"jj<<>JJ$$&D||t222		$5HI ' 	

 4 45

T../T11FT5F5FGJJ--/r   c                    U R                   nU R                  c%  U R                  R                  U5      nUS-   U l        U U R                  < 3nU =R                  S-  sl        U$ )N   )r   r   r   get_largest_node_name_suffix)r   prefixlargest_suffixnew_names       r   create_unique_node_nameFusion.create_unique_node_name?   se    ++%%-"&**"I"I&"QN)7!);D&Xd88;<""a'"r   c                    U  H8  nUR                    H%  nXQ;   a  M
  XR;   d  M  X%    H  nX`;  d  M
        g   M'     M:     gNFT)output)r   keep_outputsr   r   node_to_removeoutput_to_removeimpacted_nodes          r   is_safe_to_fuse_nodesFusion.is_safe_to_fuse_nodesK   sJ     .N$2$9$9 #3#:)<)N(?#( *O %: . r   c                    U R                    H6  nUR                  U:X  d  M  [        R                  R	                  U5      nUs  $    g )N)	attributenameonnxhelperget_attribute_value)r   attribute_nameattrvalues       r   get_node_attributeFusion.get_node_attribute^   s:    NNDyyN*77= # r   c                R    [        UR                  5       H  u  p#X0:X  d  M  Us  $    g)N)	enumerateinput)node_output
child_nodeindex
input_names       r   input_indexFusion.input_indexf   s*    !*:+;+;!<E( "= r   c                2   / nU R                   R                   Hz  nUR                  S5      (       a  UR                  UR                  5        M6  UR                  S5      (       a  UR                  UR
                  5        Mi  UR                  S5        M|     U$ )N	dim_value	dim_param?)shapedimHasFieldappendrQ   rR   )tensor_type
shape_listds      r   tensor_shape_to_listFusion.tensor_shape_to_listm   su    
""&&Azz+&&!!!++.K((!!!++.!!#& ' r   c                    [        UR                  5       H(  u  p#U R                  R                  U5      nUc  M%  X$4s  $    g)NNN)rH   rI   r   get_constant_value)r   r   iinprC   s        r   get_constant_inputFusion.get_constant_inputy   s=    

+FAJJ11#6E x ,
 r   c                v    U R                  U5      u  pEUb#  UR                  S:X  a  [        XR-
  5      U:  a  U$ g)Nr+   rG   )rb   sizeabs)r   r   expected_valuedeltar`   rC   s         r   find_constant_inputFusion.find_constant_input   s<    **40qS9O5PSX5XHr   c                ,    U R                  XU5      S:  $ Nr   )ri   )r   r   rg   rh   s       r   has_constant_inputFusion.has_constant_input   s    ''eDIIr   c                v    U R                   R                  U5      nUc  g[        UR                  5      U:w  a  ggr3   )r   r_   lenrT   )r   output_namerankrC   s       r   is_constant_with_specified_rank&Fusion.is_constant_with_specified_rank   s5    

--k:=u{{t#r   Nc                    Uc  U R                   R                  5       n[        UR                  5       H,  u  pVXc;   d  M  X6   nUR                  U:X  d  M"  Xt;  d  M)  Xu4s  $    g)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.
r^   )r   r   rH   rI   r"   )r   r   parent_op_typer   excluder`   ra   parents           r   match_first_parentFusion.match_first_parent   s^    ( &"&**"@"@"B

+FA),1>>^38M!9$	 , r   c                X   Uc   eUb  US:  d   eUc  U R                   R                  5       nUc*  U R                  XXE5      u  pxUb  UR                  U5        U$ U[	        UR
                  5      :  a  gU R                   R                  XU5      nUb  UR                  U:X  a  Xu;  a  U$ g)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   ry   rW   rp   rI   
get_parentr"   )	r   r   rv   rN   r   rw   return_indicerx   rL   s	            r   match_parentFusion.match_parent   s    2 "kQ&666&"&**"@"@"B 33DJ]gMF($$U+M#djj/)&&t:MN&..N"BvG\Mr   c           
        Ub  [        U5      [        U5      :X  d   eUc  U R                  R                  5       nUn/ n[        U5       H8  u  pU R	                  UU	Ub  X8   OSU/ US9n
U
c    gUR                  U
5        U
nM:     U$ )a  
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)rw   r}   )rp   r   r   rH   r~   rW   )r   r   parent_op_typesparent_input_indexr   r}   current_nodematched_parentsr`   r"   matched_parents              r   match_parent_pathFusion.match_parent_path   s    0 ))*c/.BBBB&"&**"@"@"B#O4JA!..);)G"%T#+ / N %"">2)L 5 r   c                |    [        U5       H-  u  pE/ nU R                  XS   US   X65      nU(       d  M)  XGU4s  $    g)z0
Find a matching parent path to the given node.
r   r+   )rG   NN)rH   r   )r   r   pathsr   r`   pathr}   matcheds           r   match_parent_pathsFusion.match_parent_paths  sL     !'GAM,,T7DGEXhGw=00	 (
 r   c                L   U R                   R                  X5      n[        U5      n[        U5      S:  ao  UR	                  5       nUR
                  U:X  a  U$ U(       a5  U R                   R                  Xs5      nU H  nUR                  U5        M     [        U5      S:  a  Mo  g rl   )r   get_childrenr   rp   popr"   
appendleft)	r   r   
child_typer   	recursivechildrendqr   childs	            r   find_first_child_by_typeFusion.find_first_child_by_type$  s     ::**4E8_"gk668L##z1##::22<U%EMM%( & "gk r   )r   r   r   r   r   r   r   )r   r   r   strr   r   )r   onnx.NodeProtor   dict[str, list[onnx.NodeProto]]r   dict[str, onnx.NodeProto])returnr%   )
r   list[onnx.NodeProto]r5   	list[str]r   r   r   r   r   r%   )r   r   rA   r   )rJ   r   rK   r   r   int)r   z	list[int])r   r   )gư>)r   r   rg   floatrh   r   r   r   )r   r   rg   r   rh   r   r   r%   )rq   r   rr   r   r   r%   )
r   r   rv   r   r    dict[str, onnx.NodeProto] | Nonerw   r   r   z(tuple[onnx.NodeProto | None, int | None])r   r   rv   r   rN   z
int | Noner   r   rw   r   r}   list[int] | Noner   onnx.NodeProto | None)NNN)r   r   r   r   r   r   r   r   r}   r   r   zlist[onnx.NodeProto] | None)r   r   r   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____firstlineno____doc__r   r   r(   r0   staticmethodr9   rD   rN   r[   rb   ri   rm   rs   ry   r~   r   r   r   __static_attributes__ 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   r>   
onnx_modelr   r   r   r   r   <module>r      s    #   "h hr   