§
    ÐÁ³g›1  ã                   óþ   — d Z ddlZddlZddlZddlmZ 	 ddlZn# e	$ r  e
d¦  «         Y nw xY wd„ Zdd„Z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dS )zO
This contrib module contains a few routines useful to do clustering variants.
é    N)Ú
ThreadPoolz2scipy not accessible, Python k-means will not workc                  ó   — d S ©N© )ÚargÚkwargss     úV/var/www/html/mpstechhub/venv/lib/python3.11/site-packages/faiss/contrib/clustering.pyÚ	print_nopr
      s   € Ø€Dó    Té   c                 ój  — | j         d         }|                     dd¦  «        }|rt          nt          } |d| j         › d|› d|› �¦  «          |d¦  «         t	          j        ||f|dd	œ|¤Ž}	|	                     | ¦  «         |	j        g}
 |¦   «          |	j        } |d
¦  «         t          j	        ¦   «         }|	 
                    | ¦  «        \  }}t          j        ||¬¦  «        } |dt          j	        ¦   «         |z
  d›dt          |¦  «        › dt          |¦  «        › �¦  «         |                     ¦   «         }~	|s3t          j        |dz   ¦  «        |z  |z  }|dd…         |dd…         z
  }n|t          j        |¦  «        }||z  |d         z  }|dd…xx         |dd…         z  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        ¦  «         ~	|}Œä |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Ú	centroidsÚtimeÚassignÚnpÚbincountÚminÚmaxÚargsortÚarangeÚcumsumÚsumÚrangeÚintÚallÚappendÚvstack)ÚxtÚnc1Únc2Ú	rebalanceÚclustering_niterÚargsÚdr   ÚlogÚkmr#   Ú
centroids1Út0Ú_Úassign1ÚbcÚoÚccÚall_nc2Úbc_sumÚi0Úc2Úc1Úi1ÚsubsetÚxtsubs                             r	   Útwo_level_clusteringrL      s�  € ð 	Œ�Œ€Aà�hŠh�y %Ñ(Ô(€GàÐ
)�%ˆ%¥	€Cà€CÐU ¤ÐUÐUÀCÐUÐUÐPSÐUÐUÑVÔVÐVØ€CÐ!Ñ"Ô"Ð"å	ŒØ	ˆ3ð
Ø&Ø $ð
ð 
ð ð
ð 
€Bð
 ‡H‚HˆR�L„L€LàÔ)Ð*€OØ€C�E„E€Eð ”€Jà€CÐ$Ñ%Ô%Ð%Ý	Œ‰Œ€BØ—’˜2‘”�J€A€wÝ	Œ�W¨Ð	,Ñ	,Ô	,€BØ€CÐR•4”9‘;”; Ñ#ÐRÐRÐR½sÀ2¹w¼wÐRÐRÍÈRÉÌÐRÐRÑSÔSÐSØ�ŠÑÔ€AØ
àð 	EåŒY�s˜Q‘wÑÔ #Ñ%¨Ñ,ˆØ�Q�R�R”&˜2˜c˜r˜cœ7Ñ"ˆˆå”˜2‘”ˆØ˜3‘, &¨¤*Ñ,ˆØ���ˆˆŒ�w˜s ˜s”|Ñ#ˆˆ‰Ý�7‰|Œ|˜sÒ"Ð"Ð"Ð"ØˆÐC¥c¨'¡l¤lÐCÐCµS¸±\´\ÐCÐCÑDÔDÐDð 
€BØ	€BÝ	Œ‰Œ€BÝ�C‰jŒjð ð ˆÝ�'˜"”+ÑÔˆØˆÐU•”	‘”˜bÑ ÐUÐUÐU¸rÐUÐUÀCÐUÐUÈcÐUÐUÐUÐ[]ÐeiÐjÑjÔjÐjØ�"�R”&‰[ˆØ�2�b�5”ˆÝŒv�g˜f”o¨Ò+Ñ,Ô,Ð,Ð,Ð,ÝŒ\˜!˜SÐ)Ð) DÐ)Ð)ˆØ�6”
ˆØ
�Š�‰ŒˆØ×Ò˜rÔ1Ñ2Ô2Ð2Ø
�	Š	�"”,ÑÔÐØØˆˆØ€CÐ+•4”9‘;”; Ñ#Ð+Ð+Ð+Ð+Ñ,Ô,Ð,ÝŒ9�R‰=Œ=˜/Ð)Ð)r   c                 ó  — t          j        | ¦  «        } t          | t           j        ¦  «        r‰t	          | j                             ¦   «         ¦  «        D ]F}| j                             |¦  «        }|                     |¦  «         | 	                    |¦  «        }ŒGt          | j        |fi |¤Ž d| _        dS t          | t           j        ¦  «        sJ ‚| j        t           j        k    sJ ‚t!          t#          j        | j        ¦  «        ¦  «        }t)          d|¦  «         t+          ||| j        fi |¤Ž\  }}| j                             |¦  «         | j                             |¦  «         |                      |¦  «         dS )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_L2r0   r'   ÚsqrtÚnlistr   rL   Ú	quantizerÚadd)rV   r4   r9   ÚiÚvtr5   r$   r?   s           r	   rU   rU   _   s]  € õ
 Ô  Ñ'Ô'€EÝ�%�Ô0Ñ1Ô1ð Ý�u”{×'Ò'Ñ)Ô)Ñ*Ô*ð 	ð 	ˆAØ”—’ Ñ"Ô"ˆBØ�HŠH�R‰LŒLˆLØ—’˜"‘”ˆBˆBÝ# E¤K°Ð<Ð<°tÐ<Ð<Ð<ØˆÔØˆÝ�e�Uœ^Ñ,Ô,Ð,Ð,Ð,ØÔ¥¤Ò/Ð/Ð/Ð/å
�bŒg�e”kÑ"Ô"Ñ
#Ô
#€CÝ	ˆ,˜ÑÔÐå'¨¨C°´ÐEÐEÀÐEÐE�L€IˆqØ	„O×Ò˜)Ñ$Ô$Ð$Ø	„O×Ò˜	Ñ"Ô"Ð"à	‡K‚K��O„O€O€O€Or   c                   ó8   — e Zd ZdZd„ Zd„ Zd„ Zd„ Zd„ Zd	d„Z	dS )
Ú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¬¦  «        | _        d S ©NÚfloat32©Údtype)r'   ÚascontiguousarrayÚx©Úselfrj   s     r	   Ú__init__zDatasetAssign.__init__†   s   € ÝÔ% a¨yÐ9Ñ9Ô9ˆŒˆˆr   c                 ó&   — | j         j        d         S )Nr   ©rj   r   ©rl   s    r	   ÚcountzDatasetAssign.count‰   ó   € ØŒvŒ|˜AŒÐr   c                 ó&   — | j         j        d         S ©Nr   ro   rp   s    r	   ÚdimzDatasetAssign.dimŒ   rr   r   c                 ó   — | j         |         S r   )rj   ©rl   Úindicess     r	   Ú
get_subsetzDatasetAssign.get_subset�   s   € ØŒv�gŒÐr   c                 ó8   — t          j        | j        |d¦  «        S rt   )r    Úknnrj   ©rl   r$   s     r	   Úperform_searchzDatasetAssign.perform_search’   s   € ÝŒy˜œ ¨AÑ.Ô.Ð.r   Nc                 óœ  — |                       |¦  «        \  }}|                     ¦   «         }|                     ¦   «         }|j        \  }}t          j        ||fd¬¦  «        }|€'t          j                             ||| j        ¦  «         n=t          j                             |||d d …t          j        f         | j        z  ¦  «         |||fS re   )	r}   Úravelr   r'   Úzerosr^   rS   rj   Únewaxis)rl   r$   ÚweightsÚDÚIÚncr:   Úsum_per_centroids           r	   Ú	assign_tozDatasetAssign.assign_to•   s·   € Ø×"Ò" 9Ñ-Ô-‰ˆˆ1à�GŠG‰IŒIˆØ�GŠG‰IŒIˆØ”‰ˆˆAÝœ8 R¨ G°9Ð=Ñ=Ô=ÐØˆ?ÝŒF�IŠIÐ&¨¨4¬6Ñ2Ô2Ð2Ð2åŒF�IŠIÐ&¨¨7°1°1°1µb´j°=Ô+AÀDÄFÑ+JÑKÔKÐKà�!Ð%Ð%Ð%r   r   )
Ú__name__Ú
__module__Ú__qualname__Ú__doc__rm   rq   ru   ry   r}   r‡   r   r   r	   rb   rb   ‚   s   € € € € € ðHð Hð:ð :ð :ðð ð ðð ð ðð ð ð/ð /ð /ð&ð &ð &ð &ð &ð &r   rb   c                   ó    — e Zd ZdZdd„Zd„ ZdS )ÚDatasetAssignGPUz GPU version of the previous Fc                 ó  — t                                | |¦  «         t          j        |j        d         ¦  «        }|dk    r.t          j        t          j        ¦   «         ||¦  «        | _        d S t          j        |¦  «        | _        d S )Nr   r   )	rb   rm   r    ÚIndexFlatL2r   Úindex_cpu_to_gpuÚStandardGpuResourcesrV   Úindex_cpu_to_all_gpus)rl   rj   Úgpu_idr   rV   s        r	   rm   zDatasetAssignGPU.__init__§   sx   € Ý×Ò˜t QÑ'Ô'Ð'ÝÔ! !¤'¨!¤*Ñ-Ô-ˆØ�QŠ;ˆ;ÝÔ/ÝÔ*Ñ,Ô,Ø˜ñô ˆDŒJˆJˆJõ
 Ô4°UÑ;Ô;ˆDŒJˆJˆJr   c                 ó¨   — | j                              ¦   «          | j                              |¦  «         | j                              | j        d¦  «        S rt   )rV   Úresetr^   Úsearchrj   r|   s     r	   r}   zDatasetAssignGPU.perform_search²   sD   € ØŒ
×ÒÑÔÐØŒ
�Š�yÑ!Ô!Ð!ØŒz× Ò  ¤¨Ñ+Ô+Ð+r   N)F)rˆ   r‰   rŠ   r‹   rm   r}   r   r   r	   r�   r�   ¤   s=   € € € € € Ø'Ð'ð	<ð 	<ð 	<ð 	<ð,ð ,ð ,ð ,ð ,r   r�   c                 óÄ  — | j         d         }|j         d         }|€|dz                       d¦  «        }|€:t          j        |                      d¦  «                             d¦  «        ¦  «        }|d| z  |j        z  z
  }|                     d¬¦  «        }|                     ¦   «         |t          j        |¦  «        |z  z            |                     ¦   «         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   Né   r   )Úaxis)	r   r.   r'   ÚarrayÚpowerÚTÚargminr   r,   )	ÚxqÚxbÚxq_normsÚxb_normsÚnqÚnbÚd2r„   rƒ   s	            r	   Úsparse_assign_to_denser¥   ¸   sÃ   € ð
 
Œ�!Œ€BØ	Œ�!Œ€BØÐØ˜!‘G—=’= Ñ#Ô#ˆØÐÝ”8˜BŸHšH Q™KœKŸOšO¨AÑ.Ô.Ñ/Ô/ˆØ
�Q˜‘V˜bœd‘]Ñ
"€BØ
�	Š	�qˆ	ÑÔ€AØ
�Š‰
Œ
�1•r”y ‘}”} rÑ)Ñ)Ô*¨X¯^ª^Ñ-=Ô-=Ñ=€AØˆaˆ4€Kr   é @  c           
      ó&  ‡ ‡‡‡‡‡‡
‡‡— ‰ j         d         }‰j         d         Št          j        |d¬¦  «        Š
‰
                     t          j        ¦  «         t          j        |t          ¬¦  «         Š‰€‰dz                       d¦  «        Šˆ
ˆˆˆˆˆˆˆ ˆf	d„}|dk    s|dk    s|‰k    r-t          t          |t          d|‰¦  «        ¦  «        ¦  «         n4t          |¦  «        }	|	 	                    |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   rf   rg   Nr˜   r   c           
      óÒ  •	— ‰| | ‰z   …         }‰
| | ‰z   …         }‰	| | ‰z   …         }‰€;t          j        |                     d¦  «                             d¦  «        ¦  «        }n‰| | ‰z   …         }t	          d‰‰¦  «        D ]b}t          |‰||‰z   …         |‰||‰z   …         ¬¦  «        \  }}|dk    r||d d …<   ||d d …<   ŒC||k     }||         |z   ||<   ||         ||<   Œcd S )Nr˜   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_blockÙ   s+  ø€ Ø�a˜!˜c™'�k”?ˆØ�1�q˜3‘w�;”ˆØ�1�q˜3‘w�;”ˆØÐÝœX h§n¢n°QÑ&7Ô&7×&;Ò&;¸AÑ&>Ô&>Ñ?Ô?ˆNˆNà% a¨!¨c©' kÔ2ˆNÝ�q˜"˜cÑ"Ô"ð 	(ð 	(ˆAÝ+ØØ�1�q˜3‘w�;”Ø'Ø! ! a¨#¡g +Ô.ð	ñ ô ‰FˆB�ð �AŠvˆvØ��q�q�q‘	Ø��q�q�q‘	�	à˜F’{�Ø! $œx¨!™|��t‘Ø! $œx��t‘�ð	(ð 	(r   )r   r'   ÚemptyÚfillÚinfÚonesr0   r.   ÚlistÚmapr/   r   )rž   rŸ   r    r¡   r²   r±   Úntr¢   r³   Úpoolrƒ   r„   r£   s   ``````    @@@r	   Úsparse_assign_to_dense_blocksr¼   É   s3  øøøøøøøøø€ ð 
Œ�!Œ€BØ	Œ�!Œ€BÝ
Œ�˜9Ð%Ñ%Ô%€AØ‡F‚F�2Œ6�N„N€NÝ	Œ��3Ð	Ñ	Ô	Ð€AàÐØ˜!‘G—=’= Ñ#Ô#ˆð(ð (ð (ð (ð (ð (ð (ð (ð (ð (ð (ð (ð (ð. 
ˆQ‚w€w�"˜’'�'˜R 3šY˜YÝ�SÐ#¥U¨1¨b°#Ñ%6Ô%6Ñ7Ô7Ñ8Ô8Ð8Ð8å˜"‰~Œ~ˆØ�ŠÐ#¥U¨1¨b°#Ñ%6Ô%6Ñ7Ô7Ð7àˆaˆ4€Kr   c                   ó,   — e Zd ZdZd„ Zd„ Zd„ Zdd„ZdS )ÚDatasetAssignSparserc   c                 óÊ   — |j         t          j        j        k    sJ ‚|| _        t          j        |                     d¦  «                             d¦  «        ¦  «        | _	        d S )Nr˜   r   )
Ú	__class__ÚscipyÚsparseÚ
csr_matrixrj   r'   rš   r›   r.   Úsquared_normsrk   s     r	   rm   zDatasetAssignSparse.__init__ý   sO   € ØŒ{�eœlÔ5Ò5Ð5Ð5Ð5ØˆŒÝœX a§g¢g¨a¡j¤j§n¢n°QÑ&7Ô&7Ñ8Ô8ˆÔÐÐr   c                 ód   — t          j        | j        |                              ¦   «         ¦  «        S r   )r'   rš   rj   Útodenserw   s     r	   ry   zDatasetAssignSparse.get_subset  s$   € ÝŒx˜œ˜wœ×/Ò/Ñ1Ô1Ñ2Ô2Ð2r   c                 ó:   — t          | j        || j        ¬¦  «        S )N)r    )r¼   rj   rÄ   r|   s     r	   r}   z"DatasetAssignSparse.perform_search  s%   € Ý,ØŒF�I¨Ô(:ð<ñ <ô <ð 	<r   Nc                 óÐ  — |                       |¦  «        \  }}|                     ¦   «         }|                     ¦   «         }| j        j        d         }|€t	          j        |d¬¦  «        }t          |¦  «        }t          j         	                    ||t	          j
        |dz   ¦  «        f||f¬¦  «        }t	          j        || j        z                       ¦   «         ¦  «        }|||fS )Nr   rf   rg   r   )r   )r}   r   rj   r   r'   r·   ÚlenrÁ   rÂ   Ú
csc_matrixr,   rš   rÆ   )	rl   r$   r‚   rƒ   r„   Únr…   Úmr†   s	            r	   r‡   zDatasetAssignSparse.assign_to	  sÑ   € Ø×"Ò" 9Ñ-Ô-‰ˆˆ1à�GŠG‰IŒIˆØ�GŠG‰IŒIˆØŒFŒL˜ŒOˆØˆ?Ý”g˜a yÐ1Ñ1Ô1ˆGÝ�‰^Œ^ˆåŒL×#Ò#Ø�a�œ 1 q¡5Ñ)Ô)Ð*Ø�q�'ð $ñ ô ˆõ œ8 Q¨¬¡Z×$8Ò$8Ñ$:Ô$:Ñ;Ô;Ðà�!Ð%Ð%Ð%r   r   )rˆ   r‰   rŠ   r‹   rm   ry   r}   r‡   r   r   r	   r¾   r¾   ù   sa   € € € € € ðHð Hð9ð 9ð 9ð
3ð 3ð 3ð<ð <ð <ð&ð &ð &ð &ð &ð &r   r¾   c                 ó˜   — t          j        |d¬¦  «        }t          j        t	          |¦  «        | t          j        |¦  «        ¦  «        S )NÚint64rg   )r'   ri   r    Úimbalance_factorrÉ   Úswig_ptr)Úkr&   s     r	   rÏ   rÏ     s<   € ÝÔ! &°Ð8Ñ8Ô8€FÝÔ!¥# f¡+¤+¨qµ%´.ÀÑ2HÔ2HÑIÔIÐIr   c                 ó¤   — | j         t          j        k    rdS dd l}t	          | |j        ¦  «        rdS t          dt          | ¦  «        › �¦  «        ‚)NFr   TzUnknown tensor type )rÀ   r'   ÚndarrayÚtorchrO   ÚTensorÚNotImplementedErrorÚtype)rj   rÔ   s     r	   Úcheck_if_torchrØ      sU   € Ø„{•b”jÒ Ð ØˆuØ€L€L€LÝ�!�U”\Ñ"Ô"ð ØˆtÝ
Ð>µT¸!±W´WÐ>Ð>Ñ
?Ô
?Ð?r   c                 óš  — |€t           j        }|j        \  }}d}t          |¦  «        }t          j        | dk    ¦  «        d         }t          |¦  «        dk    rdS |r ddl}|                     |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k    rù|                      d¦  «        dz
  }
d|
|
dk     <   |
|
 	                    ¦   «         z  }
|
dk     	                    ¦   «         }t          ||j        ¦  «        }|                     |||
¬¦  «        }t          |d|…         |¦  «        D ]F\  }}||         }||	z  ||<   ||	z  ||<   | |         dz  | |<   | |xx         | |         z  cc<   |dz  }ŒG||d…         }t          |¦  «        dk    °ù|S )z/ reassign centroids when some of them collapse Nr   r˜   g      P?r   Úfloat)rR   Úp)r'   Úrandomr   rØ   ÚwhererÉ   rÔ   Ú	ones_likeÚastyper.   r)   rR   ÚchoiceÚzip)Úhassignr$   ÚrsrÑ   r:   ÚnsplitÚis_torchÚempty_centsrÔ   ÚfacÚprobasÚnnzÚnreplaceÚcjsÚciÚcjÚcs                    r	   Úreassign_centroidsrï   )  s  € à	€zÝŒYˆØŒ?�D€A€qØ€FÝ˜iÑ(Ô(€Hå”(˜7 aš<Ñ(Ô(¨Ô+€Kå
ˆ;ÑÔ˜1ÒÐØˆqàð )ØˆˆˆØ�oŠo˜i¨œlÑ+Ô+ˆˆåŒl˜9 Qœ<Ñ(Ô(ˆØˆˆˆ!ˆ€H€H„H�	Ñ€H€H�HØˆˆˆ1ˆ€I€I„I�Ñ€I€I�Iõ ˆkÑ
Ô
˜QÒ
Ð
à—’ Ñ(Ô(¨1Ñ,ˆØˆˆv˜ŠzÑØ�&—*’*‘,”,ÑˆØ˜Šz×ÒÑ Ô ˆå�s˜KÔ,Ñ-Ô-ˆØ�iŠi˜ ¨FˆiÑ3Ô3ˆå˜+ i x iÔ0°#Ñ6Ô6ð 	ð 	‰FˆB�à˜"”ˆAØ ™GˆI�b‰MØ ™GˆI�b‰Mà! "œ+¨Ñ*ˆG�B‰KØ�BˆKˆKŒK˜7 2œ;Ñ&ˆKˆK‰KØ�a‰KˆFˆFà! ( ) )Ô,ˆõ) ˆkÑ
Ô
˜QÒ
Ð
ð, €Mr   éÒ  Fc           
      óš  — |                      ¦   «         |                     ¦   «         }}|rt          nt          }	 |	d||| ||fz  ¦  «         t          j                             |¦  «        }
t          d¦  «         t          j        ¦   «         }|
                     || d¬¦  «        }| 	                    |¦  «        }t          |¦  «        }g } |	d¦  «         d}g }t          |¦  «        D �]Ú}t          j        ¦   «         } |	ddd	¬
¦  «         |                     |¦  «        \  }}} |	ddd	¬
¦  «         |t          j        ¦   «         |z
  z  }|                     ¦   «         }|r|                     ¦   «         }|                     |¦  «         t	          j        || ¬¦  «        }|                     dd¦  «                             d¦  «        }d||dk    <   |r1ddl}|                     |¦  «                             |j        ¦  «        }||z  }t/          |||
¦  «        }|t          j        ¦   «         |z
  |t1          | |¦  «        |dœ} |	d||d         |d         ||d         |fz  ¦  «         |                     |¦  «         |�? |	d|¦  «         |rddl}|                     ||¦  «         �ŒÅt	          j        ||¦  «         �ŒÜ|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)rR   Úreplacez  doner   Ú	assigningr   Tr   zcompute centroidsr   r   r   rf   N)Úobjr%   Útime_searchrÏ   rä   zM  Iteration %d (%.2f s, search %.2f s): objective=%g imbalance=%.3f nsplit=%dr%   rõ   rÏ   zstoring centroids in)rq   ru   r   r
   r'   rÜ   ÚRandomStater%   rà   ry   rØ   r/   r‡   r.   Úitemr2   r(   Úreshaperß   rÔ   Ú
from_numpyÚtoÚdevicerï   rÏ   Úsave)rÑ   Údatar   ÚseedÚ
checkpointr   Úreturn_statsrË   r:   r;   rã   r>   Úpermr$   rå   r#   Út_search_totrô   r_   Út0sr&   rƒ   ÚsumsÚerrrâ   rç   rÔ   rä   Úss                                r	   Úkmeansr  Z  s  € ð �:Š:‰<Œ<˜Ÿš™œ€q€AØÐ
)�%ˆ%¥	€Cà€Cð 
$Ø()¨1¨a°¸Ð'=ñ	>ñ ?ô ?ð ?õ 
Œ×	Ò	˜tÑ	$Ô	$€BÝ	ˆ,ÑÔÐÝ	Œ‰Œ€Bà�9Š9�Q˜Q¨ˆ9Ñ.Ô.€DØ—’ Ñ%Ô%€IÝ˜iÑ(Ô(€Hà€Oà€Cˆ�M„M€MØ€LØ
€CÝ�5‰\Œ\ð 1/ñ 1/ˆÝŒi‰kŒkˆàˆˆK˜T¨Ð.Ñ.Ô.Ð.ØŸ.š.¨Ñ3Ô3‰ˆ��4àˆÐ T°Ð6Ñ6Ô6Ð6à�œ	™œ cÑ)Ñ)ˆà�eŠe‰gŒgˆØð 	Ø—(’(‘*”*ˆCØ�
Š
�3‰Œˆå”+˜f°Ð2Ñ2Ô2ˆà�oŠo˜b !Ñ$Ô$×+Ò+¨IÑ6Ô6ˆØˆˆC�1ŠH‰Øð 	8ØˆLˆLˆLØ×"Ò" 3Ñ'Ô'×*Ò*¨4¬;Ñ7Ô7ˆCà˜3‘Jˆ	å# G¨Y¸Ñ;Ô;ˆð Ý”Y‘[”[ 2Ñ%Ø'Ý 0°°FÑ ;Ô ;Øð
ð 
ˆð 	ˆð 5à�a˜”i  =Ô!1Ø˜Ð,Ô-Øð9ññ 	
ô 	
ð 	
ð 	×Ò˜qÑ!Ô!Ð!àÐ!ØˆCÐ&¨
Ñ3Ô3Ð3Øð /Ø���Ø—
’
˜9 jÑ1Ô1Ð1Ñ1å”˜
 IÑ.Ô.Ð.ùàð Ø˜/Ð)Ð)àÐr   )Tr   )NN)NNr¦   r¦   Nr   )r   rð   NTF)r‹   Únumpyr'   r    r%   Úmultiprocessing.poolr   Úscipy.sparserÁ   ÚImportErrorr   r
   rL   rU   rb   r�   r¥   r¼   r¾   rÏ   rØ   rï   r  r   r   r	   ú<module>r     sÙ  ððð ð Ð Ð Ð Ø €€€Ø €€€Ø +Ð +Ð +Ð +Ð +Ð +ð@ØÐÐÐÐøØð @ð @ð @Ø	€EÐ
>Ñ?Ô?Ð?Ð?Ð?ð@øøøð	ð 	ð 	ðD*ð D*ð D*ð D*ðNð ð ðF&ð &ð &ð &ð &ñ &ô &ð &ðD,ð ,ð ,ð ,ð ,�}ñ ,ô ,ð ,ð(ð ð ð ð$ HLð-ð -ð -ð -ð`&ð &ð &ð &ð &˜-ñ &ô &ð &ðDJð Jð Jð
@ð @ð @ð-ð -ð -ð -ðb CGØðRð Rð Rð Rð Rð Rs   – ›.­.