o
    \h.                     @  s>   d dl mZ d dlmZ d dlZddlmZ G dd dZdS )    )annotations)dequeN   )	ONNXModelc                   @  s   e Zd ZdZdTddZdUddZdVddZdd ZedWddZ	edXddZ
edYd#d$ZedZd&d'Zd[d(d)Zd\d]d.d/Zd\d^d0d1Zd_d4d5Zd6g fd`d;d<Zd6d6g d6fdadBdCZ	6	6	6dbdcdGdHZdddLdMZ	6	NdedfdRdSZd6S )gFusionz!
    Base class for fusions.
    modelr   fused_op_typestrsearch_op_typec                 C  s>   || _ || _|| _g | _g | _| jd | j  d | _d | _d S )N_fused__)r
   r   r   nodes_to_removenodes_to_add_new_node_name_prefix_new_node_name_suffix)selfr   r   r
    r   j/home/air/segue/gemini/backup/venv/lib/python3.10/site-packages/onnxruntime/quantization/fusions/fusion.py__init__   s   
zFusion.__init__nodeonnx.NodeProtoinput_name_to_nodesdict[str, list[onnx.NodeProto]]output_name_to_nodedict[str, onnx.NodeProto]c                 C  s   t )z
        Interface function for derived fusion classes. Tries to fuse a node sequence containing
        the specified node.
        )NotImplementedError)r   r   r   r   r   r   r   fuse   s   
zFusion.fusereturnboolc                 C  s|   | j  }| j  }| j  D ]}|j| jkr| ||| q| j | j | j 	| j
 t| jp3| j
}|r<| j   |S )z?
        Apply graph fusion on the entire model graph.
        )r   r   r   nodesop_typer
   r   remove_nodesr   	add_nodesr   r   remove_unused_constant)r   r   r   r   graph_updatedr   r   r   apply*   s   


zFusion.applyc                 C  sF   | j }| jd u r| j|}|d | _| | j}|  jd7  _|S )N   )r   r   r   get_largest_node_name_suffix)r   prefixlargest_suffixnew_namer   r   r   create_unique_node_name?   s   

zFusion.create_unique_node_namer   list[onnx.NodeProto]keep_outputs	list[str]c                 C  sL   | D ]!}|j D ]}||v rq||v r"|| D ]}|| vr!   dS qqqdS NFT)output)r   r-   r   r   node_to_removeoutput_to_removeimpacted_noder   r   r   is_safe_to_fuse_nodesK   s   

	zFusion.is_safe_to_fuse_nodesattribute_namec                 C  s.   | j D ]}|j|krtj|}|  S qd S )N)	attributenameonnxhelperget_attribute_value)r   r5   attrvaluer   r   r   get_node_attribute^   s   

zFusion.get_node_attributenode_output
child_nodeintc                 C  s(   t |jD ]\}}|| kr|  S qdS )N)	enumerateinput)r>   r?   index
input_namer   r   r   input_indexf   s
   zFusion.input_index	list[int]c                 C  sP   g }| j jD ]}|dr||j q|dr ||j q|d q|S )N	dim_value	dim_param?)shapedimHasFieldappendrH   rI   )tensor_type
shape_listdr   r   r   tensor_shape_to_listm   s   

zFusion.tensor_shape_to_listc                 C  s8   t |jD ]\}}| j|}|d ur||f  S qdS )NNN)rB   rC   r   get_constant_value)r   r   iinpr<   r   r   r   get_constant_inputy   s   zFusion.get_constant_inputư>expected_valuefloatdeltac                 C  s8   |  |\}}|d ur|jdkrt|| |k r|S dS )Nr&   rA   )rW   sizeabs)r   r   rY   r[   rU   r<   r   r   r   find_constant_input   s   "zFusion.find_constant_inputc                 C  s   |  |||dkS Nr   )r^   )r   r   rY   r[   r   r   r   has_constant_input   s   zFusion.has_constant_inputoutput_namerankc                 C  s.   | j |}|d u rdS t|j|krdS dS r/   )r   rT   lenrK   )r   ra   rb   r<   r   r   r   is_constant_with_specified_rank   s   z&Fusion.is_constant_with_specified_rankNparent_op_type dict[str, onnx.NodeProto] | Noneexclude(tuple[onnx.NodeProto | None, int | None]c                 C  sX   |du r	| j  }t|jD ]\}}||v r)|| }|j|kr)||vr)||f  S qdS )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.
        NrS   )r   r   rB   rC   r    )r   r   re   r   rg   rU   rV   parentr   r   r   match_first_parent   s   
zFusion.match_first_parentrF   
int | Nonereturn_indicelist[int] | Noneonnx.NodeProto | Nonec           	      C  s   |dusJ |du s|dksJ |du r| j  }|du r2| ||||\}}|dur0|| |S |t|jkr;dS | j |||}|durR|j|krR||vrR|S dS )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   rj   rN   rc   rC   
get_parentr    )	r   r   re   rF   r   rg   rl   ri   rD   r   r   r   match_parent   s   

zFusion.match_parentparent_op_typesparent_input_indexlist[onnx.NodeProto] | Nonec              	   C  s   |durt |t |ksJ |du r| j }|}g }t|D ]%\}}	| j||	|dur/|| nd|g |d}
|
du r= dS ||
 |
}q|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)rg   rl   )rc   r   r   rB   rp   rN   )r   r   rq   rr   r   rl   current_nodematched_parentsrU   r    matched_parentr   r   r   match_parent_path   s(   

zFusion.match_parent_pathpaths!list[tuple[list[str], list[int]]]9tuple[int, list[onnx.NodeProto] | None, list[int] | None]c                 C  sF   t |D ]\}}g }| ||d |d ||}|r |||f  S qdS )z@
        Find a matching parent path to the given node.
        r   r&   )rA   NN)rB   rw   )r   r   rx   r   rU   pathrl   matchedr   r   r   match_parent_paths  s   	zFusion.match_parent_pathsT
child_type&dict[str, list[onnx.NodeProto]] | None	recursivec           	      C  sn   | j ||}t|}t|dkr5| }|j|kr|S |r/| j ||}|D ]}|| q't|dksd S r_   )r   get_childrenr   rc   popr    
appendleft)	r   r   r~   r   r   childrendqrt   childr   r   r   find_first_child_by_type$  s   

zFusion.find_first_child_by_type)r   r   r   r	   r
   r	   )r   r   r   r   r   r   )r   r   )
r   r,   r-   r.   r   r   r   r   r   r   )r   r   r5   r	   )r>   r	   r?   r   r   r@   )r   rG   )r   r   )rX   )r   r   rY   rZ   r[   rZ   r   r@   )r   r   rY   rZ   r[   rZ   r   r   )ra   r	   rb   r@   r   r   )
r   r   re   r	   r   rf   rg   r,   r   rh   )r   r   re   r	   rF   rk   r   rf   rg   r,   rl   rm   r   rn   )NNN)r   r   rq   r.   rr   rm   r   rf   rl   rm   r   rs   )r   r   rx   ry   r   r   r   rz   )NT)
r   r   r~   r	   r   r   r   r   r   rn   )__name__
__module____qualname____doc__r   r   r%   r+   staticmethodr4   r=   rF   rR   rW   r^   r`   rd   rj   rp   rw   r}   r   r   r   r   r   r      sD    





#3
1r   )
__future__r   collectionsr   r8   
onnx_modelr   r   r   r   r   r   <module>   s
   