U
    zh[                     @   s  d dl Z d dlZd dlZd dlZd dlZd dlZd dlmZ d dlmZm	Z	m
Z
mZ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mZ d dlmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z& ej'd	ej(d
ej)dej*dej+dej,diZ-eej.j/ dddZ0d>dddddee ee ee& ee1 ee$ ee e2ddddZ3eej.j/e2dddZ4eej.j/eej5j dddZ6eej.j/e2dddZ7eej.j/eej8 dddZ9eej.j/e2dd d!Z:eej.j/eej8 dd"d#Z;ej.j<ej.j<d$d%d&Z=eej.j/ eej.j/ d'd(d)Z>d?eej.j/ eej.j/ d'd*d+Z?eej.j/ e@d'd,d-ZAeej.j/ eej.j/ d'd.d/ZBd@ej.j/ej.j/e2dd0d1d2ZCej.j/dd3d4d5ZDej5jEd6d7d8ZFd9d: ZGej.j<ejHjIej5jEe	e1ef dd;d<d=ZJdS )A    N)	Parameter)AnyDictIterableListOptionalTupleType)
FakeTensor)ExportedProgram)_name_hoo_subgraph_placeholders_rename_without_collisions)	InputKind
OutputKind)_register_pytree_nodeContextFlattenFuncFromDumpableContextFn
GetAttrKeyKeyPathkeystr
MappingKeySequenceKeyToDumpableContextFntree_flatten_with_pathUnflattenFunc Zp_Zb_Zc_Zobj_token)input_placeholdersc                 C   s4  t tddd}dd l}ddlm} ddlm} t|t| kr^tdt|  dt| d	i }t	|| D ]\\}}	}
|
j
d
}t|trt|	tjstd|| dt|	 t|jt|	jkrtd|| d|j d|	j d	tt	|	j|jD ]\}\}}t|tjrt|jjjdkrtt|jjj}||kr|jj|}||kr
td|| d| d| d| n|t|tjr|jjjsn`|||jj||}|d krtd|
j d| d| d|jj d| dnt|d ||< |jj|kr|||jj \}}|dkrd||k rdtd|| d| d| d| |tjk r||krtd|| d| d| d| n@||krt|tjrqtd|| d| d| d| qqlt|tt tfrlt|	t|ks|	|krltd|| d| d|	 qld S )N)key_pathreturnc                 S   sx   | d }t |tst|jdkr6dt| dd  S | d }t |tsLtt|dd }| t| dd  S dS )zFor a given index into the flat_args, return a human readable string
        describing how to access it, e.g. "*args["foo"][0].bar"
        r   z*args   N   )
isinstancer   AssertionErroridxr   r   str)r   Zargs_kwargs_key_pathZ	kwarg_keyname r)   E/var/www/html/venv/lib/python3.8/site-packages/torch/_export/utils.py
get_keystr1   s    
z6_check_input_constraints_for_graph.<locals>.get_keystrr   )_convert_range_to_int)	try_solvez&Unexpected number of inputs (expected z, got )valzExpected input at z to be a tensor, but got z,Unexpected number of dimensions in input at z.shape (expected r!   z.shape[z] to be equal to z
, but got zExpected input z] = z to be of the form z, where z is an integerr#   z] to be >= z] to be <= z to be equal to )!r   r'   sympyZ@torch._export.passes.add_runtime_assertions_for_constraints_passr,   Ztorch.utils._sympy.solver-   lenRuntimeErrorzipmetagetr$   r
   torchTensortypeshape	enumerateZSymIntnodeexprZfree_symbolsnextitersubsZ	is_numberEqr(   intmathinffloat)r   flat_args_with_pathZrange_constraintsr+   r0   r,   r-   Zunification_mapr   argr;   Znode_valjZarg_dimZnode_dimsymbolZexisting_dimZsolutionZmin_valZmax_valr)   r)   r*   "_check_input_constraints_for_graph.   s     



 
(




 
rI   F)serialized_type_nameto_dumpable_contextfrom_dumpable_contextreturn_none_fields)cls
flatten_fnunflatten_fnrJ   rK   rL   rM   r    c          
   	      s   t  std  tttt tf dfdd}tt ttd fdd}tttt tf dfdd	}	d k	r~n||d k	r|n|}|d k|d kA rtd
  dt	 |||	||d d S )Nz7Only dataclasses can be registered with this function: )objr    c                    sh   g }g }g }t | D ]D}|jt| |j }}|d k	s: rP|| || q|| q|||gfS N)dataclassesfieldsr(   getattrappend)rQ   	flattened
flat_names
none_namesfr(   r/   )rM   r)   r*   default_flatten_fn   s    
z=register_dataclass_as_pytree_node.<locals>.default_flatten_fn)valuescontextr    c                    s&   |\}} f t t|| t |S rR   )dictr3   fromkeys)r\   r]   rX   rY   )rN   r)   r*   default_unflatten_fn   s    z?register_dataclass_as_pytree_node.<locals>.default_unflatten_fnc                    s(    | \}\}}dd t ||D |fS )Nc                 S   s   g | ]\}}t ||fqS r)   )r   ).0kvr)   r)   r*   
<listcomp>   s     z[register_dataclass_as_pytree_node.<locals>.default_flatten_fn_with_keys.<locals>.<listcomp>)r3   )rQ   rW   rX   rY   )rO   r)   r*   default_flatten_fn_with_keys   s    zGregister_dataclass_as_pytree_node.<locals>.default_flatten_fn_with_keysz7Both to_dumpable_context and from_dumpable_context for z must be None or registered.)rJ   Zflatten_with_keys_fnrK   rL   )
rS   is_dataclassr%   r   r   r   r   r   
ValueErrorr   )
rN   rO   rP   rJ   rK   rL   rM   r[   r`   re   r)   )rN   rO   rM   r*   !register_dataclass_as_pytree_node   s.    
  
rh   )programr;   r    c                 C   s   |j | jjkS )zM
    Checks if the given node is a parameter within the exported program
    )r(   graph_signatureinputs_to_parametersri   r;   r)   r)   r*   is_param   s    rm   c                 C   s&   t | |r"| jj|j }| j| S dS )z
    Returns the parameter associated with the given node in the exported program.
    Returns None if the node is not a parameter within the exported program
    N)rm   rj   rk   r(   
state_dict)ri   r;   Zparameter_namer)   r)   r*   	get_param   s    	

ro   c                 C   s   |j | jjkS )zJ
    Checks if the given node is a buffer within the exported program
    )r(   rj   inputs_to_buffersrl   r)   r)   r*   	is_buffer   s    rq   c                 C   s<   t | |r8| jj|j }|| jjkr.| j| S | j| S dS )z
    Returns the buffer associated with the given node in the exported program.
    Returns None if the node is not a buffer within the exported program
    N)rq   rj   rp   r(   Znon_persistent_buffers	constantsrn   )ri   r;   Zbuffer_namer)   r)   r*   
get_buffer   s    	


rs   c                 C   s   |j | jjkS )zZ
    Checks if the given node is a lifted tensor constant within the exported program
    )r(   rj   !inputs_to_lifted_tensor_constantsrl   r)   r)   r*   is_lifted_tensor_constant  s    ru   c                 C   s&   t | |r"| jj|j }| j| S dS )z
    Returns the lifted tensor constant associated with the given node in the exported program.
    Returns None if the node is not a lifted tensor constant within the exported program
    N)ru   rj   rt   r(   rr   )ri   r;   Zlifted_tensor_namer)   r)   r*   get_lifted_tensor_constant  s    	

rv   )gmr    c                    sl   ddl m} i  d}| jjD ]}||r0|d7 }| |< q|| |  fddddd}| jj|j_|  |S )z
    Splits the graph module into multiple submodules based on the node_call_back.
    The node_call_back should return True if the node is a delimiter. Delimiter will be
    the first node in the next submodule.
    r   )split_moduler!   c                    s    |  S rR   r)   r;   Z	split_mapr)   r*   <lambda>?      z"sequential_split.<locals>.<lambda>T)Zkeep_original_orderZkeep_original_node_name)Ztorch.fx.passes.split_modulerx   graphnodesZ_codegen	recompile)rw   node_call_backrx   Zsplit_idr;   Znew_gmr)   rz   r*   sequential_split-  s"    

r   )r~   r    c                    s    fdd| D S )z:Returns the nodes that match the node_call_back as a list.c                    s   g | ]} |r|qS r)   r)   ra   r;   r   r)   r*   rd   K  s      z nodes_filter.<locals>.<listcomp>r)   r~   r   r)   r   r*   nodes_filterI  s    r   c                 C   s.   t | |r|ndd }t|dkr*|d S dS )z
    Returns the first node that matches the node_call_back. If no node matches, returns None.
    When node_call_back is None, returns the first node in the node list.
    c                 S   s   dS )NTr)   ry   r)   r)   r*   r{   U  r|   znodes_first.<locals>.<lambda>r   N)r   r1   )r~   r   retr)   r)   r*   nodes_firstN  s    r   c                 C   s   t t| |S )z:Returns the number of nodes that match the node_call_back.)r1   r   r   r)   r)   r*   nodes_count[  s    r   c                 C   s   | D ]}|| q| S )z
    Sequentially visit the nodes list and invoke node_call_back on each element.
    Returns the nodes list after the node_call_back is invoked on each element.
    r)   )r~   r   r;   r)   r)   r*   	nodes_map`  s    
r   )old_nodenew_node
delete_oldr    c                 C   s(   |  | |r$| j  | j|  dS )z5
    Replace all uses of old_node with new_node.
    N)Zreplace_all_uses_withusersclearr}   
erase_node)r   r   r   r)   r)   r*   node_replace_j  s    

r   )call_mod_noder    c              	      s  | j dkst| jj}t| jts&tt|| j}dd |jjD }dd |jjD }dd |jjD }t	|| j
D ](\}}t|tjjstt||dd qt|j|  |D ]}|j|}	t||	dd qt|d	krt|d
krt|d	 j
d
kst|d	 j
d	  t tjjr0t|  dd n\t ttfrxtt| j dd }
t|
 fdd | j|  ntdt  dn| j|  W 5 Q R X |  |  |S )z
    Inline the submodule of the given node into the parent module.
    Note: we only support the case where submodule takes tensors inputs.
    Zcall_modulec                 s   s   | ]}|j d kr|V  qdS )placeholderNopr   r)   r)   r*   	<genexpr>  s     
 znode_inline_.<locals>.<genexpr>c                 s   s   | ]}|j d kr|V  qdS ))r   outputNr   r   r)   r)   r*   r     s    
 c                 S   s   g | ]}|j d kr|qS )r   r   r   r)   r)   r*   rd     s     
 z node_inline_.<locals>.<listcomp>Tr   r   r!   c                 S   s   | j dko| jtjkS )NZcall_function)r   targetoperatorgetitemry   r)   r)   r*   r{     s   
znode_inline_.<locals>.<lambda>c                    s   t |  | jd  ddS )Nr!   Tr   )r   args)Zget_item_nodeZ
new_outputr)   r*   r{     s   zUnsupported output type z2. Expect it to be a Node or a list/tuple of Nodes.)r   r%   r}   Zowning_moduler$   r   r'   rU   r~   r3   r   r6   fxNoder   Zinserting_beforeZ	node_copyr1   listtupler   r   keysr   r   NotImplementedErrorr8   Zdelete_all_unused_submodulesr   )r   rw   Zsub_gmZphsbodyr   phrF   r;   r   Zget_item_usersr)   r   r*   node_inline_v  sL    $
r   )modc           	      C   s~   t | j}|jd }dtji}g }| D ]D\}}dd t|j|D }|D ] }|dkr\qN|	t
|| qNq,t
j|dS )z
    Get source code and parse argument names using AST. The function returns
    a signature of the forward() function.

    # TODO: Directly provide inspect.signature compatible TS-d module.
    r   r   c                 S   s   g | ]
}|j qS r)   )rF   )ra   ar)   r)   r*   rd     s     z:_get_torch_jit_trace_forward_signature.<locals>.<listcomp>self)
parameters)astparsecoder   r   POSITIONAL_OR_KEYWORDitemsrU   r   rV   inspect	Signature)	r   Zast_modZast_func_defZarg_type_mapZ
param_listZarg_typeZ
param_typeZarg_name_listarg_namer)   r)   r*   &_get_torch_jit_trace_forward_signature  s    

r   c                 C   s\   t | tjjtjjfrBt| }t|jt|t| ksNtdnt	
| j}|j||jS )NzyArguments other than POSITIONAL_OR_KEYWORD kinds in forward() are not supported in _get_torch_jit_trace_forward_signature)r$   r6   ZjitZScriptModuleZTracedModuler   r1   r   r%   r   	signatureforwardbind	arguments)r   	fake_argsfake_kwargssigr)   r)   r*   _bind_signature_to_inputs  s    r   )rw   export_graph_signaturer   rr   r    c              
      s  dd }dd  i }t |||}	t|	\}
}dd |jD }t|
|D ]>\\}}}|rFt||ttj d fdd	|D  d
d qF|jD ]^}|j	tjkrq|j	tj
krd}n||j }tdd|}t||jjt|j	 | d
d q| jjD ]"}|jdkrqt||j|j q| jjD ]N}|jdkrT|j|ks@t||j  |_|_n|j|kr ||j |_q t|  |   |jD ]V}|jj|kst||jj |j_|j	tjkr|j|kr||j dd |_q|jD ]J}|jj|kr||jj |j_|j	tjkr|j|kr||j |_qt| D ]h}|| }||kr<t|tjs<|| }||kr<t d|r<|ttj | kr<|||< ||= q<dS )aQ  
    This pass is run at the end of _export_non_strict() to assign better placeholder node names:
        - User inputs:
            These follow the signature of mod.forward(), e.g. forward(x, y) produces nodes x, y.
            For nested inputs from dictionaries, lists, tuples, or dataclasses,
            the names are a concatenation of the path to the tensor.
                e.g. x = {
                    'a': torch.randn(),
                    'b': [torch.randn(), torch.randn()]
                }
            produces nodes x_a, x_b_0, x_b_1.
        - Parameters/buffers/constants/custom objects:
            These follow the FQN of the object, prefixed by "p", "b", "c", "obj" respectively.
                e.g. self.bar.l0.weight produces "p_bar_l0_weight".
        - Effect tokens:
            These are named token, token_1, ...
    c                 S   s,   |  dr| tdd  } tdd| } | S )NZ
L__self___[^a-zA-Z0-9]_)
startswithr1   resubxr)   r)   r*   _strip_name  s    
z,placeholder_naming_pass.<locals>._strip_namec                 S   sb   t | tr"tddt| j} | S t | tr6t| jS t | trF| j	S t
dt|  d|  d S )Nr   r   zPytree key of type z not handled for )r$   r   r   r   r'   keyr   r&   r   r(   r2   r8   r   r)   r)   r*   _extract_pytree_key  s    



z4placeholder_naming_pass.<locals>._extract_pytree_keyc                 S   s    g | ]}|j tjkr|jjqS r)   )kindr   
USER_INPUTrF   r(   )ra   specr)   r)   r*   rd     s   z+placeholder_naming_pass.<locals>.<listcomp>r   c                 3   s   | ]} |  V  qd S rR   )lower)ra   r   r   r)   r*   r     s     z*placeholder_naming_pass.<locals>.<genexpr>T)Zis_placeholderr   r   r      Nz
arg(\d+)_1)!r   r   Zinput_specsr3   r   placeholder_prefixesr   r   joinr   TOKENr   r   r   r   rF   r(   r}   r~   r   r%   r   r   
CUSTOM_OBJZoutput_specsr   ZUSER_INPUT_MUTATIONr   r   r$   r6   r7   match)rw   r   r   r   r   Zfake_params_buffersrr   r   Zname_mapZcombined_argsrE   r   Zuser_input_namesZarg_pathrF   Zuser_input_namer   	base_namer;   r(   Zconstantnew_namer)   r   r*   placeholder_naming_pass  s    




 
r   )NN)N)F)Kr   rS   r   rB   r   r   r   typingr   r   r   r   r   r   r	   r6   Ztorch._subclasses.fake_tensorr
   Ztorch.exportr   Ztorch.export.exported_programr   r   Ztorch.export.graph_signaturer   r   Ztorch.utils._pytreer   r   r   r   r   r   r   r   r   r   r   r   r   Z	PARAMETERZBUFFERZCONSTANT_TENSORr   r   r   r   r   rI   r'   boolrh   rm   nnro   rq   r7   rs   ru   rv   ZGraphModuler   r   r   rA   r   r   r   r   Moduler   r   ZexportZExportGraphSignaturer   r)   r)   r)   r*   <module>   s   $8      
z  7	
	  

    =
