U
    Kc%                     @   s   U d dl 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
mZmZmZ d dlZd dlZd dlZd dlmZ ddd	gZi Ze	ejjef ed< ejd
ddZdddedddZeeejjejjf  e	ejjef ddd	Zd dlZd dl ZdS )    N)defaultdict)wraps)chain)CallableDict
NamedTupleSequenceTupleUnion)tree_mapdecomposition_tableregister_decompositionget_decompositionsZatenZIMPLMetaF)disable_metac                   s   t t d fdd}|S )aS  
    A decorator to register a function as a decomposition to the Python
    decomposition table.  Use it like this::

        @register_decomposition(torch.ops.aten.clamp_min)
        def clamp_min(x):
            return torch.clamp(self, min=min)

    If you are writing a new decomposition, consider contributing it
    directly to PyTorch in torch._decomp.decompositions.

    This API is experimental; we are almost certainly going to extend
    the API when we make decompositions eligible for use in transforms (e.g.,
    autograd) and not just backend tracing, where we then need to know if a
    decomposition can be used to simulate a transform.

    By default, if the decomposition is for an operator that doesn't have
    a Meta implementation, we will register it to the dispatcher.  Use
    `disable_meta` to disable this behavior.
    )freturnc                    s   t  } jd} |rt|dd tkr|jjt  fdd}dd t	|j
D }tdd |j D |}t j||jd	|_d
d  j D |_|D ]}|j|j|j< q|d krtfdd}t| S )Nout
__origin__c                     sV   t fddD }|d d k t fdd|D s<t| d rLd n|iS )Nc                 3   s   | ]}  |d V  qd S N)pop.0o)kwargs :/tmp/pip-unpacked-wheel-gikjz4vx/torch/_decomp/__init__.py	<genexpr>8   s     zWregister_decomposition.<locals>.decomposition_decorator.<locals>._fn.<locals>.<genexpr>r   c                 3   s   | ]}|d k kV  qd S r   r   r   )is_noner   r   r   ;   s     r   )tupleallAssertionError)argsr   Z
out_kwargs)r   	out_names)r   r   r   _fn6   s    zDregister_decomposition.<locals>.decomposition_decorator.<locals>._fnc                 S   s&   g | ]\}}t j|t jjd |dqS )N)kinddefault
annotation)inspect	ParameterKEYWORD_ONLY)r   r   tr   r   r   
<listcomp>>   s   zKregister_decomposition.<locals>.decomposition_decorator.<locals>.<listcomp>c                 s   s   | ]\}}|d kr|V  qdS )r   Nr   r   kvr   r   r   r   I   s      zJregister_decomposition.<locals>.decomposition_decorator.<locals>.<genexpr>)
parametersreturn_annotationc                 S   s   i | ]\}}|d kr||qS )r   r   r-   r   r   r   
<dictcomp>O   s      zKregister_decomposition.<locals>.decomposition_decorator.<locals>.<dictcomp>c                    s  g }t | tjjr||  n0t | tjjs0t|  D ]}|t| | q8|D ]}|krlt	d| |< |
tjjj |jj}|jjr|d|jj 7 } sRtj|rRtj|dsRtdd |jjD rt	dt| dt| qRd S )Nzduplicate registrations for .r   c                 s   s"   | ]}|j d k	o|j j V  qd S r   )Z
alias_infoZis_write)r   ar   r   r   r   |   s   zcregister_decomposition.<locals>.decomposition_decorator.<locals>.add_op_to_table.<locals>.<genexpr>zB
Attempting to register a python meta kernel for a view operator: a0  .
We shouldn't do this, because the output will report as not having aliased storages.
All view ops have meta kernels in C++ today, so we should use those instead.

If you're registering an operator through the `@register_decomposition` decorator,
Please set `disable_meta=True`.
                        )
isinstancetorch_ops
OpOverloadappendOpOverloadPacketr!   	overloadsgetattrRuntimeErrorZpy_implZ_CZDispatchKeyr   Z_schemanameZoverload_nameZ_dispatch_has_kernelZ._dispatch_has_computed_kernel_for_dispatch_keyany	argumentsstrmeta_libimpl)aten_opr;   olop_overloadr>   )r   fnregistryr   r   add_op_to_table[   s@    
 
zPregister_decomposition.<locals>.decomposition_decorator.<locals>.add_op_to_table)r(   	signature__annotations__getr<   r   r1   _fieldsr   zip__args__r   r0   items	Signature__signature__r'   r>   r   r   )r   sigZout_annotationr$   Z
out_paramsparamsr   rI   rD   r   rH   )r   rG   r#   r   decomposition_decorator,   s:    


  2
z7register_decomposition.<locals>.decomposition_decorator)r   )rD   rH   r   rV   r   rU   r   r      s    d)aten_opsr   c                 C   s   t t}tD ]}||j | qi }| D ]X}t|tjjr`||kr`|| D ]}t| ||< qLq*t|tjj	r*|tkr*t| ||< q*|S )a,  
    Retrieve a dictionary of decompositions corresponding to the list of
    operator overloads and overload packets passed as input.  Overload
    packets will include all decomposed overloads in the packet.  If there is
    no decomposition for a requested operator, it is silently ignored.

    This API is experimental; we are almost certainly going to give an alternate,
    more recommended formulation, where a user provides the set of operators
    they know how to implement, and we provide decompositions for everything
    not in this set.
    )
r   listr   Zoverloadpacketr9   r5   r6   r7   r:   r8   )rW   Zpackets_to_overloadsZopoZdecompositionsoprF   r   r   r   r      s    )N)!r(   collectionsr   	functoolsr   	itertoolsr   typingr   r   r   r   r	   r
   r6   Z
torch._opsZtorch.libraryZtorch.utils._pytreer   __all__r   r7   r8   rK   ZlibraryLibraryrB   boolr   r:   r   Ztorch._decomp.decompositionsZtorch._refsr   r   r   r   <module>   s$     
~