U
    U?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                	   @  sr  e Zd ZdZddddddZddd	d
ddZddddZdd Zedddd	ddddZ	edddddZ
eddddddZeddd d!Zdd"d#d$ZdIdd&d&dd'd(d)ZdJdd&d&dd'd*d+Zdddd,d-d.Zd/g fddd0dd1d2d3d4Zd/d/g d/fddd5d0dd6d7d8d9d:ZdKddd6d0d6d;d<d=d>Zdd?d	d@dAdBdCZdLdddEdd7dFdGdHZd/S )MFusionz!
    Base class for fusions.
    r   str)modelfused_op_typesearch_op_typec                 C  s>   || _ || _|| _g | _g | _| jd | j  d | _d | _d S )NZ_fused__)r
   r	   r   nodes_to_removenodes_to_add_new_node_name_prefix_new_node_name_suffix)selfr   r	   r
    r   Y/var/www/html/venv/lib/python3.8/site-packages/onnxruntime/quantization/fusions/fusion.py__init__   s    zFusion.__init__zonnx.NodeProtozdict[str, list[onnx.NodeProto]]zdict[str, onnx.NodeProto])nodeinput_name_to_nodesoutput_name_to_nodec                 C  s   t dS )z
        Interface function for derived fusion classes. Tries to fuse a node sequence containing
        the specified node.
        N)NotImplementedError)r   r   r   r   r   r   r   fuse   s    
zFusion.fusebool)returnc                 C  s|   | j  }| j  }| j  D ]}|j| jkr| ||| q| j | j | j 	| j
 t| jpf| j
}|rx| j   |S )z?
        Apply graph fusion on the entire model graph.
        )r   r   r   Znodesop_typer
   r   Zremove_nodesr   Z	add_nodesr   r   Zremove_unused_constant)r   r   r   r   Zgraph_updatedr   r   r   apply*   s    


zFusion.applyc                 C  sF   | j }| jd kr&| j|}|d | _| | j}|  jd7  _|S )N   )r   r   r   Zget_largest_node_name_suffix)r   prefixZlargest_suffixnew_namer   r   r   create_unique_node_name?   s    

zFusion.create_unique_node_namezlist[onnx.NodeProto]z	list[str])r   keep_outputsr   r   r   c                 C  sL   | D ]B}|j D ]6}||krq||kr|| D ]}|| kr,   dS q,qqdS NFT)output)r   r!   r   r   Znode_to_removeZoutput_to_removeZimpacted_noder   r   r   is_safe_to_fuse_nodesK   s    
zFusion.is_safe_to_fuse_nodes)r   attribute_namec                 C  s.   | j D ]"}|j|krtj|}|  S qd S )N)	attributenameonnxhelperZget_attribute_value)r   r%   attrvaluer   r   r   get_node_attribute^   s
    


zFusion.get_node_attributeint)node_output
child_noder   c                 C  s(   t |jD ]\}}|| kr
|  S q
dS )N)	enumerateinput)r.   r/   indexZ
input_namer   r   r   input_indexf   s    
zFusion.input_indexz	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dimZHasFieldappendr5   r6   )Ztensor_typeZ
shape_listdr   r   r   tensor_shape_to_listm   s    

zFusion.tensor_shape_to_list)r   c                 C  s8   t |jD ](\}}| j|}|d k	r
||f  S q
dS )NNN)r1   r2   r   get_constant_value)r   r   iinpr+   r   r   r   get_constant_inputy   s
    zFusion.get_constant_inputư>float)r   expected_valuedeltar   c                 C  s8   |  |\}}|d k	r4|jdkr4t|| |k r4|S dS )Nr   r0   )rA   sizeabs)r   r   rD   rE   r?   r+   r   r   r   find_constant_input   s    "zFusion.find_constant_inputc                 C  s   |  |||dkS Nr   )rH   )r   r   rD   rE   r   r   r   has_constant_input   s    zFusion.has_constant_input)output_namerankr   c                 C  s.   | j |}|d krdS t|j|kr*dS dS r"   )r   r>   lenr8   )r   rK   rL   r+   r   r   r   is_constant_with_specified_rank   s    z&Fusion.is_constant_with_specified_rankNz dict[str, onnx.NodeProto] | Nonez(tuple[onnx.NodeProto | None, int | None])r   parent_op_typer   excluder   c                 C  sX   |dkr| j  }t|jD ]6\}}||kr|| }|j|kr||k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.
        Nr=   )r   r   r1   r2   r   )r   r   rO   r   rP   r?   r@   parentr   r   r   match_first_parent   s    
zFusion.match_first_parentz
int | Nonezlist[int] | Nonezonnx.NodeProto | None)r   rO   r4   r   rP   return_indicer   c           	      C  s   |dk	st |dks |dks t |dkr2| j }|dkrd| ||||\}}|dk	r`|| |S |t|jkrvdS | j|||}|dk	r|j|kr||kr|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   )	AssertionErrorr   r   rR   r:   rM   r2   Z
get_parentr   )	r   r   rO   r4   r   rP   rS   rQ   r3   r   r   r   match_parent   s    

zFusion.match_parentzlist[onnx.NodeProto] | None)r   parent_op_typesparent_input_indexr   rS   r   c              	   C  s   |dk	rt |t |kst|dkr.| j }|}g }t|D ]J\}}	| j||	|dk	r^|| nd|g |d}
|
dkrz 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)rP   rS   )rM   rT   r   r   r1   rU   r:   )r   r   rV   rW   r   rS   current_nodeZmatched_parentsr?   r   Zmatched_parentr   r   r   match_parent_path   s(    

zFusion.match_parent_pathz!list[tuple[list[str], list[int]]]z9tuple[int, list[onnx.NodeProto] | None, list[int] | None])r   pathsr   r   c                 C  sF   t |D ]8\}}g }| ||d |d ||}|r|||f  S qdS )z@
        Find a matching parent path to the given node.
        r   r   )r0   NN)r1   rY   )r   r   rZ   r   r?   pathrS   Zmatchedr   r   r   match_parent_paths  s    	zFusion.match_parent_pathsTz&dict[str, list[onnx.NodeProto]] | None)r   
child_typer   	recursiver   c           	      C  sd   | j ||}t|}t|dkr`| }|j|kr8|S |r| j ||}|D ]}|| qNqd S rI   )r   Zget_childrenr   rM   popr   
appendleft)	r   r   r]   r   r^   childrenZdqrX   childr   r   r   find_first_child_by_type$  s    
zFusion.find_first_child_by_type)rB   )rB   )NNN)NT)__name__
__module____qualname____doc__r   r   r   r    staticmethodr$   r,   r4   r<   rA   rH   rJ   rN   rR   rU   rY   r\   rc   r   r   r   r   r      sB   
#3   1  r   )
__future__r   collectionsr   r(   Z
onnx_modelr   r   r   r   r   r   <module>   s   