U
    d-                     @   s   d dl mZmZ d dlmZmZmZ d dlZd dl	m
Z
 d dlmZ ddlmZmZ d dlmZ edd	d
d Zedd	dd Zedd	eG dd dZedd	G dd de
jZedd	ejjee ejjdddZdS )    )	dataclassfield)ListOptionalDictN)map_arg   )NodeListNodeSet)compatibilityF)Zis_backward_compatiblec                 C   s0   | dD ] }t| |r$t| |} q
 d S q
| S )N.)splithasattrgetattr)objnamelayer r   ?/tmp/pip-unpacked-wheel-ua33x9lu/torch/fx/passes/split_utils.pygetattr_recursive   s
    
r   c                 C   sH   d|krt | || n.|d}tt| |d d|dd  | d S )Nr   r   r   )setattrr   setattr_recursiver   join)r   attrvaluer   r   r   r   r      s    
r   c                   @   s   e Zd ZU dZejjed< eed< e	ed< e
edZeed< e
edZeed< e
edZeed< e
edZeejjejjf ed	< e
edZee	 ed
< dZeejj ed< dS )	ComponentzX
    A component serves as a container for a subgraph we want to create afterwards.
    graphorderr   )default_factoryinput_placeholdersorig_inputsorig_outputsgetattr_mapsconstructor_argsNgm)__name__
__module____qualname____doc__torchfxGraph__annotations__intstrr   listr   r   r    r!   dictr"   r   Noder#   r$   r   GraphModuler   r   r   r   r      s   
"r   c                       s    e Zd ZdZ fddZ  ZS )HolderModulezy
    HolderModule is used to copy all the attributes from original module to submodules
    that uses the attributes
    c                    s,   t    | D ]\}}| || qd S N)super__init__items
add_module)selfdkv	__class__r   r   r6   ?   s    
zHolderModule.__init__)r%   r&   r'   r(   r6   __classcell__r   r   r=   r   r3   8   s   r3   )r$   tagsreturnc                    s  t jjjtddd}i i i }g }t t j }i }d}|D ].}tt j t||  |	   ||< qB| j
jD ]}	|	jdkr|dk	rtd|	}qz|	jdkr|j|	j|	jd||	< qz|	jd	krqzt|	d
stfdd||	j||	j D }
||	j   |	< tdd |
D dd} j|ks4t fdd} j
|	|}|	j|_||	<  |< qz|dkrtd||jd D ]4}|jd	kr|j|j|jd||< n
| qD ]"}|jdkrȈ| j	| q|D ]h ttj j} j
t|dkr$|d n| t i } j
jD ]}|jdkrNq:|j!}t"|t#sdt|$d}|}| }|dd D ]6}t||s|%|t i  t&||}t&||}q|d }t&||}t'||| q:t j(| j
 _)|j* jtt|j j+dd}t|dkr,|| jd < n,t, jD ] \}}t j-|| j||< q6q|t.|jd |j t dd |D }||jd D ](}|jd	krt'||jt&| |j! qt j(||S )a~  
    Splits a GraphModule using tags on its graph nodes. We honor the order of
    tags. For example, we have tags = ["a", "b", "c"], the function will create
    the initial submodules in the order of "a_0", "b_1", "c_2".

    To set a tag:
    gm.graph.nodes[idx].tag = "mytag"

    This will result in all nodes with the same tag being extracted and placed in their
    own submodule. For placeholder, output and get_attr node, the tag is ignored. placeholder
    and output nodes are created when needed while get_attr nodes get copied to submodules
    where they are used.

    Given the following module def:

    class SimpleModule(torch.nn.Module):
        def __init__(self):
            super().__init__()
            self.linear1 = torch.nn.Linear(...)
            self.linear2 = torch.nn.Linear(...)
            self.linear3 = torch.nn.Linear(...)

        def forward(self, in1, in2):
            r1 = self.linear1(in1)
            r2 = self.linear2(in2)
            r3 = torch.cat([r1, r2])
            return self.linear3(r3)

    Marking the node corresponding to in1 with the tag sc.REQUEST_ONLY.lower() results in the following split:

    ro_0:
    def forward(self, in1):
        self = self.root
        linear1 = self.linear1(in1)
        return linear1

    main_1:
    def forward(self, in2, linear1):
        self = self.root
        linear2 = self.linear2(in2)
        cat_1 = torch.cat([linear1, linear2])
        linear3 = self.linear3(cat_1)
        return linear3

    main_0:
    def forward(self, in1, in2):
        self = self.root
        ro_0 = self.ro_0(in1)
        main_1 = self.main_1(in2, ro_0)
        return main_1
    )xrA   c                 S   s   g }t | |j |S )zC
        Stores nodes in x to a list and returns the list.
        )r   append)rB   rr   r   r   flatten{   s    zsplit_by_tags.<locals>.flattenNoutputzMultiple output nodes in graph!placeholderZ	type_exprget_attrtagc                    s   g | ]}|j d kr | qS )>   rG   rI   )op).0rB   )node_to_componentr   r   
<listcomp>   s   
z!split_by_tags.<locals>.<listcomp>c                 s   s   | ]}|j V  qd S r4   )r   )rL   cr   r   r   	<genexpr>   s     z split_by_tags.<locals>.<genexpr>r   )defaultc                    s    j dkr8 jkr.jj j jdj < j  S  j dkrV  krV  S  jkrj  jjj	 j
 jd   jt fddtjD  S )NrI   rH   rG   c                 3   s   | ]\}} |kr|V  qd S r4   r   )rL   iyrB   r   r   rP      s      z4split_by_tags.<locals>.remap_func.<locals>.<genexpr>)rK   r"   r   rI   targettyper    rC   r   rG   r   addnext	enumeraterT   compZnode_remappingrM   Zused_in_mainrT   r   
remap_func   s$    

 


z!split_by_tags.<locals>.remap_funczGraph had no output node!r   )call_modulerI   r   )argskwargsc                 S   s   i | ]}|j |jqS r   )r   r$   )rL   r[   r   r   r   
<dictcomp>7  s      z!split_by_tags.<locals>.<dictcomp>)/r)   r*   nodeZArgumentr	   setr+   r   lenrC   r   ZnodesrK   RuntimeErrorrG   r   rV   r   AssertionErrorr_   r`   rJ   maxr   Z	node_copyrI   rW   r!   tuplemap__getitem__rF   r3   rU   
isinstancer.   r   r8   r   r   r2   r$   r]   r    rY   ZProxyr   )r$   r@   rE   Ztag_to_componentZall_componentsZmain_gZmain_remappingZoutput_noderJ   rb   Zupstream_componentsZmxr\   nrB   ZoutsrootrU   Ztarget_name_partscurrZorig_gmr   Zleaf_node_nameZ	leaf_nodeZ	main_noderR   oZ	main_rootr   rZ   r   split_by_tagsE   s    6	










"


rp   )Zdataclassesr   r   typingr   r   r   Ztorch.fxr)   Ztorch.nnnnZtorch.fx.graphr   Ztools_commonr	   r
   Ztorch.fx._compatibilityr   r   r   r   Moduler3   r*   r2   r.   rp   r   r   r   r   <module>   s"   
	
