o
    .wi                     @   s  d dl Z d dlZd dlmZmZ d dlZd dlmZ d dlmZm	Z	m
Z
mZ d dlmZ d dlmZ d dlmZ ded	ed
eeef fddZded
dfddZdedeedf d
efddZdeded
efddZ	 d:dedee deeedf  ded
ef
ddZ			d;ded eeeee f  d!ed" d#ed$ d
ef
d%d&Z	'	d<ded	ed(ed)eeeeef eeeef f  d
eeeef eeeeef f f
d*d+Z		d=ded	ed,ed" d)eeeee f  d
ef
d-d.Z			/d>ded	ed,ed" d)eeeee f  d0ed
eeeeef f fd1d2Ze j 	d?d)eeeef eeeef f d3eej! d
eeef fd4d5Z"d?d)eeef d3eej! d
eeef fd6d7Z#e j d?d)eeeef d3eej! d
eeef fd8d9Z$dS )@    N)OptionalUnion)Tensor)conv2dconv3dpadunfold)Literal)_check_same_shape)_SCIPY_AVAILABLEpredstargetreturnc                 C   sT   | j d dkr| ddddf n| } |j d dkr$|ddddf n|}| |fS )zQIgnore the background class in the computation assuming it is the first, index 0.   Nshape)r   r    r   g/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/torchmetrics/functional/segmentation/utils.py_ignore_background   s   &&r   xc                 C   s   t |  | kstddS )zCheck if tensor is binarized.

    Example:
        >>> from torchmetrics.functional.segmentation.utils import check_if_binarized
        >>> import torch
        >>> check_if_binarized(torch.tensor([0, 1, 1, 0]))

    zInput x should be binarizedN)torchallbool
ValueError)r   r   r   r   check_if_binarized"   s   	r   kernel_size.c           	      C   s   | j dd \}}| jd }|dkrt| |S |d |d  |d  }|dgdd |D  }tj|| j| jd}|j|dg|R  j| }t	| |dd}|||| d	S )
a.  Unfold the input tensor to a matrix. Function supports 3d images e.g. (B, C, D, H, W).

    Inspired by:
    https://github.com/f-dangel/unfoldNd/blob/main/unfoldNd/unfold.py

    Args:
        x: Input tensor to be unfolded.
        kernel_size: The size of the sliding blocks in each dimension.

    N   r   r   c                 S   s   g | ]}d qS r   r   .0_r   r   r   
<listcomp>@   s    z_unfold.<locals>.<listcomp>devicedtype)weightbias)
r   ndimr   r   eyer#   r$   reshaperepeatr   )	r   r   
batch_sizechannelsnkernel_size_numelr+   r%   unfold_xr   r   r   _unfold/   s   

r1   rankconnectivityc                 C   sp   |dk rd}| dk rt jdgt jdS t jdd t| D dd}t t j|ddd }t j|dd}||kS )	a  Translated version of the function from scipy.ndimage.morphology.

    Args:
        rank: The rank of the structuring element.
        connectivity: The number of neighbors connected to a given pixel.

    Returns:
        The structuring element.

    Examples::
        >>> from torchmetrics.functional.segmentation.utils import generate_binary_structure
        >>> import torch
        >>> generate_binary_structure(2, 1)
        tensor([[False,  True, False],
                [ True,  True,  True],
                [False,  True, False]])
        >>> generate_binary_structure(2, 2)
        tensor([[True,  True,  True],
                [True,  True,  True],
                [True,  True,  True]])
        >>> generate_binary_structure(3, 2)  # doctest: +NORMALIZE_WHITESPACE
        tensor([[[False,  True, False],
                 [ True,  True,  True],
                 [False,  True, False]],
                [[ True,  True,  True],
                 [ True,  True,  True],
                 [ True,  True,  True]],
                [[False,  True, False],
                 [ True,  True,  True],
                 [False,  True, False]]])

    r   )r$   c                 S   s   g | ]}t d qS )   )r   aranger   r   r   r   r!   l   s    z-generate_binary_structure.<locals>.<listcomp>ij)indexingr   dim)r   tensoruint8meshgridrangeabsstacksum)r2   r3   gridsoutputr   r   r   generate_binary_structureG   s   !rC   image	structureoriginborder_valuec           
         s   t | tstdt|  | jdvrtd| j t|  du r1t| jd d 	| j
t  du r>jd  t|  fdd	tt D d
|d}t| jd}tdd}||  }|jdd\}}	t|| jd  S )a  Binary erosion of a tensor image.

    Implementation inspired by answer to this question: https://stackoverflow.com/questions/56235733/

    Args:
        image: The image to be eroded, must be a binary tensor with shape ``(batch_size, channels, height, width)``.
        structure: The structuring element used for the erosion. If no structuring element is provided, an element
            is generated with a square connectivity equal to one.
        origin: The origin of the structuring element.
        border_value: The value to be used for the border.

    Examples::
        >>> from torchmetrics.functional.segmentation.utils import binary_erosion
        >>> import torch
        >>> image = torch.tensor([[[[0, 0, 0, 0, 0],
        ...                         [0, 1, 1, 1, 0],
        ...                         [0, 1, 1, 1, 0],
        ...                         [0, 1, 1, 1, 0],
        ...                         [0, 0, 0, 0, 0]]]])
        >>> binary_erosion(image)
        tensor([[[[0, 0, 0, 0, 0],
                  [0, 0, 0, 0, 0],
                  [0, 0, 1, 0, 0],
                  [0, 0, 0, 0, 0],
                  [0, 0, 0, 0, 0]]]], dtype=torch.uint8)
        >>> binary_erosion(image, structure=torch.ones(4, 4))
        tensor([[[[0, 0, 0, 0, 0],
                  [0, 0, 0, 0, 0],
                  [0, 0, 0, 0, 0],
                  [0, 0, 0, 0, 0],
                  [0, 0, 0, 0, 0]]]], dtype=torch.uint8)

    z9Expected argument `image` to be of type Tensor but found )      z>Expected argument `image` to be of rank 4 or 5 but found rank Nr   r   r   c                    s4   g | ]} | j |  |  d  fD ]}|qqS r   r   )r   ir   rF   rE   r   r   r!      s   4 z"binary_erosion.<locals>.<listcomp>constant)modevalue)r   r   r'   r8   )
isinstancer   	TypeErrortyper(   r   r   rC   inttor#   r   r=   lenr1   floatr   r   flatten	unsqueezeminr*   byte)
rD   rE   rF   rG   	image_padimage_unfoldstrel_flattensumsresultr    r   rK   r   binary_erosionr   s*   
$

r_   	euclideanpytorchsamplingmetricr`   
chessboardtaxicabenginera   scipyc                 C   s<  t | tstdt|  d| jdkrtd| j d|dur0t |ts0tdt| d|dvr<td| d|d	vrHtd
| d|du rQddg}nt|dkratdt| d|dkr|  } t	| dk\}}t	| dk\}}|
dd|
dd  }|
dd|
dd  }	| j\}
}|dkr|d | d |d |	 d   }|dkrt|d | |d |	  }|dkr|d | |d |	   }tj|dd\}}t| 
d}||||
 | < |
| jS tstdddlm} |dkr||   |S |j|   ||dS )a  Calculate distance transform of a binary tensor.

    This function calculates the distance transform of a binary tensor, replacing each foreground pixel with the
    distance to the closest background pixel. The distance is calculated using the euclidean, chessboard or taxicab
    distance.

    The memory consumption of this function is in the worst cast N/2**2 where N is the number of pixel. Since we need
    to compare all foreground pixels to all background pixels, the memory consumption is quadratic in the number of
    pixels. The memory consumption can be reduced by using the ``scipy`` engine, which is more memory efficient but
    should also be slower for larger images.

    Args:
        x: The binary tensor to calculate the distance transform of.
        sampling: The sampling refers to the pixel spacing in the image, i.e. the distance between two adjacent pixels.
            If not provided, the pixel spacing is assumed to be 1.
        metric: The distance to use for the distance transform. Can be one of ``"euclidean"``, ``"chessboard"``
            or ``"taxicab"``.
        engine: The engine to use for the distance transform. Can be one of ``["pytorch", "scipy"]``. In general,
            the ``pytorch`` engine is faster, but the ``scipy`` engine is more memory efficient.

    Returns:
        The distance transform of the input tensor.

    Examples::
        >>> from torchmetrics.functional.segmentation.utils import distance_transform
        >>> import torch
        >>> x = torch.tensor([[0, 0, 0, 0, 0],
        ...                   [0, 1, 1, 1, 0],
        ...                   [0, 1, 1, 1, 0],
        ...                   [0, 1, 1, 1, 0],
        ...                   [0, 0, 0, 0, 0]])
        >>> distance_transform(x)
        tensor([[0., 0., 0., 0., 0.],
                [0., 1., 1., 1., 0.],
                [0., 1., 2., 1., 0.],
                [0., 1., 1., 1., 0.],
                [0., 0., 0., 0., 0.]])

    z<Expected argument `x` to be of type `torch.Tensor` but got ``.r   z4Expected argument `x` to be of rank 2 but got rank `NzLExpected argument `sampling` to either be `None` or of type `list` but got `rd   zZExpected argument `metric` to be one of `['euclidean', 'chessboard', 'taxicab']` but got `rh   zHExpected argument `engine` to be one of `['pytorch', 'scipy']` but got `r   z>Expected argument `sampling` to have length 2 but got length `ra   r   r'   r`   re   rf   r8   zhThe `scipy` engine requires `scipy` to be installed. Either install `scipy` or use the `pytorch` engine.)ndimage)rc   )rO   r   r   rQ   r(   listrT   rU   r   whereviewr>   r   sqrtmaxrX   
zeros_liker   ri   rk   distance_transform_edtcpunumpydistance_transform_cdt)r   rb   rc   rg   i0j0i1j1dis_rowdis_colhr    dismindiszrk   r   r   r   distance_transform   sV   
-



$ 
r   Tcropspacingc                 C   s  t | | | jdvrtd| j dt|  t| |rK| |B }| s6t| t|}}||||fS t| | jddg t||jddg } }|du rot| 	d	d
 | A }t|	d	d
 |A }||fS t|| jd\}	}
t|}|dkrtnt}tj| 	d|	dgdd	 }|||
|\}}t|	d }|dk||k@ }|dk||k@ }t|	d|d
 |}t|	d|d
 |}|d |d |d |d fS )a  Get the edges of binary segmentation masks.

    Args:
        preds: The predicted binary segmentation mask
        target: The ground truth binary segmentation mask
        crop: Whether to crop the edges to the region of interest. If ``True``, the edges are cropped to the bounding
        spacing: The pixel spacing of the input images. If provided, the edges are calculated using the euclidean

    Returns:
        If spacing is not provided, a 2-tuple containing the edges of the predicted and target mask respectively is
        returned. If spacing is provided, a 4-tuple containing the edges and areas of the predicted and target mask
        respectively is returned.

    )r   r4   z=Expected argument `preds` to be of rank 2 or 3 but got rank `rj   r   Nr   r#   r   r8   r'   )r
   r(   r   r   anyr   rq   r   r_   rW   squeezeget_neighbour_tablesr#   rT   r   r   r?   rU   rS   index_selectrn   rR   view_as)r   r   r   r   or_valptbe_pred	be_targettablekernelspatial_dimsconv_operatorvolume
code_predscode_targetall_onesedges_predsedges_targetareas_predsareas_targetr   r   r   
mask_edges  s4   

*"r   distance_metricc                 C   s   | j tjkr|j tjkstd| j  d|j  dt|s*tjt| }||  S t| s;tjt|  }|| S t| ||d}||  S )a  Calculate the surface distance between two binary edge masks.

    May return infinity if the predicted mask is empty and the target mask is not, or vice versa.

    Args:
        preds: The predicted binary edge mask.
        target: The target binary edge mask.
        distance_metric: The distance metric to use. One of `["euclidean", "chessboard", "taxicab"]`.
        spacing: The spacing between pixels along each spatial dimension.

    Returns:
        A tensor with length equal to the number of edges in predictions e.g. `preds.sum()`. Each element is the
        distance from the corresponding edge in `preds` to the closest edge in `target`.

    Example::
        >>> import torch
        >>> from torchmetrics.functional.segmentation.utils import surface_distance
        >>> preds = torch.tensor([[1, 1, 1, 1, 1],
        ...                       [1, 0, 0, 0, 1],
        ...                       [1, 0, 0, 0, 1],
        ...                       [1, 0, 0, 0, 1],
        ...                       [1, 1, 1, 1, 1]], dtype=torch.bool)
        >>> target = torch.tensor([[1, 1, 1, 1, 0],
        ...                        [1, 0, 0, 1, 0],
        ...                        [1, 0, 0, 1, 0],
        ...                        [1, 0, 0, 1, 0],
        ...                        [1, 1, 1, 1, 0]], dtype=torch.bool)
        >>> surface_distance(preds, target, distance_metric="euclidean", spacing=[1, 1])
        tensor([0., 0., 0., 0., 1., 0., 1., 0., 1., 0., 1., 0., 0., 0., 0., 1.])

    z9Expected both inputs to be of type `torch.bool`, but got z and .)rb   rc   )r$   r   r   r   r   inf	ones_liker   )r   r   r   r   r}   r   r   r   surface_distanceV  s   %

r   F	symmetricc                 C   sX   t | |}|d  |d  }}|r$t||||dt||||dfS t||||dS )a5  Extracts the edges from the input masks and calculates the surface distance between them.

    Args:
        preds: The predicted binary edge mask.
        target: The target binary edge mask.
        distance_metric: The distance metric to use. One of `["euclidean", "chessboard", "taxicab"]`.
        spacing: The spacing between pixels along each spatial dimension.
        symmetric: Whether to calculate the symmetric distance between the edges.

    Returns:
        A tensor with length equal to the number of edges in predictions e.g. `preds.sum()`. Each element is the
        distance from the corresponding edge in `preds` to the closest edge in `target`. If `symmetric` is `True`, the
        function returns a tuple containing the distances from the predicted edges to the target edges and vice versa.

    r   r   )r   r   )r   r   r   )r   r   r   r   r   rB   r   r   r   r   r   edge_surface_distance  s   
r   r#   c                 C   sH   t | trt| dkrt| |S t | tr t| dkr t| |S td)a  Create a table that maps neighbour codes to the contour length or surface area of the corresponding contour.

    Args:
        spacing: The spacing between pixels along each spatial dimension.
        device: The device on which the table should be created.

    Returns:
        A tuple containing as its first element the table that maps neighbour codes to the contour length or surface
        area of the corresponding contour and as its second element the kernel used to compute the neighbour codes.

    r   r4   z-The spacing must be a tuple of length 2 or 3.)rO   tuplerT   table_contour_lengthtable_surface_arear   )r   r#   r   r   r   r     s
   

r   c                 C   s   t | tst| dkrtd| \}}dt|d |d   }tjdtj|d}dD ]}|||< q+dD ]}|||< q4dD ]}|||< q=d	D ]}d| ||< qFtj	d
dgddgggg|d}||fS )a  Create a table that maps neighbour codes to the contour length of the corresponding contour.

    Adopted from:
    https://github.com/deepmind/surface-distance/blob/master/surface_distance/lookup_tables.py

    Args:
        spacing: The spacing between pixels along each spatial dimension. Should be a tuple of length 2.
        device: The device on which the table should be created.

    Returns:
        A tuple containing as its first element the table that maps neighbour codes to the contour length of the
        corresponding contour and as its second element the kernel used to compute the neighbour codes.

    Example::
        >>> from torchmetrics.functional.segmentation.utils import table_contour_length
        >>> table, kernel = table_contour_length((2,2))
        >>> table
        tensor([0.0000, 1.4142, 1.4142, 2.0000, 1.4142, 2.0000, 2.8284, 1.4142, 1.4142,
                2.8284, 2.0000, 1.4142, 2.0000, 1.4142, 1.4142, 0.0000])
        >>> kernel
        tensor([[[[8, 4],
                  [2, 1]]]])

    r   z(The spacing must be a tuple of length 2.      ?   r$   r#   )r   r   rH                  )r4      )rI   
   )   	   r   rH   r   r   )
rO   r   rT   r   mathro   r   zerosfloat32	as_tensor)r   r#   firstseconddiagr   rJ   r   r   r   r   r     s   


r   c                 C   s<  t | tst| dkrtdg d}tjg ||||gg d|||gg d|||gg dg d||gg d|||gg d	g d
||gg dg d||gg dg dg d|gg d|||gg dg d||gg dg d||gg dg dg d|gg dg d||gg dg dg d|gg dg dg d|gg dg d||gg d|||gg dg d||gg dg d||gg dg dg d|gg dg d||gg dg dg d|gg dg dg d|gg dg dg dg dgg dg d||gg dg dg d|gg dg dg d|gg dg dg dg dgg dg dg d|gg dg dg dg d gg dg dg dg dgg dg dg d|gg d|||gg dg d||gg dg d||gg dg d!g d"|gg dg d||gg dg d	g d
|gg dg dg d|gg d#g d$g d!g d	gg dg d||gg dg dg d|gg d%g dg d|gg d"g d"g d!g dgg dg dg d|gg dg dg dg dgg dg d&g dg d'gg dg dg d|gg dg d ||gg d(g dg d|gg d(g dg d)|gg d(g d||gg dg d g d|gg d*g dg dg d gg dg dg dg dgg dg dg d|gg dg dg d |gg d(g d"g dg dgg d+g dg dg dgg d(g d"g d|gg dg d g dg dgg dg dg d|gg dg dg d|gg dg d||gg d|||gg dg d||gg dg d||gg dg dg d|gg dg d||gg d,g dg d|gg dg dg d|gg d-g dg dg d'gg dg d||gg dg dg d|gg dg dg d|gg dg dg dg dgg d.g d)g d|gg d)g d)g dg dgg d/g d&g dg dgg dg d)g d|gg dg d0||gg d%g dg d|gg dg dg d0|gg d	g d1g dg dgg dg d"g d|gg d%g d,||gg dg dg dg d,gg dg dg d,|gg dg d0g d|gg d%g dg dg dgg dg dg dg d0gg dg d
g d
|gg d
g d#g d g dgg d%g dg d|gg dg d
g d
|gg d
g d
||gg dg d||gg dg dg d|gg dg dg d|gg dg d!g d"g dgg dg dg d|gg d,g dg dg dgg dg dg dg dgg dg dg d|gg dg dg d|gg dg dg dg dgg d%g dg dg dgg dg dg d|gg d.g d)g dg dgg dg dg d|gg dg dg d|gg dg d||gg dg d2g d|gg dg dg dg dgg d-g dg dg dgg dg dg d|gg d#g dg dg dgg dg dg d,|gg dg dg d|gg dg d||gg dg dg dg dgg dg dg d|gg d	g d
g d|gg dg d||gg dg dg d|gg dg d||gg dg d||gg d|||gg d|||gg dg d||gg dg d||gg dg dg d|gg dg d||gg d	g d
g d|gg dg dg d|gg dg dg dg dgg dg d||gg dg dg d|gg dg dg d,|gg d#g dg dg dgg dg dg d|gg d-g dg dg dgg dg dg dg dgg dg d2g d|gg dg d||gg dg dg d|gg dg dg d|gg d.g d)g dg dgg dg dg d|gg d%g dg dg dgg dg dg dg dgg dg dg d|gg dg dg d|gg dg dg dg dgg d,g dg dg dgg dg dg d|gg dg d!g d"g dgg dg dg d|gg dg dg d|gg dg d||gg d
g d
||gg dg d
g d
|gg d%g dg d|gg d
g d#g d g dgg dg d
g d
|gg d	g d
g d
g d
gg d%g dg dg dgg dg d0g d|gg dg dg d,|gg dg dg dg d,gg d%g d,||gg dg d"g d|gg d	g d1g dg dgg dg dg d0|gg d%g dg d|gg dg d0||gg dg d)g d|gg d/g d&g dg dgg d)g d)g dg dgg d.g d)g d|gg dg dg dg dgg dg dg d|gg dg dg d|gg dg d||gg d-g dg dg d'gg dg dg d|gg d,g dg d|gg dg d||gg dg dg d|gg dg d||gg dg d||gg d|||gg dg d||gg dg dg d|gg dg dg d|gg dg dg dg dgg d(g d"g d|gg d+g dg dg dgg d(g d"g dg dgg dg dg d |gg dg dg d|gg dg dg dg dgg d*g dg dg d gg dg d g d|gg d(g d||gg d(g dg d)|gg d(g dg d|gg dg d ||gg dg dg d|gg dg d&g dg d'gg dg dg dg dgg dg dg d|gg d"g d"g d!g dgg d%g dg d|gg dg dg d|gg dg d||gg d#g d$g d!g d	gg dg dg d|gg dg d	g d
|gg dg d||gg dg d!g d"|gg dg d||gg dg d||gg d|||gg dg dg d|gg dg dg dg dgg dg dg dg d gg dg dg d|gg dg dg dg dgg dg dg d|gg dg dg d|gg dg d||gg dg dg dg dgg dg dg d|gg dg dg d|gg dg d||gg dg dg d|gg dg d||gg dg d||gg d|||gg dg d||gg dg dg d|gg dg dg d|gg dg d||gg dg dg d|gg dg d||gg dg d||gg d|||gg dg dg d|gg dg d||gg d	g d
||gg d|||gg dg d||gg d|||gg d|||g||||gtj|d3}tj| d4 | d5  | d6 | d5  | d6 | d4  ggg||jd7}tj	j
|| d8d9}|d8}tjd:d;gd<d=ggd>d?gd5d4ggggg|d@}||fS )Aa  Create a table that maps neighbour codes to the surface area of the corresponding surface.

    Adopted from:
    https://github.com/deepmind/surface-distance/blob/master/surface_distance/lookup_tables.py

    Args:
        spacing: The spacing between pixels along each spatial dimension. Should be a tuple of length 3.
        device: The device on which the table should be created.

    Returns:
        A tuple containing as its first element the table that maps neighbour codes to the surface area of the
        corresponding surface and as its second element the kernel used to compute the neighbour codes.

    Example::
        >>> from torchmetrics.functional.segmentation.utils import table_surface_area
        >>> table, kernel = table_surface_area((2,2,2))
        >>> table
        tensor([0.0000, 0.8660, 0.8660, 2.8284, 0.8660, 2.8284, 1.7321, 4.5981, 0.8660,
                1.7321, 2.8284, 4.5981, 2.8284, 4.5981, 4.5981, 4.0000, 0.8660, 2.8284,
                1.7321, 4.5981, 1.7321, 4.5981, 2.5981, 5.1962, 1.7321, 3.6945, 3.6945,
                6.2925, 3.6945, 6.2925, 5.4641, 4.5981, 0.8660, 1.7321, 2.8284, 4.5981,
                1.7321, 3.6945, 3.6945, 6.2925, 1.7321, 2.5981, 4.5981, 5.1962, 3.6945,
                5.4641, 6.2925, 4.5981, 2.8284, 4.5981, 4.5981, 4.0000, 3.6945, 6.2925,
                5.4641, 4.5981, 3.6945, 5.4641, 6.2925, 4.5981, 5.6569, 3.6945, 3.6945,
                2.8284, 0.8660, 1.7321, 1.7321, 3.6945, 2.8284, 4.5981, 3.6945, 6.2925,
                1.7321, 2.5981, 3.6945, 5.4641, 4.5981, 5.1962, 6.2925, 4.5981, 2.8284,
                4.5981, 3.6945, 6.2925, 4.5981, 4.0000, 5.4641, 4.5981, 3.6945, 5.4641,
                5.6569, 3.6945, 6.2925, 4.5981, 3.6945, 2.8284, 1.7321, 2.5981, 3.6945,
                5.4641, 3.6945, 5.4641, 5.6569, 3.6945, 2.5981, 3.4641, 5.4641, 2.5981,
                5.4641, 2.5981, 3.6945, 1.7321, 4.5981, 5.1962, 6.2925, 4.5981, 6.2925,
                4.5981, 3.6945, 2.8284, 5.4641, 2.5981, 3.6945, 1.7321, 3.6945, 1.7321,
                1.7321, 0.8660, 0.8660, 1.7321, 1.7321, 3.6945, 1.7321, 3.6945, 2.5981,
                5.4641, 2.8284, 3.6945, 4.5981, 6.2925, 4.5981, 6.2925, 5.1962, 4.5981,
                1.7321, 3.6945, 2.5981, 5.4641, 2.5981, 5.4641, 3.4641, 2.5981, 3.6945,
                5.6569, 5.4641, 3.6945, 5.4641, 3.6945, 2.5981, 1.7321, 2.8284, 3.6945,
                4.5981, 6.2925, 3.6945, 5.6569, 5.4641, 3.6945, 4.5981, 5.4641, 4.0000,
                4.5981, 6.2925, 3.6945, 4.5981, 2.8284, 4.5981, 6.2925, 5.1962, 4.5981,
                5.4641, 3.6945, 2.5981, 1.7321, 6.2925, 3.6945, 4.5981, 2.8284, 3.6945,
                1.7321, 1.7321, 0.8660, 2.8284, 3.6945, 3.6945, 5.6569, 4.5981, 6.2925,
                5.4641, 3.6945, 4.5981, 5.4641, 6.2925, 3.6945, 4.0000, 4.5981, 4.5981,
                2.8284, 4.5981, 6.2925, 5.4641, 3.6945, 5.1962, 4.5981, 2.5981, 1.7321,
                6.2925, 3.6945, 3.6945, 1.7321, 4.5981, 2.8284, 1.7321, 0.8660, 4.5981,
                5.4641, 6.2925, 3.6945, 6.2925, 3.6945, 3.6945, 1.7321, 5.1962, 2.5981,
                4.5981, 1.7321, 4.5981, 1.7321, 2.8284, 0.8660, 4.0000, 4.5981, 4.5981,
                2.8284, 4.5981, 2.8284, 1.7321, 0.8660, 4.5981, 1.7321, 2.8284, 0.8660,
                2.8284, 0.8660, 0.8660, 0.0000])
        >>> kernel
        tensor([[[[[128,  64],
                   [ 32,  16]],
                  [[  8,   4],
                   [  2,   1]]]]])

    r4   z(The spacing must be a tuple of length 3.)        r   r   )      ?r   r   )      r   r   )      пr   r   )      ?r          )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )      r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )      ?r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )      ؿr   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   )r   r   r   r   r   r   r   r"   r'   r8      @       r   r   rH   r   )rO   r   rT   r   r   r:   r   r   r$   linalgnormr@   )r   r#   r   r   spacer   r   r   r   r   r     s:  7
	
 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~                 	  
                                               !  "  #  $  %  &  '  (  )  *  +  ,  -  .  /  0  1  2  3  4  5  6  7  8  9  :  ;  <  =  >  ?  @  A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  [  \  ]  ^  _  `  a  b  c  d  e  f  g  h  i  j  k  l  m  n  o  p  q  r  s  t  u  v  w  x  y  z  {  |  }  ~         
        	0
.r   )NNr   )Nr`   ra   )TN)r`   N)r`   NF)N)%	functoolsr   typingr   r   r   r   torch.nn.functionalr   r   r   r   typing_extensionsr	   torchmetrics.utilities.checksr
   torchmetrics.utilities.importsr   r   r   r   rR   r1   rC   r_   rl   rU   r   r   r   r   r   	lru_cacher#   r   r   r   r   r   r   r   <module>   s   ,
H
g 
=
5
 
.+6