o
    Hh%                     @   s  d dl Z d dlmZ d dlmZ d dlZd dlm	Z	 d dl
mZ d dlmZ d dlmZ d dlmZmZmZ d d	lmZ e	d
ddedefddZe	d
ddedefddZe	d
d	d'd
ddedededeeedf  dedeeeedf eedf f fddZe	d
ddededeedf deedf fddZe	d
ddedefd d!Ze	d
d	"	
d(ded#eeedf  d$ededef
d%d&Z dS ))    N)SimpleQueue)Optional)compatibility)Graph)GraphModule)Node)legalize_graphNodeListNodeSet)lift_subgraph_as_moduleF)is_backward_compatiblenodesreturnc                 C   s   t | d}t }| D ]}|jD ]}||v r||  d7  < q|| dkr*|| qg }| s[| }|| |jD ]}||v rV||  d8  < || dkrV|| q=| r1t	| t	|ksgJ d|S )Nr      z@topological sorted nodes doesn't have same length as input nodes)
dictfromkeysr   all_input_nodesputemptygetappenduserslen)r   indegree_map
candidatesnodensorted_nodes r   U/var/www/vscode/kcb/lib/python3.10/site-packages/torch/fx/passes/utils/fuser_utils.py	topo_sort   s6   





r    	partitionc                    sZ   t |  g } D ]}|jD ]}| vr|| qqdtdtf fdd}||r+dS dS )N
root_nodesr   c                    sT   t  }| }|r(| }|| | v rdS |jD ]}||v r q|| q|sdS )NTF)setpopaddr   r   )r"   visitedqueuecurrent	user_nodepartition_setr   r   bfs_find_cycle?   s   

z*validate_partition.<locals>.bfs_find_cycleFT)r#   r   r   r	   bool)r!   outputsr   r)   r,   r   r*   r   validate_partition.   s   

r/   always_return_tuplegmmodule_namepartition_lookup_tabler1   .c                   sh  |D ].}|j j| u sJ | d|   |jrJ | d|| j jv s0J | d|   qt|s9J ddu rBt|t i i   fdd}|D ]}	||}| |< qTi }|D ]}|j
D ]}	|	vrv | ||< qjqet| }
|r|
 nt|
dkr|
d	 n|
   t| d
|d\}}t }t| }|||fS )a  
    Fuse nodes in graph_module into a GraphModule.

    Args:
        gm (GraphModule): target graph_module

        nodes (List[Node]): list of nodes in `gm` to fuse, where the node must be topologically sorted

        module_name: class name for the fused GraphModule

        partition_lookup_table (Optional[Dict[Node, None]]): optional dict of nodes to speed up lookup

        always_return_tuple (bool): whether to always return a tuple, even if there is only one output

    Returns:
        fused_gm (GraphModule): fused graph module, where its node is a copy of `nodes` in `gm`

        original_inputs (Tuple[Node, ...]): input nodes to `nodes` in original `gm`

        original_outputs (Tuple[Node, ...]): consumer nodes of `nodes` in original `gm`

    z* doesn't belong to passed in graph module z# has been removed from owning graphz is not found in graph module z*Invalid partition, found dependency cyclesNc                    sT   | j dkr	 | v r |  S | vr&j| j| jd}t| j|_|| < |  S )Nget_attr)	type_expr)opplaceholdernametypecopymeta)xplaceholder_nodenode_mapnode_to_placeholderr4   subgraphr   r   remap_inputs   s   
z)fuse_as_graphmodule.<locals>.remap_inputsr   r    )	comp_name
class_name)graphowning_module	_get_name_erased_find_nodes_lookup_tabler/   r   r   r   	node_copyr   tuplevaluesoutputr   lintr   keys)r2   r   r3   r4   r1   r   rC   new_nodeoutput_mappingr)   outsfused_gm_original_inputsoriginal_outputsr   r?   r   fuse_as_graphmodule_   sJ   "




rY   sub_gmorig_inputsorig_outputsc           
      C   s   |j j}| || | jj||d d}|j }t|dkr1t|jd t	s1|d j
|dd | S t|D ]\}}tj|| j}	|j
|	dd q5t	dd |D |jd< | S )	N)argskwargsr   r   T)propagate_metac                 s   s    | ]
}|j d dV  qdS )valN)r<   r   ).0orig_outputr   r   r   	<genexpr>   s    
zinsert_subgm.<locals>.<genexpr>r`   )	__class____name__add_submodulerG   call_moduleoutput_noder   
isinstancer]   rM   replace_all_uses_with	enumeratetorchfxProxyr   r<   )
r2   rZ   r[   r\   submodule_namemodule_noderh   irb   	proxy_outr   r   r   insert_subgm   s   

rs   c                 C   s   t |D ]}| j| qd S N)reversedrG   
erase_node)r2   r   r   r   r   r   erase_nodes   s   rw   fused_
partitionsprefixc                 C   sf   t |D ](\}}tt|}|t| }t| ||||d\}}	}
t| ||	|
 t| | qt|  | S )Nr0   )rk   r    liststrrY   rs   rw   r   )r2   ry   rz   r1   partition_idr!   r   ro   rZ   r[   r\   r   r   r   fuse_by_partitions   s   r~   rt   )rx   F)!r;   r'   r   typingr   	_Optionaltorch.fxrl   torch.fx._compatibilityr   torch.fx.graphr   torch.fx.graph_moduler   torch.fx.noder   torch.fx.passes.tools_commonr   r	   r
   torch.fx.passes.utilsr   r    r-   r/   r|   r   rM   rY   rs   rw   r{   r~   r   r   r   r   <module>   sr   0u

