Ë
    °Œj(>  ã                   óô   — d Z ddlZddlZddlZddlmZ 	 ddlZd„ Z	 dd„Zd„ Z	 dd„Z G d	„ d
«      Z G d„ de«      Zdd„Z	 dd„Z G d„ de«      Zd„ Zd„ Zdd„Z	 	 	 	 	 dd„Zy# e	$ r  e
d«       Y Œ\w xY w)zO
This contrib module contains a few routines useful to do clustering variants.
é    N)Ú
ThreadPoolz2scipy not accessible, Python k-means will not workc                   ó   — y ©N© )ÚargÚkwargss     úb/var/www/html/Fitness-lenito-AI-main/venv/lib/python3.12/site-packages/faiss/contrib/clustering.pyÚ	print_nopr
      s   € Øó    c                 óº  — | j                   d   }|j                  dd«      }|rt        nt        } |d| j                   › d|› d|› �«        |d«       t	        j
                  ||f|dd	œ|¤Ž}	|	j                  | «       |	j                  g}
 |«         |d
«       t        j                  «       }|	j                  | «      \  }}t        j                  ||¬«      } |dt        j                  «       |z
  d›dt        |«      › dt        |«      › �«       |j                  «       }~	|s*t        j                  |dz   «      |z  |z  }|dd |dd z
  }nat        j                   |«      }||z  |d   z  }|ddxxx |dd z  ccc t#        |«      |k(  sJ ‚ |dt        |«      › dt        |«      › �«       d}g }t        j                  «       }t%        |«      D ]Î  }t'        ||   «      } |dt        j                  «       |z
  d›d|› d|› d|› d�	dd¬«       |||   z   }||| }t        j(                  ||   |k(  «      sJ ‚t	        j
                  ||fi |¤Ž}	| |   }|	j                  |«       |
j+                  |	j                  «       |j+                  |	j,                  «       ~	|}ŒÐ  |dt        j                  «       |z
  d›d�«       t        j.                  |«      |
fS )a=  
    perform 2-level clustering on a training set xt
    nc1 and nc2 are the number of clusters at each level, the final number of
    clusters is nc2. Additional arguments are passed to the Kmeans object.

    Rebalance allocates the number of sub-clusters depending on the number of
    first-level assignment.
    é   ÚverboseFz2-level clustering of z nb 1st level clusters = z total zperform coarse trainingiÐ  )ÚniterÚmax_points_per_centroidzassigning the training set©Ú	minlengthzdone in z.2fz s. Sizes of clusters Ú-Néÿÿÿÿznb 2nd-level centroids r   Ú[z s] training sub-cluster Ú/z nc2=ÚÚ T©ÚendÚflushz s)ÚshapeÚgetÚprintr
   ÚfaissÚKmeansÚtrainÚiteration_statsÚtimeÚassignÚnpÚbincountÚminÚmaxÚargsortÚarangeÚcumsumÚsumÚrangeÚintÚallÚappendÚ	centroidsÚvstack)ÚxtÚnc1Únc2Ú	rebalanceÚclustering_niterÚargsÚdr   ÚlogÚkmr"   Út0Ú_Úassign1ÚbcÚoÚccÚall_nc2Úbc_sumÚi0Úc2Úc1Úi1ÚsubsetÚxtsubs                            r	   Útwo_level_clusteringrJ      sí  € ð 	�‰�‰€Aà�h‰h�y %Ó(€Gá�%¤	€CáØ
  §¡ 
Ð*CÀCÀ5ð IØ�ð	ôñ Ð!Ô"ä	�‰Ø	ˆ3ð
Ø&Àñ
ØHLñ
€Bð ‡H�HˆR„Là×)Ñ)Ð*€OÙ„EáÐ$Ô%Ü	�‰‹€BØ—‘˜2“�J€A€wÜ	�‰�W¨Ô	,€BÙØ
”4—9‘9“; Ñ# CÐ(ð )Ü  ›W˜I Q¤s¨2£w ið	1ôð 	�‰Ó€AØ
áä�Y‰Y�s˜Q‘wÓ #Ñ%¨Ñ,ˆØ�Q�R�&˜2˜c˜r˜7Ñ"‰ä—‘˜2“ˆØ˜3‘, &¨¡*Ñ,ˆØ��‹�w˜s �|Ñ#‹Ü�7‹|˜sÒ"Ð"Ð"ÙÐ%¤c¨'£l ^°1´S¸³\°NÐCÔDð 
€BØ	€BÜ	�‰‹€BÜ�CŽjˆÜ�'˜"‘+ÓˆÙØ”—	‘	“˜bÑ  Ð%Ð%>Øˆd�!�C�5˜˜c˜U "ð&àØõ		
ð �"�R‘&‰[ˆØ�2�b�ˆÜ�v‰v�g˜f‘o¨Ñ+Ô,Ð,Ð,Ü�\‰\˜!˜SÑ) DÑ)ˆØ�6‘
ˆØ
�‰�ŒØ×Ñ˜r×1Ñ1Ô2Ø
�	‰	�"—,‘,ÔØØ‰ð# ñ$ ˆ(”4—9‘9“; Ñ# CÐ(¨Ð+Ô,Ü�9‰9�R‹=˜/Ð)Ð)r   c                 ó  — t        j                  | «      } t        | t         j                  «      r„t	        | j
                  j                  «       «      D ]?  }| j
                  j                  |«      }|j                  |«       |j                  |«      }ŒA t        | j                  |fi |¤Ž d| _        yt        | t         j                  «      sJ ‚| j                  t         j                  k(  sJ ‚t!        t#        j$                  | j&                  «      «      }t)        d|«       t+        ||| j&                  fi |¤Ž\  }}| j,                  j                  |«       | j,                  j/                  |«       | j                  |«       y)zJ
    Applies 2-level clustering to an index_ivf embedded in an index.
    TNz
REBALANCE=)r   Údowncast_indexÚ
isinstanceÚIndexPreTransformr-   ÚchainÚsizeÚatr!   ÚapplyÚtrain_ivf_index_with_2levelÚindexÚ
is_trainedÚIndexIVFÚmetric_typeÚ	METRIC_L2r.   r%   ÚsqrtÚnlistr   rJ   Ú	quantizerÚadd)rT   r3   r8   ÚiÚvtr4   r1   r=   s           r	   rS   rS   i   s!  € ô
 × Ñ  Ó'€EÜ�%œ×0Ñ0Ô1Ü�u—{‘{×'Ñ'Ó)Ö*ˆAØ—‘—‘ Ó"ˆBØ�H‰H�RŒLØ—‘˜"“‰Bð +ô 	$ E§K¡K°Ñ<°tÒ<ØˆÔØÜ�eœUŸ^™^Ô,Ð,Ð,Ø×Ñ¤§¡Ò/Ð/Ð/ä
Œb�g‰g�e—k‘kÓ"Ó
#€CÜ	ˆ,˜Ôä'¨¨C°·±ÑEÀÑE�L€IˆqØ	‡O�O×Ñ˜)Ô$Ø	‡O�O×Ñ˜	Ô"à	‡K�K�…Or   c           
      óÒ  — t        |«      }t        | «      }||z  }t        j                  | ||«      \  }}	t        j                  |t        j
                  ¬«      }
t        |«      D ]p  }|
dz  }|||	   z   }|j                  d¬«      }t        j                  |	|dd…df   d¬«      j                  «       }t        j                  ||¬«      }|
||z  |z  z  }
Œr t        |t        |«      | ||   z
  dz  j                  d«      j                  «       t        j!                  «       «      t        |j#                  «       «      |
j!                  «       |
j#                  «       ¬«      }||fS )u²  
    Assign vectors x to centroids with a balance constraint.

    Iteratively adjusts per-cluster penalties so that oversized clusters
    become less attractive. At each iteration the penalized distance for
    cluster c is ``d(x, c)^2 + penalty_c^2`` and the penalty is updated as
    ``penalty_c *= (binsize_c / n_opt) ** alpha`` where ``n_opt = n / nc``.

    A single kNN call (with *maxk* neighbors) is done upfront; subsequent
    iterations only re-weight among those candidates, making the routine
    fast even for large datasets.

    Reference: "Balancing clusters to reduce response time variability in
    large scale image search", Tavenard et al., CBMI 2011.
    https://inria.hal.science/inria-00576886/document
    See also notebook N10159950.

    Args:
        x:          (n, d) float32 array of vectors to assign.
        centroids:  (nc, d) float32 array of cluster centroids.
        alpha:      exponent that controls how aggressively penalties grow.
                    Higher values yield more balanced clusters at the cost
                    of higher MSE.  Typical range: 0.01 â€“ 0.1.
        num_iter:   number of penalty-update iterations.
        maxk:       number of nearest centroids to consider per vector.
                    Must be <= nc.

    Returns:
        assign:  (n,) int64 array of centroid indices.
        stats:   dict with keys

                 - *imf*: imbalance factor (1.0 = perfectly balanced)
                 - *mse*: mean squared error of the assignment
                 - *binsize_min*, *binsize_max*: smallest / largest cluster
                 - *penalty_min*, *penalty_max*: penalty value range
                 - *alpha*: the alpha value used
    ©Údtypeé   r   ©ÚaxisNr   )ÚalphaÚimfÚmseÚbinsize_minÚbinsize_maxÚpenalty_minÚpenalty_max)Úlenr   Úknnr%   ÚonesÚfloat32r-   ÚargminÚtake_along_axisÚravelr&   ÚdictÚimbalance_factorr,   Úmeanr.   r'   r(   )Úxr1   re   Únum_iterÚmaxkÚncÚnÚnoptÚfull_d2Úfull_assignÚ	penaltiesÚitÚ
penalties2Úfull_d2_penalizedÚa0r$   ÚbinsizesÚstatss                     r	   Ú"balanced_assignment_with_penaltiesr…   „   sL  € ôR 
ˆY‹€BÜˆA‹€AØˆr‰6€Dô !Ÿ9™9 Q¨	°4Ó8Ñ€Gˆ[ô —‘˜¤"§*¡*Ô-€Iä�HŽoˆà ‘\ˆ
Ø# j°Ñ&=Ñ=ÐØ×%Ñ%¨1Ð%Ó-ˆÜ×#Ñ# K°²A°t°G±À1ÔE×KÑKÓMˆÜ—;‘;˜v°Ô4ˆð 	�h ‘o¨%Ñ/Ñ/‰	ð ô ØÜ˜R Ó(Ø�)˜FÑ#Ñ#¨Ñ)×.Ñ.¨qÓ1×6Ñ6Ó8Ü˜Ÿ™›Ó'Ü˜Ÿ™›Ó'Ø—M‘M“OØ—M‘M“Oô€Eð �5ˆ=Ðr   c                   ó6   — e Zd ZdZd„ Zd„ Zd„ Zd„ Zd„ Zd	d„Z	y)
ÚDatasetAssignú†Wrapper for a matrix that offers a function to assign the vectors
    to centroids. All other implementations offer the same interfacec                 ó<   — t        j                  |d¬«      | _        y ©Nro   r`   )r%   Úascontiguousarrayrv   ©Úselfrv   s     r	   Ú__init__zDatasetAssign.__init__Ü   s   € Ü×%Ñ% a¨yÔ9ˆ�r   c                 ó4   — | j                   j                  d   S )Nr   ©rv   r   ©r�   s    r	   ÚcountzDatasetAssign.countß   ó   € Ø�v‰v�|‰|˜A‰Ðr   c                 ó4   — | j                   j                  d   S ©Nr   r�   r‘   s    r	   ÚdimzDatasetAssign.dimâ   r“   r   c                 ó    — | j                   |   S r   )rv   ©r�   Úindicess     r	   Ú
get_subsetzDatasetAssign.get_subsetå   s   € Ø�v‰v�g‰Ðr   c                 óD   — t        j                  | j                  |d«      S r•   )r   rm   rv   ©r�   r1   s     r	   Úperform_searchzDatasetAssign.perform_searchè   s   € Ü�y‰y˜Ÿ™ ¨AÓ.Ð.r   Nc                 ó¦  — | j                  |«      \  }}|j                  «       }|j                  «       }|j                  \  }}t        j                  ||fd¬«      }|€,t        j
                  j                  ||| j                  «       nCt        j
                  j                  |||d d …t        j                  f   | j                  z  «       |||fS rŠ   )	r�   rr   r   r%   Úzerosr\   rQ   rv   Únewaxis)r�   r1   ÚweightsÚDÚIry   r9   Úsum_per_centroids           r	   Ú	assign_tozDatasetAssign.assign_toë   s¥   € Ø×"Ñ" 9Ó-‰ˆˆ1à�G‰G‹IˆØ�G‰G‹IˆØ—‘‰ˆˆAÜŸ8™8 R¨ G°9Ô=ÐØˆ?Ü�F‰F�I‰IÐ&¨¨4¯6©6Õ2ä�F‰F�I‰IÐ&¨¨7²1´b·j±j°=Ñ+AÀDÇFÁFÑ+JÔKà�!Ð%Ð%Ð%r   r   )
Ú__name__Ú
__module__Ú__qualname__Ú__doc__rŽ   r’   r–   rš   r�   r¥   r   r   r	   r‡   r‡   Ø   s&   „ ñHò:òòòò/ô&r   r‡   c                   ó   — e Zd ZdZdd„Zd„ Zy)ÚDatasetAssignGPUzGPU version of the previousc                 ó  — t         j                  | |«       t        j                  |j                  d   «      }|dk\  r/t        j
                  t        j                  «       ||«      | _        y t        j                  |«      | _        y )Nr   r   )	r‡   rŽ   r   ÚIndexFlatL2r   Úindex_cpu_to_gpuÚStandardGpuResourcesrT   Úindex_cpu_to_all_gpus)r�   rv   Úgpu_idr   rT   s        r	   rŽ   zDatasetAssignGPU.__init__ý   sg   € Ü×Ñ˜t QÔ'Ü×!Ñ! !§'¡'¨!¡*Ó-ˆØ�QŠ;Ü×/Ñ/Ü×*Ñ*Ó,¨f°eóˆD�Jô
 ×4Ñ4°UÓ;ˆD�Jr   c                 ó¸   — | j                   j                  «        | j                   j                  |«       | j                   j                  | j                  d«      S r•   )rT   Úresetr\   Úsearchrv   rœ   s     r	   r�   zDatasetAssignGPU.perform_search  s=   € Ø�
‰
×ÑÔØ�
‰
�‰�yÔ!Ø�z‰z× Ñ  §¡¨Ó+Ð+r   N)F)r¦   r§   r¨   r©   rŽ   r�   r   r   r	   r«   r«   ú   s   „ Ù%ó	<ó,r   r«   c                 ó¤  — | j                   d   }|j                   d   }|€|dz  j                  d«      }|€3t        j                  | j	                  d«      j                  d«      «      }|d| z  |j
                  z  z
  }|j                  d¬«      }|j                  «       |t        j                  |«      |z  z      |j                  «       z   }||fS )zŒassignment function for xq is sparse, xb is dense
    uses a matrix multiplication. The squared norms can be provided if
    available.
    r   rb   r   rc   )	r   r,   r%   ÚarrayÚpowerÚTrp   rr   r*   )	ÚxqÚxbÚxq_normsÚxb_normsÚnqÚnbÚd2r£   r¢   s	            r	   Úsparse_assign_to_denserÀ     s·   € ð
 
�‰�!‰€BØ	�‰�!‰€BØÐØ˜‘E—;‘;˜q“>ˆØÐÜ—8‘8˜BŸH™H Q›KŸO™O¨AÓ.Ó/ˆØ	�A˜‘F˜RŸT™T‘MÑ	!€BØ
�	‰	�qˆ	Ó€AØ
�‰‹
�1”r—y‘y “} rÑ)Ñ)Ñ*¨X¯^©^Ó-=Ñ=€AØˆaˆ4€Kr   c           
      óø  ‡ ‡‡‡‡‡‡
‡‡— ‰ j                   d   }‰j                   d   Št        j                  |d¬«      Š
‰
j                  t        j                  «       t        j
                  |t        ¬«       Š‰€‰dz  j                  d«      Šˆ
ˆˆˆˆˆˆˆ ˆf	d„}|dk(  s
|dk(  s|‰k  r$t        t        |t        d|‰«      «      «       ‰
‰fS t        |«      }	|	j                  |t        d|‰«      «       ‰
‰fS )zÙ
    decomposes the sparse_assign_to_dense function into blocks to avoid a
    possible memory blow up. Can be run in multithreaded mode, because scipy's
    sparse-dense matrix multiplication is single-threaded.
    r   ro   r`   rb   r   c           
      ób  •	— ‰| | ‰z    }‰
| | ‰z    }‰	| | ‰z    }‰€4t        j                  |j                  d«      j                  d«      «      }n‰| | ‰z    }t	        d‰‰«      D ]H  }t        |‰||‰z    |‰||‰z    ¬«      \  }}|dk(  r||d d  ||d d  Œ1||k  }||   |z   ||<   ||   ||<   ŒJ y )Nrb   r   r   )r»   r¼   )r%   r¶   r·   r,   r-   rÀ   )r]   Úxq_blockÚIblockÚDblockÚxq_norms_blockÚjÚDiÚIiÚmaskr¢   r£   Úbbsr¾   Úqbsrº   r¼   r¹   r»   s            €€€€€€€€€r	   Úhandle_query_blockz9sparse_assign_to_dense_blocks.<locals>.handle_query_block0  sì   ø€ Ø�a˜!˜c™'�?ˆØ�1�q˜3‘w�ˆØ�1�q˜3‘w�ˆØÐÜŸX™X h§n¡n°QÓ&7×&;Ñ&;¸AÓ&>Ó?‰Nà% a¨!¨c©'Ð2ˆNÜ�q˜"˜cÖ"ˆAÜ+ØØ�1�q˜3‘w�Ø'Ø! ! a¨#¡gÐ.ô	‰FˆB�ð �AŠvØ�‘q�	Ø�‘q‘	à˜F‘{�Ø! $™x¨!™|��t‘Ø! $™x��t’ñ #r   )r   r%   ÚemptyÚfillÚinfrn   r.   r,   ÚlistÚmapr-   r   )r¹   rº   r»   r¼   rÌ   rË   Úntr½   rÍ   Úpoolr¢   r£   r¾   s   ``````    @@@r	   Úsparse_assign_to_dense_blocksrÕ     sØ   ÿø€ ð 
�‰�!‰€BØ	�‰�!‰€BÜ
�‰�˜9Ô%€AØ‡F�FŒ2�6‰6„NÜ	�‰�œ3Ô	Ð€AàÐØ˜‘E—;‘;˜q“>ˆ÷(ô (ð. 
ˆQ‚w�"˜’'˜R 3šYÜŒSÐ#¤U¨1¨b°#Ó%6Ó7Ô8ð
 ˆaˆ4€Kô ˜"‹~ˆØ�‰Ð#¤U¨1¨b°#Ó%6Ô7àˆaˆ4€Kr   c                   ó*   — e Zd ZdZd„ Zd„ Zd„ Zdd„Zy)ÚDatasetAssignSparserˆ   c                 óÔ   — |j                   t        j                  j                  k(  sJ ‚|| _        t        j                  |j                  d«      j                  d«      «      | _	        y )Nrb   r   )
Ú	__class__ÚscipyÚsparseÚ
csr_matrixrv   r%   r¶   r·   r,   Úsquared_normsrŒ   s     r	   rŽ   zDatasetAssignSparse.__init__T  sG   € Ø�{‰{œeŸl™l×5Ñ5Ò5Ð5Ð5ØˆŒÜŸX™X a§g¡g¨a£j§n¡n°QÓ&7Ó8ˆÕr   c                 ób   — t        j                  | j                  |   j                  «       «      S r   )r%   r¶   rv   Útodenser˜   s     r	   rš   zDatasetAssignSparse.get_subsetY  s"   € Ü�x‰x˜Ÿ™˜w™×/Ñ/Ó1Ó2Ð2r   c                 óF   — t        | j                  || j                  ¬«      S )N)r»   )rÕ   rv   rÝ   rœ   s     r	   r�   z"DatasetAssignSparse.perform_search\  s    € Ü,Ø�F‰F�I¨×(:Ñ(:ô
ð 	
r   Nc                 óÆ  — | j                  |«      \  }}|j                  «       }|j                  «       }| j                  j                  d   }|€t	        j
                  |d¬«      }t        |«      }t        j                  j                  ||t	        j                  |dz   «      f||f¬«      }t	        j                  || j                  z  j                  «       «      }|||fS )Nr   ro   r`   r   )r   )r�   rr   rv   r   r%   rn   rl   rÚ   rÛ   Ú
csc_matrixr*   r¶   rß   )	r�   r1   r¡   r¢   r£   rz   ry   Úmr¤   s	            r	   r¥   zDatasetAssignSparse.assign_toa  sÁ   € Ø×"Ñ" 9Ó-‰ˆˆ1à�G‰G‹IˆØ�G‰G‹IˆØ�F‰F�L‰L˜‰OˆØˆ?Ü—g‘g˜a yÔ1ˆGÜ�‹^ˆä�L‰L×#Ñ#Ø�aœŸ™ 1 q¡5Ó)Ð*°2°q°'ð $ó 
ˆô Ÿ8™8 Q¨¯©¡Z×$8Ñ$8Ó$:Ó;Ðà�!Ð%Ð%Ð%r   r   )r¦   r§   r¨   r©   rŽ   rš   r�   r¥   r   r   r	   r×   r×   P  s   „ ñHò9ò
3ò
ô
&r   r×   c                 ó–   — t        j                  |d¬«      }t        j                  t	        |«      | t        j
                  |«      «      S )NÚint64r`   )r%   r‹   r   rt   rl   Úswig_ptr)Úkr$   s     r	   rt   rt   s  s6   € Ü×!Ñ! &°Ô8€FÜ×!Ñ!¤# f£+¨q´%·.±.ÀÓ2HÓIÐIr   c                 ó¢   — | j                   t        j                  k(  rydd l}t	        | |j
                  «      ryt        dt        | «      › �«      ‚)NFr   TzUnknown tensor type )rÙ   r%   ÚndarrayÚtorchrM   ÚTensorÚNotImplementedErrorÚtype)rv   rê   s     r	   Úcheck_if_torchrî   x  s@   € Ø‡{�{”b—j‘jÒ ØÛä�!�U—\‘\Ô"ØÜ
Ð 4´T¸!³W°IÐ>Ó
?Ð?r   c                 ó  — |€t         j                  }|j                  \  }}d}t        |«      }t        j                  | dk(  «      d   }t        |«      dk(  ry|rddl}|j                  |d   «      }	nt        j                  |d   «      }	|	ddd…xx   dz  cc<   |	ddd…xx   dz  cc<   t        |«      dkD  rÌ| j                  d«      dz
  }
d|
|
dk  <   |
|
j                  «       z  }
|
dkD  j                  «       }t        ||j                  «      }|j                  |||
¬«      }t        |d| |«      D ]:  \  }}||   }||	z  ||<   ||	z  ||<   | |   dz  | |<   | |xx   | |   z  cc<   |dz  }Œ< ||d }t        |«      dkD  rŒÌ|S )z-reassign centroids when some of them collapseNr   rb   g      P?r   Úfloat)rP   Úp)r%   Úrandomr   rî   Úwhererl   rê   Ú	ones_likeÚastyper,   r'   rP   ÚchoiceÚzip)Úhassignr1   Úrsrç   r9   ÚnsplitÚis_torchÚempty_centsrê   ÚfacÚprobasÚnnzÚnreplaceÚcjsÚciÚcjÚcs                    r	   Úreassign_centroidsr  ‚  s«  € à	€zÜ�Y‰YˆØ�?‰?�D€A€qØ€FÜ˜iÓ(€Hä—(‘(˜7 a™<Ó(¨Ñ+€Kä
ˆ;Ó˜1ÒØáÛà�o‰o˜i¨™lÓ+‰ä�l‰l˜9 Q™<Ó(ˆØ‰ˆ!ˆƒH�
ÑƒHØˆˆˆ1ˆƒI�ÑƒIô ˆkÓ
˜QÒ
à—‘ Ó(¨1Ñ,ˆØˆˆv˜‰zÑØ�&—*‘*“,ÑˆØ˜‰z×ÑÓ ˆä�s˜K×,Ñ,Ó-ˆØ�i‰i˜ ¨FˆiÓ3ˆä˜+ i xÐ0°#Ö6‰FˆB�à˜"‘ˆAØ ™GˆI�b‰MØ ™GˆI�b‰Mà! "™+¨Ñ*ˆG�B‰KØ�B‹K˜7 2™;Ñ&‹KØ�a‰K‰Fð 7ð " ( )Ð,ˆô) ˆkÓ
˜QÓ
ð, €Mr   c           
      óä  — |j                  «       |j                  «       }}|rt        nt        }	 |	d||| ||fz  «       t        j
                  j                  |«      }
t        d«       t        j                  «       }|
j                  || d¬«      }|j                  |«      }t        |«      }g } |	d«       d}g }t        |«      D �]   }t        j                  «       } |	ddd	¬
«       |j                  |«      \  }}} |	ddd	¬
«       |t        j                  «       |z
  z  }|j                  «       }|r|j                  «       }|j                  |«       t	        j                   || ¬«      }|j#                  dd«      j%                  d«      }d||dk(  <   |r.ddl}|j)                  |«      j+                  |j,                  «      }||z  }t/        |||
«      }|t        j                  «       |z
  |t1        | |«      |dœ} |	d||d   |d   ||d   |fz  «       |j                  |«       |€�Œh |	d|«       |rddl}|j3                  ||«       �Œ‹t	        j2                  ||«       �Œ£ |r||fS |S )a0  Pure python kmeans implementation. Follows the Faiss C++ version
    quite closely, but takes a DatasetAssign instead of a training data
    matrix. Also redo is not implemented.

    For the torch implementation, the centroids are tensors (possibly on GPU),
    but the indices remain numpy on CPU.
    zAClustering %d points in %dD to %d clusters, %d iterations seed %dz
preproc...F)rP   Úreplacez  doner   Ú	assigningr   Tr   zcompute centroidsr   r   r   ro   N)Úobjr#   Útime_searchrt   rú   zM  Iteration %d (%.2f s, search %.2f s): objective=%g imbalance=%.3f nsplit=%dr#   r
  rt   zstoring centroids in)r’   r–   r   r
   r%   rò   ÚRandomStater#   rö   rš   rî   r-   r¥   r,   Úitemr0   r&   Úreshaperõ   rê   Ú
from_numpyÚtoÚdevicer  rt   Úsave)rç   Údatar   ÚseedÚ
checkpointr   Úreturn_statsrz   r9   r:   rù   r<   Úpermr1   rû   r"   Út_search_totr	  r]   Út0sr$   r¢   ÚsumsÚerrrø   rý   rê   rú   Úss                                r	   Úkmeansr  ³  sc  € ð  �:‰:‹<˜Ÿ™›€q€AÙ�%¤	€Cáð&ð ˆa��E˜4Ð
 ñ		!ôô 
�‰×	Ñ	˜tÓ	$€BÜ	ˆ,ÔÜ	�‰‹€Bà�9‰9�Q˜Q¨ˆ9Ó.€DØ—‘ Ó%€IÜ˜iÓ(€Hà€Oáˆ„MØ€LØ
€CÜ�5�\ˆÜ�i‰i‹kˆáˆK˜T¨Õ.ØŸ.™.¨Ó3‰ˆ��4áÐ T°Õ6àœŸ	™	› cÑ)Ñ)ˆà�e‰e‹gˆÙØ—(‘(“*ˆCØ�
‰
�3Œä—+‘+˜f°Ô2ˆà�o‰o˜b !Ó$×+Ñ+¨IÓ6ˆØˆˆC�1‰H‰ÙÛà×"Ñ" 3Ó'×*Ñ*¨4¯;©;Ó7ˆCà˜3‘Jˆ	ä# G¨Y¸Ó;ˆð Ü—Y‘Y“[ 2Ñ%Ø'Ü 0°°FÓ ;Øñ
ˆñ 	ð8ð Ø�&‘	Ø�-Ñ ØØÐ$Ñ%Øðñ	ô	
ð 	×Ñ˜qÔ!àÒ!ÙÐ&¨
Ô3ÙÛà—
‘
˜9 jÖ1ä—‘˜
 IÖ.ðw ñz Ø˜/Ð)Ð)àÐr   )Té   )g¸…ëQ¸ž?é   éd   )NN)NNé @  r   Nr   )r  iÒ  NTF)r©   Únumpyr%   r   r#   Úmultiprocessing.poolr   Úscipy.sparserÚ   ÚImportErrorr   r
   rJ   rS   r…   r‡   r«   rÀ   rÕ   r×   rt   rî   r  r  r   r   r	   Ú<module>r%     s¿   ðñó Û Û Ý +ð@Ûò
	ð
 46óL*ò^ð8 14óI÷h&ñ &ôD,�}ô ,ó(ð$ DHó.ôb &˜-ô  &òFJò
@ó.ðh Ø	ØØØôhøðC ò @Ù	Ð
>Ö?ð@ús   –A' Á'A7Á6A7