o
    iUO                     @   s   d Z ddlZddlZddlZddlmZ G dd deZ	e	eeZG dd deZ
dd	 Ze  G d
d deZdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd ZdS ) z}
`fallback_mode` for cupy. Whenever a method is not yet implemented in CuPy,
it will fallback to corresponding NumPy method.
    N)notificationc                   @   sR   e Zd ZdZdddZdd Zdd Zd	d
 Zedd Ze	dd Z
dd ZdS )_RecursiveAttrz
    RecursiveAttr class to catch all attributes corresponding to numpy,
    when user calls fallback_mode. numpy is an instance of this class.
    Nc                 C   s   || _ || _|| _dS )a  
        _RecursiveAttr initializer.

        Args:
            numpy_object (method): NumPy method.
            cupy_method (method): Corresponding CuPy method.
            array (ndarray): Acts as flag to know if _RecursiveAttr object
                is called from ``ndarray`` class. Also, acts as container for
                modifying args in case it is called from ``ndarray``.
                None otherwise.
        N)_numpy_object_cupy_object_fallback_array)selfnumpy_objectcupy_objectarray r   Y/home/ubuntu/veenaModal/venv/lib/python3.10/site-packages/cupyx/fallback_mode/fallback.py__init__   s   
z_RecursiveAttr.__init__c                 C   s"   | j durt|| j S t|| jS )z
        Enable support for isinstance(instance, _RecursiveAttr instance)
        by redirecting it to appropriate isinstance method.
        N)r   
isinstancer   )r   instancer   r   r   __instancecheck__&   s   
z _RecursiveAttr.__instancecheck__c                 C   sL   t | j|}t | j|d}|tju rtS |tju rtS ||u r!|S t||S )a5  
        Catches attributes corresponding to numpy.

        Runs recursively till attribute gets called.
        Or numpy ScalarType is retrieved.

        Args:
            attr (str): Attribute of _RecursiveAttr class object.

        Returns:
            (_RecursiveAttr object, NumPy scalar):
                Returns_RecursiveAttr object with new numpy_object,
                cupy_object. OR
                Returns objects in cupy which is an alias
                of numpy object. OR
                Returns wrapper objects, `ndarray`, `vectorize`.
        N)getattrr   r   npndarray	vectorizer   )r   attrr   r	   r   r   r   __getattr__1   s   


z_RecursiveAttr.__getattr__c                 C   s8   t | jtjrd| jjt| jdd S d| j| jS )Nz%<numpy = module {}, cupy = module {}>__name__z<numpy = {}, cupy = {}>)r   r   types
ModuleTypeformatr   r   r   r   r   r   r   __repr__R   s   z_RecursiveAttr.__repr__c                 C   s   | j jS N)r   __doc__r   r   r   r   r   \   s   z_RecursiveAttr.__doc__c                    s\   t  tr
 js
dS t  ttfrtdd  D S t  tr, fdd D }t|S dS )a-  
        Returns False if CuPy's functions never accept the arguments as
        parameters due to the following reasons.
        - The inputs include an object of a NumPy's specific class other than
          `np.ndarray`.
        - The inputs include a dtype which is not supported in CuPy.
        Fc                 s   s    | ]}t |V  qd S r   r   _is_cupy_compatible.0ir   r   r   	<genexpr>o   s    z5_RecursiveAttr._is_cupy_compatible.<locals>.<genexpr>c                    s   g | ]	}t  | qS r   r   r!   argr   r   
<listcomp>r   s    z6_RecursiveAttr._is_cupy_compatible.<locals>.<listcomp>T)r   r   _supports_cupytuplelistalldict)r&   boolsr   r%   r   r    `   s   


z"_RecursiveAttr._is_cupy_compatiblec                 O   s   t | jstdt| jj| jdur| jf| }| jdur@t	||fr@zt
| j||W S  ty?   t| j|| Y S w t| j t| j||S )aR  
        Gets invoked when last attribute of _RecursiveAttr class gets called.
        Calls _cupy_object if not None else call _numpy_object.

        Args:
            args (tuple): Arguments.
            kwargs (dict): Keyword arguments.

        Returns:
            (res, ndarray): Returns of methods call_cupy or call_numpy
        z'{}' object is not callableN)callabler   	TypeErrorr   typer   r   r   r   r    
_call_cupy	Exception_call_numpyr   _dispatch_notificationr   argskwargsr   r   r   __call__w   s    



z_RecursiveAttr.__call__r   )r   
__module____qualname__r   r   r   r   r   propertystaticmethodr    r8   r   r   r   r   r      s    
!


r   c                   @   st   e Zd ZdZejjZdd Zdd Zedd Z	edd	 Z
ed
d Zdd Zdd Zdd Zdd Zdd ZdS )r   z~
    Wrapper around cupy.ndarray
    Supports cupy.ndarray.__init__ as well as,
    gets initialized with a cupy ndarray.
    c                 O   s:   | dd}|durt| S tj|i |}| |ddS )z
        If `_initial_array` and `_supports_cupy` are arguments,
        initialize cls(ndarray).
        Else get cupy.ndarray from provided arguments,
        then initialize cls(ndarray).
        _initial_arrayNTr=   r(   )getobject__new__cpr   )clsr6   r7   r=   cupy_ndarray_initr   r   r   rA      s
   
zndarray.__new__c                 O   s   | dd}| dd}|du rdS d| _d| _d| _|| _t|tjtjfs)J |rBt	|tju r:|| _d| _
dS || _d| _
dS || _dS )a  
        Args:
            _initial_array (None, cp.ndarray/np.ndarray(including variants)):
                If _initial_array is None, object is not initialized.
                Otherwise, _initial_array (ndarray) would be set to
                _cupy_array and/or _numpy_array depending upon _supports_cupy.
            _supports_cupy (bool): If _supports_cupy is True, _initial_array
                is set as _cupy_array and _numpy_array.
                Otherwise, _initial_array is set as only _numpy_array.

        Attributes:
            _cupy_array (None or cp.ndarray): ndarray fully compatible with
                CuPy. This will be always set to a ndarray in GPU.
            _numpy_array (None or np.ndarray(including variants)): ndarray not
                supported by CuPy. Such as np.ndarray (where dtype is not in
                '?bhilqBHILQefdFD') and it's variants. This will be always set
                to a ndarray in CPU.
            _supports_cupy (bool): If _supports_cupy is True, data of array
                will contain in _cupy_array and _numpy_array.
                Else only _numpy_array will have the data.
        r(   Nr=   FT)pop_cupy_array_numpy_arraybaser(   r   rB   r   r   r0   _remember_numpy)r   r6   r7   r(   r=   r   r   r   r      s    


zndarray.__init__c                 C   s   | |ddS )NTr>   r   rC   r
   r   r   r   _store_array_from_cupy   s   zndarray._store_array_from_cupyc                 C   s2   t |tju r|jjdv r| |ddS | |ddS )Nz?bhilqBHILQefdFDTr>   F)r0   r   r   dtypekindrJ   r   r   r   _store_array_from_numpy   s   zndarray._store_array_from_numpyc                 C   s   | j r
| js
| jjS | jjS r   )r(   rI   rF   rL   rG   r   r   r   r   rL      s   zndarray.dtypec                 C   st   | j rttj|d}ttj|}n	d}t| jj|}t|s4| j r.| jr(| 	  t| j
|S t| j|S t||| S )aQ  
        Catches attributes corresponding to ndarray.

        Args:
            attr (str): Attribute of ndarray class.

        Returns:
            (_RecursiveAttr object, self._array.attr):
            Returns_RecursiveAttr object with numpy_object, cupy_object.
            Returns self._array.attr if attr is not callable.
        N)r(   r   rB   r   r   rG   	__class__r.   rI   _update_cupy_arrayrF   r   )r   r   r	   r   r   r   r   r      s   zndarray.__getattr__c                 C   s    | j }|dur
d|_d| _| jS )z
        Returns _cupy_array (cupy.ndarray) of ndarray object. And marks
        self(ndarray) and it's base (if exist) as numpy not up-to-date.
        NF)rH   rI   rF   r   rH   r   r   r   _get_cupy_array  s
   zndarray._get_cupy_arrayc                 C   s,   | j }|dur|jrd|_| jrd| _| jS )z
        Returns _numpy_array (ex: np.ndarray, numpy.ma.MaskedArray,
        numpy.chararray etc.) of ndarray object. And marks self(ndarray)
        and it's base (if exist) as numpy up-to-date.
        NT)rH   r(   rI   rG   rQ   r   r   r   _get_numpy_array   s   zndarray._get_numpy_arrayc                 C   s   | j }| jr	tjn| jj}| jra|du r1| js/| jdu r%t| j	| _dS | j	j
| jd dS dS |js[|  | jdu r]|jj|d| _| j	j| j_| jj| j	jkr_| j	j| j_dS dS dS dS |durs|jsjJ |jsu|  dS dS dS )zn
        Updates _numpy_array from _cupy_array.
        To be executed before calling numpy function.
        N)out)r0   )rH   r(   r   r   rG   rO   rI   rB   asnumpyrF   r?   _update_numpy_arrayviewshapestrides)r   rH   _typer   r   r   rV   -  s<   



zndarray._update_numpy_arrayc                 C   s^   | j }|du r$| jr"| jdu rt| j| _dS | j| jdd< dS dS |jr-|  dS dS )zm
        Updates _cupy_array from _numpy_array.
        To be executed before calling cupy function.
        N)rH   rI   rF   rB   r
   rG   rP   rQ   r   r   r   rP   O  s   
zndarray._update_cupy_arrayN)r   r9   r:   r   r   r   rA   r   classmethodrK   rN   r;   rL   r   rR   rS   rV   rP   r   r   r   r   r      s     0


"r   c                  C   s&   dd } dD ]
}t t|| | qdS )zK
    Set magic methods of cupy.ndarray as methods of fallback.ndarray.
    c                    s     fdd}t tj j|_|S )Nc                    sF   | j rtjn| jj}t| }| f| }| j rt|||S t|||S r   )r(   rB   r   rG   rO   r   r1   r3   )r   r6   r7   CLASS_methodnamer   r   methodh  s   

z:_create_magic_methods.<locals>.make_method.<locals>.method)r   r   r   r   )r_   r`   r   r^   r   make_methodg  s   z*_create_magic_methods.<locals>.make_method)?__eq____ne____lt____gt____le____ge____neg____pos____abs__
__invert____add____sub____mul____truediv____floordiv____mod__
__divmod____pow__
__lshift__
__rshift____and____or____xor____iadd____isub____imul____itruediv____ifloordiv____imod____ipow____ilshift____irshift____iand____ior____ixor__
__matmul____radd____rsub____rmul____rtruediv____rfloordiv____rmod____rdivmod____rpow____rlshift____rrshift____rand____ror____rxor____rmatmul____copy____deepcopy__
__reduce____iter____len____getitem____setitem____bool____int__	__float____complex__r   __str__N)setattrr   )ra   r`   r   r   r   _create_magic_methodsa  s   $r   c                   @   s4   e Zd ZejjZdd Zdd Zdd Zdd Z	d	S )
r   c                 O   s   d| j d< d| j d< t|d tr,d| j d< |d jr d| j d< |d jf|dd   }ttj tj|i || j d< | j d j	| j d< d S )	NF_is_numpy_pyfunc_cupy_supportr   T   vec_objr   )
__dict__r   r   r   r   r   r4   r   r   r   r5   r   r   r   r     s   




zvectorize.__init__c                 C   s   t | jd |S )Nr   )r   r   )r   r   r   r   r   r        zvectorize.__getattr__c                 C   s   t | j||S r   )r   r   )r   r_   valuer   r   r   __setattr__  s   zvectorize.__setattr__c                 O   s&   | j rt| jj| j t| j||S r   )r   r   r4   r   pyfuncr   r3   r5   r   r   r   r8     s
   
zvectorize.__call__N)
r   r9   r:   r   r   r   r   r   r   r8   r   r   r   r   r     s    r   c                    sx   t | r	|S t |trt fdd|D S t |tr+ fdd| D S t |tr: fdd|D S |S )a  
    Converts ndarray_instance type object to target object using to_xp.

    Args:
        ndarray_instance (numpy.ndarray, cupy.ndarray or fallback.ndarray):
            Objects of type `ndarray_instance` will be converted using `to_xp`.
        to_xp (FunctionType): Method to convert ndarray_instance type objects.
        arg (object): `ndarray_instance`, `tuple`, `list` and `dict` type
            objects will be returned by either converting the object or it's
            elements, if object is iterable. Objects of other types is
            returned as it is.

    Returns:
        Return data structure will be same as before after converting ndarrays.
    c                       g | ]}t  |qS r   _get_xp_argsr"   xndarray_instanceto_xpr   r   r'         z _get_xp_args.<locals>.<listcomp>c                    s   i | ]\}}|t  |qS r   r   )r"   x_namer   r   r   r   
<dictcomp>  s    z _get_xp_args.<locals>.<dictcomp>c                    r   r   r   r   r   r   r   r'     r   )r   r)   r,   itemsr*   )r   r   r&   r   r   r   r     s   



r   c                 C      t tjtj| S r   )r   r   r   rN   )	numpy_resr   r   r   _convert_numpy_to_fallback  r   r   c                 C      t ttj| |fS r   )r   r   rS   r6   r7   r   r   r   _convert_fallback_to_numpy     r   c                 C   r   r   )r   r   rR   r   r   r   r   _convert_fallback_to_cupy  r   r   c                 C   r   r   )r   rB   r   rK   )cupy_resr   r   r   _convert_cupy_to_fallback  r   r   c                 C   r   r   )r   r   rV   r   r   r   r   _update_numpy_args  r   r   c                 C   r   r   )r   r   rP   r   r   r   r   _update_cupy_args  r   r   c           	      C      t || t||\}}| |i |}t|||||}|dur!|S t|tjrD|jdu r2t|}|S t|j||||}t|}||_|S |S )a8  
    Calls cupy function with *args and **kwargs and
    does necessary data transfers.

    Args:
        func: A cupy function that needs to be called.
        args (tuple): Arguments.
        kwargs (dict): Keyword arguments.

    Returns:
        Result after calling func and performing data transfers.
    N)r   r   _get_same_referencer   rB   r   rH   r   )	funcr6   r7   	cupy_argscupy_kwargsr   ext_resfallback_resbase_argr   r   r   r1     &   


r1   c           	      C   r   )a:  
    Calls numpy function with *args and **kwargs and
    does necessary data transfers.

    Args:
        func: A numpy function that needs to be called.
        args (tuple): Arguments.
        kwargs (dict): Keyword arguments.

    Returns:
        Result after calling func and performing data transfers.
    N)r   r   r   r   r   r   rH   r   )	r   r6   r7   
numpy_argsnumpy_kwargsr   r   r   r   r   r   r   r3   $  r   r3   c                 C   sP   t t|D ]}| || u r||   S q|D ]}| || u r%||   S qdS )z_
    Returns object corresponding to res in (args, kwargs)
    from (ret_args, ret_kwargs)
    N)rangelen)resr6   r7   ret_args
ret_kwargsr#   keyr   r   r   r   J  s   r   )r   r   numpyr   cupyrB   cupyx.fallback_moder   r@   r   r   r   r   r   r   r   r   r   r   r   r1   r3   r   r   r   r   r   <module>   s.     
	 C9#!	&&