o
    oi                     @  sN   d dl mZ d dlZd dlmZ d dlmZmZ d dlm	Z	 G dd dZ
dS )    )annotationsN)Tensor)KORNIA_CHECKKORNIA_CHECK_SHAPEeuclidean_distancec                   @  sf   e Zd ZdZ			d#d$ddZed%ddZed%ddZd&ddZd'ddZ	d(ddZ
d)d!d"ZdS )*KMeansa  Implements the kmeans clustering algorithm with euclidean distance as similarity measure.

    Args:
        num_clusters: number of clusters the data has to be assigned to
        cluster_centers: tensor of starting cluster centres can be passed instead of num_clusters
        tolerance: float value. the algorithm terminates if the shift in centers is less than tolerance
        max_iterations: number of iterations to run the algorithm for
        seed: number to set torch manual seed for reproducibility

    Example:
        >>> kmeans = kornia.contrib.KMeans(3, None, 10e-4, 100, 0)
        >>> kmeans.fit(torch.rand((1000, 5)))
        >>> predictions = kmeans.predict(torch.rand((10, 5)))

    MbP?r   Nnum_clustersintcluster_centersTensor | None	tolerancefloatmax_iterationsseed
int | NonereturnNonec                 C  sb   t |dkd |d urt|ddg || _|| _|| _|| _d | _d | _|d ur/t	| d S d S )Nr   znum_clusters can't be 0CD)
r   r   r
   _cluster_centersr   r   _final_cluster_assignments_final_cluster_centerstorchmanual_seed)selfr
   r   r   r   r    r   I/home/ubuntu/.local/lib/python3.10/site-packages/kornia/contrib/kmeans.py__init__.   s   zKMeans.__init__r   c                 C  s,   t | jtr	| jS t | jtr| jS tdNz#Model has not been fit to a dataset)
isinstancer   r   r   	TypeErrorr   r   r   r   r   G   s
   zKMeans.cluster_centersc                 C  s   t | jtr	| jS tdr    )r!   r   r   r"   r#   r   r   r   cluster_assignmentsP   s   zKMeans.cluster_assignmentsXc                 C  s0   t |}tj||jd}|d| }|| }|S )a  Chooses num_cluster points from X as the initial cluster centers.

        Args:
            X: 2D input tensor to be clustered
            num_clusters: number of desired cluster centers

        Returns:
            2D Tensor with num_cluster rows

        deviceN)lenr   randpermr'   )r   r%   r
   num_samplespermidxinitial_stater   r   r   _initialise_cluster_centersW   s
   z"KMeans._initialise_cluster_centersdata1data2c                 C  s(   |ddddf }|d }t ||}|S )zCompute pairwise squared distance between 2 sets of vectors.

        Args:
            data1: 2D tensor of shape N, D
            data2: 2D tensor of shape C, D

        Returns:
            2D tensor of shape N, C

        N.)N.r   )r   r/   r0   ABdistancer   r   r   _pairwise_euclidean_distanceh   s   
z#KMeans._pairwise_euclidean_distancec           
      C  sb  t |ddg | jdu r| || j| _nt|jd | jjd kd|jd  d| jjd   | j}d}d}	 | ||}|d	}| }t	| jD ].}t
||k }t
|d|}|jd dkrr|t
jt|d
|jd }|jdd||< qLt
t
t
j|| d dd}	|d }| jdur|	d | jk rn| jdkr|| jkrnq8|| _|| _dS )zFit iterative KMeans clustering till a threshold for shift in cluster centers or a maximum no of iterations
        have reached.

        Args:
            X: 2D input tensor to be clustered

        Nr   N   zPDimensions at position 1 of X and cluster_centers do not match.                  != r   T)r6   r&   )dim   )r   r   r.   r
   r   shaper4   argmincloneranger   nonzerosqueezeindex_selectrandintr(   r'   meansumsqrtr   r   r   r   )
r   r%   current_centersprevious_centers	iterationr3   cluster_assignmentindexselectedcenter_shiftr   r   r   fitz   sB   	


"
z
KMeans.fitxc                 C  sR   t |jd | jjd kd|jd  d| jjd   | || j}|d}|S )zFind the cluster center closest to each point in x.

        Args:
            x: 2D tensor

        Returns:
            1D tensor containing cluster id assigned to each data point in x

        r6   zPDimensions at position 1 of x and cluster_centers do not match.                 r7   r8   )r   r;   r   r4   r<   )r   rN   r3   rI   r   r   r   predict   s   

zKMeans.predict)r	   r   N)r
   r   r   r   r   r   r   r   r   r   r   r   )r   r   )r%   r   r
   r   r   r   )r/   r   r0   r   r   r   )r%   r   r   r   )rN   r   r   r   )__name__
__module____qualname____doc__r   propertyr   r$   r.   r4   rM   rO   r   r   r   r   r      s    


:r   )
__future__r   r   kornia.corer   kornia.core.checkr   r   kornia.geometry.linalgr   r   r   r   r   r   <module>   s   