a
    h;"                     @   s   U d dl Z d dlZd dlmZ d dlmZ d dlZd dlmZm	Z	 G dd dZ
ee
eddd	Zd
d Zeaeed< e jdd ZG dd dZdddZdS )    N)Callable)
deprecated)KernelRegistrationHandlec                   @   sP   e Zd ZdZedddZedd Zejdd Zdd	e	ee
d
ddZdS )FakeImplHolderz0A holder where one can register an fake impl to.)qualnamec                 C   s   || _ g | _d S N)r   kernels)selfr    r   F/var/www/auris/lib/python3.9/site-packages/torch/_library/fake_impl.py__init__   s    zFakeImplHolder.__init__c                 C   s   t | jdkrd S | jd S )Nr   )lenr	   )r
   r   r   r   kernel   s    zFakeImplHolder.kernelc                 C   s   t dd S )NzUnable to directly set kernel.RuntimeError)r
   valuer   r   r   r      s    Fallow_override)funcsourcereturnc                   s   |snj dur*tdj dj j dtjjdrLtdj dtjjdrntdj dt|| j	   fd	d
}t
j}|jj|d|d t|}|S )z}Register an fake impl.

        Returns a RegistrationHandle that one can use to de-register this
        fake impl.
        Nz!register_fake(...): the operator z( already has an fake impl registered at .ZMetaz already has an DispatchKey::Meta implementation via a pre-existing torch.library or TORCH_LIBRARY registration. Please either remove that registration or don't call register_fake.ZCompositeImplicitAutograda%   already has an implementation for this device type via a pre-existing registration to DispatchKey::CompositeImplicitAutograd.CompositeImplicitAutograd operators do not need an fake impl; instead, the operator will decompose into its constituents and those can have fake impls defined on them.c                      s   j   d S r   )r	   remover   r   r
   r   r   deregister_fake_kernelN   s    z7FakeImplHolder.register.<locals>.deregister_fake_kernelr   )r   r   r   r   torchZ_CZ%_dispatch_has_kernel_for_dispatch_keyr   r	   appendconstruct_meta_kernelimplr   )r
   r   r   libr   r   meta_kernelhandler   r   r   register"   s0    	


zFakeImplHolder.registerN)__name__
__module____qualname____doc__strr   propertyr   setterr   r   r$   r   r   r   r   r      s   


r   )r   fake_impl_holderr   c                    s.    j d usJ t j j fdd}|S )Nc                     s`   j d usJ j j  fdd}t|  j | i |W  d    S 1 sR0    Y  d S )Nc                      s   t   d dd S )Nz (a  ): You're trying to run this operator with meta Tensors (as opposed to FakeTensors), but this operator may return an output Tensor with data-dependent shape. Meta Tensors don't support operators with outputs that have data-dependent shapes but FakeTensors do. If your operator does not return an output with data-dependent shape, make sure the FakeTensor and/or meta kernel does not call torch.library.get_ctx(). Otherwise, please use FakeTensors.r   r   )r   r   r   r   error_on_ctx`   s    z@construct_meta_kernel.<locals>.meta_kernel.<locals>.error_on_ctx)r   r   set_ctx_getter)argskwargsr-   r,   r   )r   r   r"   [   s
    
z*construct_meta_kernel.<locals>.meta_kernel)r   	functoolswrapsr   )r   r,   r"   r   r1   r   r   X   s    r   c                   C   s   d S r   r   r   r   r   r   get_noner   s    r4   global_ctx_getterc                 c   s"   t }z| a d V  W |a n|a 0 d S r   )r5   )Z
ctx_getterprevr   r   r   r.   y   s
    r.   c                   @   sT   e Zd ZdZdd Zededdddejd	d
dZ	dddejd	ddZ
dS )FakeImplCtxzO
    Context object for writing fake implementations for custom operators.
    c                 C   s   || _ |j| _|| _d S r   )
_fake_mode	shape_env
_shape_env_op)r
   r8   r;   r   r   r   r      s    zFakeImplCtx.__init__zM`create_unbacked_symint` is deprecated, please use `new_dynamic_size` instead)category   Nminmax)r   c                C   s   | j ||dS Nr>   )new_dynamic_sizer
   r?   r@   r   r   r   create_unbacked_symint   s    z"FakeImplCtx.create_unbacked_symintr   c                C   sv   | j du s| j js"tjj| jt|tjs:t|tjrPt	d| d| d|dk rht	d| dt
| j ||S )a	  Constructs a new symint (symbolic int) representing a data-dependent value.

        This is useful for writing the fake implementation (which is necessary
        for torch.compile) for a CustomOp where an output Tensor has a size
        that depends on the data of the input Tensors.

        Args:
            min (int): A statically known inclusive lower bound for this symint. Default: 0
            max (Optional[int]): A statically known inclusive upper bound for this
                symint. Default: None

        .. warning:

            It is important that the ``min`` and ``max`` (if not None) values are set
            correctly, otherwise, there will be undefined behavior under
            torch.compile. The default value of ``min`` is 2 due to torch.compile
            specializing on 0/1 sizes.

            You must also verify that your implementation on concrete Tensors
            (e.g. CPU/CUDA) only returns Tensors where the size that corresponds
            to the symint also has respects these constraint.
            The easiest way to do this is to add an assertion in the CPU/CUDA/etc
            implementation that the size follows these bounds.

        Example::

            >>> # An operator with data-dependent output shape
            >>> lib = torch.library.Library("mymodule", "FRAGMENT")
            >>> lib.define("mymodule::custom_nonzero(Tensor x) -> Tensor")
            >>>
            >>> @torch.library.register_fake("mymodule::custom_nonzero")
            >>> def _(x):
            >>>     # Number of nonzero-elements is data-dependent.
            >>>     # Since we cannot peek at the data in an fake impl,
            >>>     # we use the ctx object to construct a new symint that
            >>>     # represents the data-dependent size.
            >>>     ctx = torch.library.get_ctx()
            >>>     nnz = ctx.new_dynamic_size()
            >>>     shape = [nnz, x.dim()]
            >>>     result = x.new_empty(shape, dtype=torch.int64)
            >>>     return result
            >>>
            >>> @torch.library.impl(lib, "custom_nonzero", "CPU")
            >>> def _(x):
            >>>     x_np = x.numpy()
            >>>     res = np.stack(np.nonzero(x_np), axis=1)
            >>>     return torch.tensor(res, device=x.device)

        Nzctx.new_dynamic_size(min=z, max=zZ): expected min and max to be statically known ints but got SymInt. This is not supported.r   zc, ...): expected min to be greater than or equal to 0: this API can only create non-negative sizes.)r:   Zallow_dynamic_output_shape_opsr   Z_subclassesZfake_tensorZDynamicOutputShapeExceptionr;   
isinstanceSymInt
ValueErrorallocate_sizerC   r   r   r   rB      s    3
zFakeImplCtx.new_dynamic_size)r%   r&   r'   r(   r   r   FutureWarningr   rF   rD   rB   r   r   r   r   r7      s   r7   c                 C   s"   |   }tjjjj|||d |S rA   )rD   r   ZfxZexperimentalZsymbolic_shapesZ_constrain_range_for_size)r9   Zmin_valZmax_valresultr   r   r   rH      s
    
rH   )r   N)
contextlibr2   typingr   Ztyping_extensionsr   r   Ztorch._library.utilsr   r   r   r)   r   r4   r5   __annotations__contextmanagerr.   r7   rH   r   r   r   r   <module>   s   
M

Z