U
    <cZ0                     @   s|   d dl Z d dlZd dlmZ ddgZdd Zdd	d
Zdd Zdd Zdd Z	dd Z
dd Zdd ZG dd dejZdS )    N)get_default_nowrap_functionsMaskedTensoris_masked_tensorc                 C   s
   t | tS )a   Returns True if the input is a MaskedTensor, else False

    Args:
        a: any input

    Examples:

        >>> # xdoctest: +SKIP
        >>> from torch.masked import MaskedTensor
        >>> data = torch.arange(6).reshape(2,3)
        >>> mask = torch.tensor([[True, False, False], [True, True, False]])
        >>> mt = MaskedTensor(data, mask)
        >>> is_masked_tensor(mt)
        True
    )
isinstancer   a r   B/tmp/pip-unpacked-wheel-gikjz4vx/torch/masked/maskedtensor/core.pyr      s    Th㈵>:0yE>c                 C   sD  t | st |rtd| j|jkr<td| j d|j | j|jkrT|| j}| j|j  krntjkrn n(t|  | |ot| 	 |	 |S | j|j  krtj
krn n<t|  | |ot|  | |ot|  | |S |r |  | kot| |  S |  | koBtj| |||dS )Nz*Neither `a` nor `b` can be a MaskedTensor.z+`a` and `b` must have the same layout. Got  and )rtolatol)r   
ValueErrorlayoutdtypetypetorch
sparse_coo_tensors_matchvaluesindices
sparse_csrcrow_indicescol_indicesdimeqallitemZallclose)r   bexactr   r   r   r   r	   r   "   s*      &r   c                 C   s2   t | r.t |r.|  }| }t||ddS dS )NTr    )r   get_maskr   )r   r   Zmask_aZmask_br   r   r	   _masks_match9   s
    r#   c           	      C   s^   dd }|d kri }g }| D ]}| ||| qi }| D ]\}}|||||< q>||fS )Nc                 S   sf   t | r|| S t| r| S t| tr<t| i |\}}|S t| tr^t| i |\}}t|S | S d S N)r   r   	is_tensorr   list_map_mt_args_kwargstuple)r   map_fnZa_impl_r   r   r	   _helperB   s    


z$_map_mt_args_kwargs.<locals>._helper)appenditems)	argskwargsr)   r+   Z	impl_argsr   Zimpl_kwargskvr   r   r	   r'   A   s    r'   c                 C   s\   t | tr"tdd t| |D S t | trDtdd t| |D S t| rXt| |S tS )Nc                 s   s   | ]\}}t ||V  qd S r$   _wrap_result.0rmr   r   r	   	<genexpr>]   s     z_wrap_result.<locals>.<genexpr>c                 s   s   | ]\}}t ||V  qd S r$   r2   r4   r   r   r	   r8   _   s     )r   r&   zipr(   r   r%   r   NotImplemented)Zresult_dataZresult_maskr   r   r	   r3   [   s    



r3   c                    s   | j tjtjhkr"|  } | }|  dkr fdd| D }ttdd t|| dd	fddt|| D  d	 S  fd
dt| |D }dd |D }dd	| d S )N   c                    s4   g | ],}t | tr$ | n
t| qS r   )r   r   floatformatstr)r5   d	formatterr   r	   
<listcomp>k   s   z&_masked_tensor_str.<locals>.<listcomp>c                 S   s   | d rdS t | d S )Nr;      r   )len)xr   r   r	   <lambda>p       z$_masked_tensor_str.<locals>.<lambda>[, c                    s"   g | ]\}}|rd   n|qS )--)rjust)r5   er7   )max_lenr   r	   rB   u   s   ]c                    s   g | ]\}}t || qS r   )_masked_tensor_str)r5   r?   r7   r@   r   r	   rB   |   s     c                 S   s&   g | ]}d  dd |d D qS )
c                 S   s   g | ]}d | qS )  r   r5   sir   r   r	   rB   }   s     z1_masked_tensor_str.<locals>.<listcomp>.<listcomp>)joinsplit)r5   sr   r   r	   rB   }   s     z[
z,
z
])
r   r   r   r   Zto_denser   maxmapr9   rT   )datamaskrA   Zformatted_elementsZsub_stringsr   )rA   rM   r	   rO   f   s.    



rO   c                 C   s   t | r| jS | S r$   )r   _masked_datar   r   r   r	   	_get_data   s    r\   c                 C   s   t | r|  S d S r$   )r   r"   r   r   r   r	   _maybe_get_mask   s    r]   c                   @   s   e Zd Zed&ddZdd Zdd Zd'dd	Zed
d Zdd Z	dd Z
ed(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"d# Zd$d% ZdS ))r   Fc                 C   s   t |st|stdt |s,t|s4tdi }|j|d< |j|d< |j|d< ||d< d|d< d	|d
< tdt	 |j
rtdt	 tjj| | f|S )Nzdata must be a Tensorzmask must be a Tensordevicer   r   requires_gradstridesZdispatch_sizes_strides_policyTZdispatch_layoutzThe PyTorch API of MaskedTensors is in prototype stage and will change in the near future. Please open a Github issue for features requests and see our documentation on the torch.masked module for further information about the project.zIt is not recommended to create a MaskedTensor with a tensor that requires_grad. To avoid this, you can use data.clone().detach())r   r   r%   	TypeErrorr^   r   r   warningswarnUserWarningr_   TensorZ_make_wrapper_subclasssize)clsrY   rZ   r_   r/   r   r   r	   __new__   s&    


zMaskedTensor.__new__c                 C   s   ddl m}m} |j|jkr$td|jtjkrd| }| }| | kr|||t	d}n.|jtj
kr| | kr|||t	d}| | _| | _d S )N   )_sparse_coo_where_sparse_csr_wherez(data and mask must have the same layout.r   )Z_opsrj   rk   r   ra   r   r   ZcoalesceZ_nnzZtensorr   cloner[   _masked_mask)selfrY   rZ   rj   rk   r   r   r	   _preprocess_data   s    
zMaskedTensor._preprocess_datac                 C   s  | j }|  }t|t|kr:tdt| dt| |jtjtjtjhkrbtd|j d|jtjkrt	|
 |
 ddstdn@|jtjkrt	| | ddrt	| | ddstd|jtjkrtd	|jtjksb|jtjksb|jtjksb|jtjksb|jtjksb|jtjksb|jtjksb|jtjksbt|j d
| | kr|td| | krtdd S )Nz+data and mask must have the same type. Got r   zdata layout of z is not supported.Tr!   zKdata and mask are both sparse COO tensors but do not have the same indices.zVdata and mask are both sparse CSR tensors but do not share either crow or col indices.zmask must have dtype bool.z" is not supported in MaskedTensor.z data.dim() must equal mask.dim()z"data.size() must equal mask.size())r[   r"   r   ra   r   r   Zstridedr   r   r   r   r   r   r   r   boolZfloat16Zfloat32Zfloat64Zint8Zint16Zint32Zint64r   rf   rn   rY   rZ   r   r   r	   _validate_members   sR    
  








zMaskedTensor._validate_membersc                 C   s   |  || |   d S r$   )ro   rr   )rn   rY   rZ   r_   r   r   r	   __init__   s    zMaskedTensor.__init__c                 C   s$   G dd dt jj}|| |}|S )z- Differentiable constructor for MaskedTensor c                   @   s$   e Zd Zedd Zedd ZdS )z.MaskedTensor._from_values.<locals>.Constructorc                 S   s
   t ||S r$   r   )ctxrY   rZ   r   r   r	   forward   s    z6MaskedTensor._from_values.<locals>.Constructor.forwardc                 S   s   |d fS r$   r   ru   Zgrad_outputr   r   r	   backward   s    z7MaskedTensor._from_values.<locals>.Constructor.backwardN__name__
__module____qualname__staticmethodrv   rx   r   r   r   r	   Constructor   s   
r~   r   ZautogradZFunctionapply)rY   rZ   r~   resultr   r   r	   _from_values   s    	zMaskedTensor._from_valuesc                 C   s   || _ || _|   d S r$   )r[   rm   rr   rq   r   r   r	   _set_data_mask   s    zMaskedTensor._set_data_maskc                 C   s   d}|   dkrh|   }t|tr0||nt|}|   sHd}d| d t|    d S t|  |  |}d	dd	 |
dD }d
| d S )Nz{0:8.4f}r   rJ   zMaskedTensor(rI   )rP   c                 s   s   | ]}d | V  qdS )rQ   Nr   rR   r   r   r	   r8     s     z(MaskedTensor.__repr__.<locals>.<genexpr>zMaskedTensor(
z
))r   get_datar   r   r<   r=   r>   r"   rO   rT   rU   )rn   rA   Zscalar_dataZdata_formattedrV   r   r   r	   __repr__   s,    zMaskedTensor.__repr__r   Nc              
      s   |pi }ddl m} ||kr*|| ||S t fdd|D sDtS tj D |||}|t krt|W  5 Q R  S tj	| W  5 Q R  S W 5 Q R X d S )Nr;   )_MASKEDTENSOR_FUNCTION_TABLEc                 3   s   | ]}t  |V  qd S r$   )
issubclass)r5   trg   r   r	   r8     s     z2MaskedTensor.__torch_function__.<locals>.<genexpr>)
	_ops_refsr   r   r:   r   Z_CZDisableTorchFunctionr   Z_tensor_convert)rg   functypesr.   r/   r   retr   r   r	   __torch_function__  s    

zMaskedTensor.__torch_function__c                 C   s   t |||S r$   rt   )rg   fnrY   rZ   r   r   r	   unary  s    zMaskedTensor.unaryc                 C   sB   |j }ddlm} ||kr(|| ||S |j d}t| tS )Nr;   )_MASKEDTENSOR_DISPATCH_TABLEaz   is not implemented in __torch_dispatch__ for MaskedTensor.
If you would like this operator to be supported, please file an issue for a feature request at https://github.com/pytorch/maskedtensor/issues with a minimal reproducible code snippet.
In the case that the semantics for the operator are not trivial, it would be appreciated to also include a proposal for the semantics.)Zoverloadpacketr   r   rz   rb   rc   r:   )rg   r   r   r.   r/   r   msgr   r   r	   __torch_dispatch__  s    

zMaskedTensor.__torch_dispatch__c                 C   s8   t |r"t|  t|k |  S t|  |k |  S r$   )r   r   r   r\   r"   )rn   otherr   r   r	   __lt__.  s    zMaskedTensor.__lt__c                 C   s   |   |   |S r$   )r   Zmasked_fillr"   )rn   valuer   r   r	   	to_tensor3  s    zMaskedTensor.to_tensorc                    s"   G  fdddt jj}| S )Nc                       s(   e Zd Zedd Ze fddZdS )z&MaskedTensor.get_data.<locals>.GetDatac                 S   s   |j S r$   )r[   )ru   rn   r   r   r	   rv   8  s    z.MaskedTensor.get_data.<locals>.GetData.forwardc                    s   t |r|S t|  S r$   )r   r   r"   rw   rn   r   r	   rx   <  s    z/MaskedTensor.get_data.<locals>.GetData.backwardNry   r   r   r   r	   GetData7  s   
r   r   )rn   r   r   r   r	   r   6  s    zMaskedTensor.get_datac                 C   s   | j S r$   )rm   r   r   r   r	   r"   D  s    zMaskedTensor.get_maskc                 C   s   | j tjkS r$   )r   r   r   r   r   r   r	   is_sparse_cooG  s    zMaskedTensor.is_sparse_cooc                 C   s   | j tjkS r$   )r   r   r   r   r   r   r	   is_sparse_csrJ  s    zMaskedTensor.is_sparse_csrc                 C   s   |   p|  S r$   )r   r   r   r   r   r	   	is_sparseN  s    zMaskedTensor.is_sparse)F)F)r   N)rz   r{   r|   r}   rh   ro   rr   rs   r   r   r   classmethodr   r   r   r   r   r   r"   r   r   r   r   r   r   r	   r      s,   !



)Tr
   r   )rb   r   Ztorch.overridesr   __all__r   r   r#   r'   r3   rO   r\   r]   re   r   r   r   r   r	   <module>   s   
