o
    oi:                     @  s6  d Z ddlmZ ddlmZmZmZmZmZ ddl	Z	ddl	m
Z
mZmZ ddlmZ ddlmZ g dZdLdMddZdNdOddZdPddZededZ		dNdQd"d#ZdNdRd%d&ZdLdSd)d*ZdLdTd,d-ZdNdUd0d1ZdLdTd2d3ZdNdVd4d5ZdNdVd6d7ZdNdVd8d9ZdWdXd=d>Z dLdYdBdCZ!dLdZdEdFZ"d[dJdKZ#dS )\z8The testing package contains testing-specific utilities.    )annotations)AnyOptionalSequenceTypeVarcastN)float16float32float64)	TypeGuard)Tensor)KORNIA_CHECKKORNIA_CHECK_DM_DESCKORNIA_CHECK_IS_COLORKORNIA_CHECK_IS_GRAYKORNIA_CHECK_IS_IMAGEKORNIA_CHECK_IS_LIST_OF_TENSORKORNIA_CHECK_IS_TENSORKORNIA_CHECK_LAFKORNIA_CHECK_SAME_DEVICEKORNIA_CHECK_SAME_DEVICESKORNIA_CHECK_SHAPEKORNIA_CHECK_TYPEKORNIA_UNWRAPTxr   shape	list[str]raisesboolreturnc                 C  s   d|d kr|dd }| j t| d d }nd|d kr1|dd }| j dt|d  }n|}| j }t|t|krO|rMt|  d| d| j  dS tt|D ]'}|| }| s`qUt|}|| |kr||ryt|  d| d| j   dS qUd	S )
a  Check whether a tensor has a specified shape.

    The shape can be specified with a implicit or explicit list of strings.
    The guard also check whether the variable is a type `Tensor`.

    Args:
        x: the tensor to evaluate.
        shape: a list with strings with the expected shape.
        raises: bool indicating whether an exception should be raised upon failure.

    Raises:
        Exception: if the input tensor is has not the expected shape and raises is True.

    Example:
        >>> x = torch.rand(2, 3, 4, 4)
        >>> KORNIA_CHECK_SHAPE(x, ["B", "C", "H", "W"])  # implicit
        True

        >>> x = torch.rand(2, 3, 4, 4)
        >>> KORNIA_CHECK_SHAPE(x, ["2", "3", "H", "W"])  # explicit
        True

    *r      Nz shape must be [z]. Got FT)r   len	TypeErrorrange	isnumericint)r   r   r   shape_to_checkx_shape_to_checkidim_dim r-   E/home/ubuntu/.local/lib/python3.10/site-packages/kornia/core/check.pyr   2   s.   r   	conditionmsgOptional[str]c                 C  s"   | s|rt |  d| dS dS )a  Check any arbitrary boolean condition.

    Args:
        condition: the condition to evaluate.
        msg: message to show in the exception.
        raises: bool indicating whether an exception should be raised upon failure.

    Raises:
        Exception: if the condition is met and raises is True.

    Example:
        >>> x = torch.rand(2, 3, 3)
        >>> KORNIA_CHECK(x.shape[-2:] == (3, 3), "Invalid homography")
        True

    z not true.
FT)	Exception)r/   r0   r   r-   r-   r.   r   i   s
   r   	maybe_objobjecttypr   c                 C  s
   t || S )zUnwraps an optional contained value that may or not be present.

    Args:
        maybe_obj: the object to unwrap.
        typ: expected type after unwrap.

    )r   )r3   r5   r-   r-   r.   r      s   
	r   T)boundT | tuple[T, ...]TypeGuard[T]c                 C  s.   t | |s|rtdt|  d| dS dS )a  Check the type of an aribratry variable.

    Args:
        x: any input variable.
        typ: the expected type of the variable.
        msg: message to show in the exception.
        raises: bool indicating whether an exception should be raised upon failure.

    Raises:
        TypeException: if the input variable does not match with the expected and raises is True.

    Example:
        >>> KORNIA_CHECK_TYPE("foo", str, "Invalid string")
        True

    zInvalid type: .
FT)
isinstancer$   type)r   r5   r0   r   r-   r-   r.   r      s
   
r   TypeGuard[Tensor]c                 C  s.   t | ts|rtdt|  d| dS dS )a  Check the input variable is a Tensor.

    Args:
        x: any input variable.
        msg: message to show in the exception.
        raises: bool indicating whether an exception should be raised upon failure.

    Raises:
        TypeException: if the input variable does not match with the expected and raises is True.

    Example:
        >>> x = torch.rand(2, 3, 3)
        >>> KORNIA_CHECK_IS_TENSOR(x, "Invalid tensor")
        True

    zNot a Tensor type. Got: r:   FT)r;   r   r$   r<   r   r0   r   r-   r-   r.   r      s
   
r   Optional[Sequence[object]]TypeGuard[list[Tensor]]c                 C  s@   t | totdd | D }|s|rtdt|  ddS dS )a3  Check the input variable is a List of Tensors.

    Args:
        x: Any sequence of objects
        raises: bool indicating whether an exception should be raised upon failure.

    Raises:
        TypeException: if the input variable does not match with the expected and raises is True.

    Return:
        True if the input is a list of Tensors, otherwise return False.

    Example:
        >>> x = torch.rand(2, 3, 3)
        >>> KORNIA_CHECK_IS_LIST_OF_TENSOR(x, raises=False)
        False
        >>> KORNIA_CHECK_IS_LIST_OF_TENSOR([x])
        True

    c                 s  s    | ]}t |tV  qd S )N)r;   r   ).0dr-   r-   r.   	<genexpr>   s    z1KORNIA_CHECK_IS_LIST_OF_TENSOR.<locals>.<genexpr>zProvided container of type z is not a list of tensorsFT)r;   listallr$   r<   )r   r   are_tensorsr-   r-   r.   r      s   r   yc                 C  0   | j |j kr|rtd| j  d|j  dS dS )a  Check whether two tensor in the same device.

    Args:
        x: first tensor to evaluate.
        y: sencod tensor to evaluate.
        msg: message to show in the exception.
        raises: bool indicating whether an exception should be raised upon failure.

    Raises:
        TypeException: if the two tensors are not in the same device and raises is True.

    Example:
        >>> x1 = torch.rand(2, 3, 3)
        >>> x2 = torch.rand(1, 3, 1)
        >>> KORNIA_CHECK_SAME_DEVICE(x1, x2)
        True

    "Not same device for tensors. Got:  and FT)devicer$   r   rG   r   r-   r-   r.   r      
   r   tensorslist[Tensor]c                   s^   t t tot dkd| t fdd D s-|r+tddd  D  d| d	S d
S )a  Check whether a list provided tensors live in the same device.

    Args:
        tensors: a list of tensors.
        msg: message to show in the exception.
        raises: bool indicating whether an exception should be raised upon failure.

    Raises:
        Exception: if all the tensors are not in the same device and raises is True.

    Example:
        >>> x1 = torch.rand(2, 3, 3)
        >>> x2 = torch.rand(1, 3, 1)
        >>> KORNIA_CHECK_SAME_DEVICES([x1, x2], "Tensors not in the same device")
        True

    r!   z)Expected a list with at least one elementc                 3  s     | ]} d  j |j kV  qdS )r   NrK   rA   r   rN   r-   r.   rC     s    z,KORNIA_CHECK_SAME_DEVICES.<locals>.<genexpr>rI   c                 S  s   g | ]}|j qS r-   rP   rQ   r-   r-   r.   
<listcomp>  s    z-KORNIA_CHECK_SAME_DEVICES.<locals>.<listcomp>r:   FT)r   r;   rD   r#   rE   r2   )rN   r0   r   r-   rR   r.   r      s   r   c                 C  rH   )a   Check whether two tensor have the same shape.

    Args:
        x: first tensor to evaluate.
        y: sencod tensor to evaluate.
        msg: message to show in the exception.
        raises: bool indicating whether an exception should be raised upon failure.

    Raises:
        TypeException: if the two tensors have not the same shape and raises is True.

    Example:
        >>> x1 = torch.rand(2, 3, 3)
        >>> x2 = torch.rand(2, 3, 3)
        >>> KORNIA_CHECK_SAME_SHAPE(x1, x2)
        True

    z!Not same shape for tensors. Got: rJ   FT)r   r$   rL   r-   r-   r.   KORNIA_CHECK_SAME_SHAPE  rM   rT   c                 C  s@   t | jdk s| jd dkr|rtdt|  d| dS dS )a  Check whether an image tensor is a color images.

    Args:
        x: image tensor to evaluate.
        msg: message to show in the exception.
        raises: bool indicating whether an exception should be raised upon failure.

    Raises:
        TypeException: if all the input tensor has not a shape :math:`(3,H,W)` and raises is True.

    Example:
        >>> img = torch.rand(2, 3, 4, 4)
        >>> KORNIA_CHECK_IS_COLOR(img, "Image is not color")
        True

       zNot a color tensor. Got: r:   FTr#   r   r$   r<   r>   r-   r-   r.   r   0  
   r   c                 C  sN   t | jdk st | jdkr%| jd dkr%|r#tdt|  d| dS dS )	a  Check whether an image tensor is grayscale.

    Args:
        x: image tensor to evaluate.
        msg: message to show in the exception.
        raises: bool indicating whether an exception should be raised upon failure.

    Raises:
        TypeException: if the tensor has not a shape :math:`(1,H,W)` or :math:`(H,W)` and raises is True.

    Example:
        >>> img = torch.rand(2, 1, 4, 4)
        >>> KORNIA_CHECK_IS_GRAY(img, "Image is not grayscale")
        True

       rU   rV   r!   zNot a gray tensor. Got: r:   FTrW   r>   r-   r-   r.   r   H  s
   *r   c                 C  s@   t | jdk s| jd dvr|rtdt|  d| dS dS )a  Check whether an image tensor is grayscale or color.

    Args:
        x: image tensor to evaluate.
        msg: message to show in the exception.
        raises: bool indicating whether an exception should be raised upon failure.

    Raises:
        TypeException: if the tensor has not a shape :math:`(1,H,W)` or :math:`(3,H,W)` and raises is True.

    Example:
        >>> img = torch.rand(2, 3, 4, 4)
        >>> KORNIA_CHECK_IS_COLOR_OR_GRAY(img, "Image is not color or grayscale")
        True

    rU   rV   )r!   rU   z!Not a color or gray tensor. Got: r:   FTrW   r>   r-   r-   r.   KORNIA_CHECK_IS_COLOR_OR_GRAY`  rX   rZ      bitsr'   c                 C  sz   |s
t | ||s
dS t| \}}| jtttfv r"|dk |dkB }nd|> d }|dk ||kB }| r;t||||S dS )a  Check whether an image tensor is ranged properly [0, 1] for float or [0, 2 ** bits] for int.

    Args:
        x: image tensor to evaluate.
        msg: message to show in the exception.
        raises: bool indicating whether an exception should be raised upon failure.
        bits: the image bits. The default checks if given integer input image is an
            8-bit image (0-255) or not.

    Raises:
        TypeException: if all the input tensor has not 1) a shape :math:`(3,H,W)`,
        2) [0, 1] for float or [0, 255] for int, 3) and raises is True.

    Example:
        >>> img = torch.rand(2, 3, 4, 4)
        >>> KORNIA_CHECK_IS_IMAGE(img, "It is not an image")
        True

    Fr   r!   T)	rZ   torchaminmaxdtyper   r	   r
   item_handle_invalid_range)r   r0   r   r\   aminamaxinvalidmax_int_valuer-   r-   r.   r   x  s   r   desc1desc2dmc                 C  sT   | d|  dkr| d| dks(|r&td|j d| j d|j dS dS )am  Check whether the provided descriptors match with a distance matrix.

    Args:
        desc1: first descriptor tensor to evaluate.
        desc2: second descriptor tensor to evaluate.
        dm: distance matrix tensor to evaluate.
        raises: bool indicating whether an exception should be raised upon failure.

    Raises:
        TypeException: if the descriptors shape do not match with the distance matrix and raises is True.

    Example:
        >>> desc1 = torch.rand(4)
        >>> desc2 = torch.rand(8)
        >>> dm = torch.rand(4, 8)
        >>> KORNIA_CHECK_DM_DESC(desc1, desc2, dm)
        True

    r   r!   zdistance matrix shape z0 is not onsistent with descriptors shape: desc1 z desc2 FT)sizer$   r   )rf   rg   rh   r   r-   r-   r.   r     s   (r   lafc                 C  s   t | g d|S )a  Check whether a Local Affine Frame (laf) has a valid shape.

    Args:
        laf: local affine frame tensor to evaluate.
        raises: bool indicating whether an exception should be raised upon failure.

    Raises:
        Exception: if the input laf does not have a shape :math:`(B,N,2,3)` and raises is True.

    Example:
        >>> lafs = torch.rand(2, 10, 2, 3)
        >>> KORNIA_CHECK_LAF(lafs)
        True

    )BN23)r   )rj   r   r-   r-   r.   r     s   r   min_valfloat | Tensormax_valc                 C  s8   d| d| d}| dur|d|  7 }|rt |dS )z.Helper function to handle invalid range cases.z2Invalid image value range. Expect [0, 1] but got [z, z].N
F)
ValueError)r0   r   ro   rq   err_msgr-   r-   r.   ra     s   ra   )T)r   r   r   r   r   r   r   r   )NT)r/   r   r0   r1   r   r   r   r   )r3   r4   r5   r   r   r   )
r   r4   r5   r8   r0   r1   r   r   r   r9   )r   r4   r0   r1   r   r   r   r=   )r   r?   r   r   r   r@   )r   r   rG   r   r   r   r   r   )rN   rO   r0   r1   r   r   r   r   )r   r   r0   r1   r   r   r   r   )NTr[   )
r   r   r0   r1   r   r   r\   r'   r   r   )
rf   r   rg   r   rh   r   r   r   r   r   )rj   r   r   r   r   r   )
r0   r1   r   r   ro   rp   rq   rp   r   r   )$__doc__
__future__r   typingr   r   r   r   r   r]   r   r	   r
   typing_extensionsr   kornia.corer   __all__r   r   r   r<   r6   r   r   r   r   r   rT   r   r   rZ   r   r   r   ra   r-   r-   r-   r.   <module>   s4   7
&