o
    i.                     @  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 )NZ_fused__)r
   r   r   nodes_to_removenodes_to_add_new_node_name_prefix_new_node_name_suffix)selfr   r   r
    r   a/home/kim/smarthome/.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   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 u 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_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   Znode_to_removeZoutput_to_removeZ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helperZget_attribute_value)r   r+   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)r3   r4   indexZ
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dimZHasFieldappendr<   r=   )Ztensor_typeZ
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)r7   r8   r   get_constant_value)r   r   iinpr1   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!   r6   )rH   sizeabs)r   r   rJ   rL   rF   r1   r   r   r   find_constant_input   s   "zFusion.find_constant_inputc                 C  s   |  |||dkS Nr   )rO   )r   r   rJ   rL   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   rE   lenr?   )r   rR   rS   r1   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.
        NrD   )r   r   r7   r8   r   )r   r   rV   r   rX   rF   rG   parentr   r   r   match_first_parent   s   
zFusion.match_first_parentr:   
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   r[   rA   rT   r8   Z
get_parentr   )	r   r   rV   r:   r   rX   r]   rZ   r9   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)rX   r]   )rT   r   r   r7   r`   rA   )r   r   ra   rb   r   r]   current_nodeZmatched_parentsrF   r   Z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!   )r6   NN)r7   re   )r   r   rf   r   rF   pathr]   Z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 rP   )r   Zget_childrenr   rT   popr   
appendleft)	r   r   rk   r   rm   childrenZdqrd   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   r+   r	   )r3   r	   r4   r   r   r5   )r   r;   )r   r   )rI   )r   r   rJ   rK   rL   rK   r   r5   )r   r   rJ   rK   rL   rK   r   r   )rR   r	   rS   r5   r   r   )
r   r   rV   r	   r   rW   rX   r%   r   rY   )r   r   rV   r	   r:   r\   r   rW   rX   r%   r]   r^   r   r_   )NNN)r   r   ra   r'   rb   r^   r   rW   r]   r^   r   rc   )r   r   rf   rg   r   r   r   rh   )NT)
r   r   rk   r	   r   rl   rm   r   r   r_   )__name__
__module____qualname____doc__r   r   r    r$   staticmethodr*   r2   r:   rC   rH   rO   rQ   rU   r[   r`   re   rj   rr   r   r   r   r   r      sD    



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