
    Oh:                         S SK rS SKrS SKrS SKrS SKJr  S rS rSS jr	SS jr
S rS r SS	 jrS
 rSS jrS r " S S5      r " S S\5      r " S S5      r " S S5      rg)    N)
ThreadPoolc                    ^ ^ T R                   u  p#TR                   X#4:X  d   e[        U U4S j[        U5       5       5      nUT R                  -  $ )z;computes the intersection measure of two result tables
    c              3   p   >#    U H,  n[         R                  " TU   TU   5      R                  v   M.     g 7fN)npintersect1dsize).0iI1I2s     P/var/www/html/shao/venv/lib/python3.13/site-packages/faiss/contrib/evaluation.py	<genexpr>+knn_intersection_measure.<locals>.<genexpr>   s1      A 	r!ube$))s   36)shapesumranger	   )r   r   nqrankninters   ``   r   knn_intersection_measurer      sP     xxHB88z!!! r F BGG    c                     U R                   S-
  nX:  n[        R                  " U 5      n[        U5       H'  nXg   XPU   XS-       R	                  5       -   XgS-   '   M)     XaU   X%   4$ )zselect a set of results    )r	   r   
zeros_liker   r   )limsDIthreshr   masknew_limsr   s           r   filter_range_resultsr"      sm    	QB:D}}T"H2Y"+!WtE{(C(G(G(IIQ tWag%%r   c                 6  ^ ^^^^^	^
 UU 4S jm
UU4S jmT R                   S-
  nTR                   S-
  U:X  d   e[        R                  " USS9m	UU	U
4S jn[        S5      nUR	                  U[        U5      5        [        T SS T SS	 -
  TSS TSS	 -
  T	US
9$ )zqcompute the precision and recall of range search results. The
function does not take the distances into account. c                     > TTU    TU S-       $ Nr    r   Ireflims_refs    r   ref_result_for range_PR.<locals>.ref_result_for,       HQKQ00r   c                     > TTU    TU S-       $ r%   r&   )r   Inewlims_news    r   new_result_for range_PR.<locals>.new_result_for/   r,   r   r   int64dtypec                 n   > T" U 5      nT" U 5      n[         R                  " X5      n[        U5      TU '   g r   )r   r   len)qgt_idsnew_idsinterr0   r   r*   s       r   compute_PR_for range_PR.<locals>.compute_PR_for7   s8      " !# v/Jq	r      Nmode)r	   r   zerosr   mapr   counts_to_PR)r)   r(   r/   r.   r@   r   r;   poolr0   r   r*   s   ````    @@@r   range_PRrE   (   s    11 
	B==1"""XXb(F b>DHH^U2Y'x}$x}$	 r   c                    US:X  aY  U R                  5       UR                  5       UR                  5       p!n US:  a  X!-  nOSnU S:  a  X -  nXE4$ US:X  a  SnXE4$ SnXE4$ US:X  a|  U S:H  nSX'   X -  nX   S:H  R                  [        5      Xv'   US:H  n[        R                  " X&   S:H  5      (       d   eSX&'   SX'   X!-  nUR                  5       UR                  5       4$ [        5       e)zcomputes a  precision-recall for a ser of queries.
ngt = nb of GT results per query
nres = nb of found results per query
ninter = nb of correct results per query (smaller than nres of course)
overallr         ?        averager   )r   astypefloatr   allmeanAssertionError)	ngtnresr   r@   	precisionrecallr    recalls
precisionss	            r   rC   rC   P   s    yGGItxxz6::<6!8II7\F    QYF    F  		 ax	,q007 qyvvfla'((((
]
 ',,.00 r   c                     [         R                  " U5      n[         R                  " U5      n[        U 5      S-
  n[        U5       H1  nX   XS-      pX'U n	XU n
U
R	                  5       nX   X7U& X   XGU& M3     X44$ )z%sort 2 arrays using the first as key r   )r   
empty_liker6   r   argsort)r   r   r   r   D2r   r   l0l1iidios               r   sort_range_res_2r_   ~   s    	q	B	q	B	TQB2Y$1u+B"X"XJJLEb	Eb	  6Mr   c                     [         R                  " U5      n[        U 5      S-
  n[        U5       H%  nX   XS-      peXU X%U& X%U R	                  5         M'     U$ r%   )r   rW   r6   r   sort)r   r   r   r   r   rZ   r[   s          r   sort_range_res_1rb      s\    	q	B	TQB2Y$1u+BHb	
b	  Ir   c           	      L  ^ ^^^^^^^^ SU;   a  [        T T5      mSU;   a  [        TTT5      u  mmUU 4S jmUUU4S jmT R                  S-
  nTR                  S-
  U:X  d   e[        T5      n	[        R
                  " XS4SS9mUUUU4S	 jn
[        S
5      nUR                  U
[        U5      5        [        R
                  " U	5      n[        R
                  " U	5      n[        U	5       H2  n[        TSS2US4   TSS2US4   TSS2US4   US9u  nnXU'   UX'   M4     X4$ )zcompute precision-recall values for range search results
for several thresholds on the "new" results.
This is to plot PR curves
refnewc                     > TTU    TU S-       $ r%   r&   r'   s    r   r*   4range_PR_multiple_thresholds.<locals>.ref_result_for   r,   r   c                 ,   > TU    TU S-      p!TX TX 4$ r%   r&   )r   rZ   r[   Dnewr.   r/   s      r   r0   4range_PR_multiple_thresholds.<locals>.new_result_for   s)    !hq1uoBB{DK''r   r      r2   r3   c                   > T	" U 5      nT" U 5      u  p#[        U5      TU S S 2S4'   UR                  S:X  a  g [        R                  " UT
5      nUTU S S 2S4'   UR                  S:X  a  g [        R                  " X5      nSXU[        U5      :H  '   [        R                  " X   U:H  5      n[        R
                  " S/U45      nXd   TU S S 2S4'   g )Nr   r   r>      )r6   r	   r   searchsortedcumsumhstack)r7   r8   res_idsres_disrQ   r\   n_okcountsr0   r*   
thresholdss          r   r;   4range_PR_multiple_thresholds.<locals>.compute_PR_for   s    ")!,f+q!Qw<<1 oogz2q!Qw;;! __V- "Vyyw./ yy1#t%*q!Qwr   r=   Nr   rm   r?   )
rb   r_   r	   r6   r   rA   r   rB   r   rC   )r)   r(   r/   ri   r.   ru   r@   do_sortr   ntr;   rD   rU   rT   tprrt   r0   r*   s   ``````           @@@r   range_PR_multiple_thresholdsr|      s&    $/ %hd;
d1( 
	B==1"""	ZBXXrqk1F% %4 b>DHH^U2Y' "JhhrlG2Yq!Qw1a&Aq/
1 1
  r   c                 "   [         R                  " X/5      nUR                  5         [        U5      n[         R                  " U5      nUSS USS -
  USS& X5U:     n[         R
                  " X`SS9S-
  n[         R
                  " XaSS9S-
  nXx4$ )zofor two tables, cluster them by merging values closer than thr.
Returns the cluster ids for each table element r   Nr>   right)side)r   rp   ra   r6   onesrn   )	tab1tab2thrtabndiffsunique_valsidx1idx2s	            r   _cluster_tables_with_tolerancer      s     ))TL
!CHHJCAGGAJEAB#cr("E!"Ick"K??;7;a?D??;7;a?D:r   c           
         [         R                  R                  XUS9  [        R                  " 5       n[        [        U5      5       H  n[         R                  " X   X6   :H  5      (       a  M'  X@U   R                  5       -  n[        X   X&   U5      u  p[         R                  " U5       H=  n
XS   :X  a  M  X:H  nUR                  [        XU4   5      [        X6U4   5      5        M?     M     g)zNtest that knn search results are identical, with possible ties.
Raise if not. )rtolr>   N)r   testingassert_allcloseunittestTestCaser   r6   rM   maxr   uniqueassertEqualset)Drefr(   ri   r.   r   testcaser   r{   DrefCDnewCdisr    s               r   check_ref_knn_with_drawsr      s     JJt5  "H3t966$'TW$%% 7;;= 5dgtwJ99U#CBi<D  TT']!3Sg5GH	 $ r   c                    [         R                  R                  X5        [        U 5      S-
  n[	        U5       H  nX   XS-      pX(U	 n
XXU	 nXU	 nXHU	 n[         R
                  " X:H  5      (       a  O6S nU" X5      u  pU" X5      u  p[         R                  R                  X5        [         R                  R                  XSS9  M     g)zHcompare range search results wrt. a reference result,
throw if it fails r   c                 2    U R                  5       nX   X   4$ r   )rX   )r   r   r^   s      r   sort_by_ids,check_ref_range_results.<locals>.sort_by_ids  s    IIKtQTz!r      )decimalN)r   r   assert_array_equalr6   r   rM   assert_array_almost_equal)Lrefr   r(   Lnewri   r.   r   r   rZ   r[   Ii_refIi_newDi_refDi_newr   s                  r   check_ref_range_resultsr   	  s     JJ!!$-	TQB2Y$1u+B66&"##"  +6:V*6:VJJ))&9


,,VQ,G! r   c                   B    \ rS rSrSrS rS rS rS rS r	S r
S	 rS
rg)OperatingPointsi&  zk
Manages a set of search parameters with associated performance and time.
Keeps the Pareto optimal points.
c                      / U l         / U l        g r   operating_pointssuboptimal_pointsselfs    r   __init__OperatingPoints.__init__,  s    !
 "$r   c                     [         e)z0return -1 if k1 > k2, 1 if k2 > k1, 0 otherwise NotImplementedr   k1k2s      r   compare_keysOperatingPoints.compare_keys3      r   c                     [         e)zBparameters to say we do noting, takes 0 time and has 0 performancer   r   s    r   do_nothing_keyOperatingPoints.do_nothing_key7  r   r   c                 L    U R                    H  u  p4nXA:  d  M  XR::  d  M    g   g)NFT)r   )r   perf_newt_new_perfry   s         r   is_pareto_optimal!OperatingPoints.is_pareto_optimal;  s(    //JAQAJ 0 r   c                     SnSnU R                   U R                  -    H5  u  pEnU R                  X5      nUS:  a  Xb:  a  UnUS:  d  M,  XS:  d  M3  UnM7     X24$ )z+predicts the bound on time and performance rI   rH   r   )r   r   r   )r   keymin_timemax_perfkey2r   ry   cmps           r   predict_boundsOperatingPoints.predict_boundsA  si    !22T5K5KKMD##C.CQw< HQw?#H L !!r   c                 J    U R                  U5      u  p#U R                  X#5      $ r   )r   r   )r   r   r   r   s       r   should_run_experiment%OperatingPoints.should_run_experimentO  s&    #2237%%h99r   c                    U R                  X#5      (       a  SnU[        U R                  5      :  aq  U R                  U   u  pVnX&:  a:  X7:  a5  U R                  R	                  U R                  R                  U5      5        OUS-  nU[        U R                  5      :  a  Mq  U R                  R	                  XU45        gU R                  R	                  XU45        g)Nr   r   TF)r   r6   r   r   appendpop)r   r   r   ry   r   op_Lsperf2t2s           r   add_operating_point#OperatingPoints.add_operating_pointS  s    !!$**Ac$//00#'#8#8#; b=QV**11--11!46 FA c$//00 !!((#Q8""))3a.9r   r   N)__name__
__module____qualname____firstlineno____doc__r   r   r   r   r   r   r   __static_attributes__r&   r   r   r   r   &  s*    
$":r   r   c                   h    \ rS rSrSrS rS rS rS rS r	\
R                  4S jrS	 rS
 rS rSrg)OperatingPointsWithRangesie  z
Set of parameters that are each picked from a discrete range of values.
An increase of each parameter is assumed to make the operation slower
and more accurate.
A key = int array of indices in the ordered set of parameters.
c                 <    [         R                  U 5        / U l        g r   )r   r   rangesr   s    r   r   "OperatingPointsWithRanges.__init__m  s      &r   c                 <    U R                   R                  X45        g r   )r   r   r   namevaluess      r   	add_range#OperatingPointsWithRanges.add_ranger  s    D>*r   c                 |    [         R                  " X:  5      (       a  g[         R                  " X!:  5      (       a  gg)Nr   r>   r   )r   rM   r   s      r   r   &OperatingPointsWithRanges.compare_keysu  s-    66"(66"(r   c                 Z    [         R                  " [        U R                  5      [        S9$ )Nr3   )r   rA   r6   r   intr   s    r   r   (OperatingPointsWithRanges.do_nothing_key|  s    xxDKK(44r   c                     [        [        R                  " U R                   VVs/ sH  u  p[	        U5      PM     snn5      5      $ s  snnf r   )r   r   prodr   r6   r   s      r   num_experiments)OperatingPointsWithRanges.num_experiments  s2    277DKKHKLDCKKHIJJHs   Ac                 D   US:X  d  US:  d   eU R                  5       n[        R                  R                  S5      nUS:X  d  X1:  a  UR	                  US-
  5      nOUR                  US-
  US-
  SS9nSUS-
  /U Vs/ sH  n[        U5      S-   PM     sn-   nU$ s  snf )zlsample a set of experiments of max size n_autotune
(run all experiments in random order if n_autotune is 0)
r   rm   {   F)r	   replacer   )r   r   randomRandomStatepermutationchoicer   )r   
n_autotunerstotexexperimentscnos         r   sample_experiments,OperatingPointsWithRanges.sample_experiments  s     Q*/11$$&YY""3'?e0..3K))	
Q $ ?K %!)n'LC1'LL (Ms   ?Bc                     [         R                  " [        U R                  5      [        S9n[        U R                  5       H&  u  nu  pEU[        U5      -  X#'   U[        U5      -  nM(     US:X  d   eU$ )z/Convert a sequential experiment number to a keyr3   r   )r   rA   r6   r   r   	enumerate)r   r   kr   r   r   s         r   
cno_to_key$OperatingPointsWithRanges.cno_to_key  se    HHS%S1!*4;;!7A~V$ADCKC "8 axxr   c           	      v    [        U R                  5       VVVs0 sH  u  nu  p4X4X      _M     snnn$ s  snnnf )z3Convert a key to a dictionary with parameter values)r  r   )r   r  r   r   r   s        r   get_parameters(OperatingPointsWithRanges.get_parameters  sB     &/t{{%;
%;!>D ,%;
 	
 
s   4c                     U R                    H(  u  p4X:X  d  M  U Vs/ sH  oUU:  d  M
  UPM     nnXdSS&   g   [        SU S35      es  snf )z$remove too large values from a rangeNz
parameter z
 not found)r   RuntimeError)r   r   max_valname2r   vval2s          r   restrict_range(OperatingPointsWithRanges.restrict_range  sT    ![[ME}#)96a[69 q		 )
 ZvZ899 :s
   AA)r   N)r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r   r&   r   r   r   r   e  s>    
+5K 13		  
:r   r   c                        \ rS rSrS rS rSrg)	TimerIteri  c                     / U l         UR                  U l        Xl        UR                  S:  a!  [        R
                  " UR                  5        g g )Nr   )tsrunstimerrx   faissomp_set_num_threads)r   r  s     r   r   TimerIter.__init__  s;    JJ	
88q=%%ehh/ r   c                    U R                   nU =R                  S-  sl        U R                  R                  [        R                  " 5       5        [        U R                  5      S:  a  U R                  S   U R                  S   -
  OSnU R                  S:X  d  X!R                  :  a  UR                  S:  a   [        R                  " UR                  5        [        R                  " U R                  5      nUSS  US S -
  n[        U5      UR                  :X  a  XAR                  S  Ul        [        eUS S  Ul        [        eg )Nr   rm   r>   r   )r  r  r  r   timer6   max_secsrx   r  r  remember_ntr   arraywarmuptimesStopIteration)r   r  
total_timer  r!  s        r   __next__TimerIter.__next__  s    

		Q	tyy{#14TWW1BTWWR[4771:-
99?j>>9xx1}))%*;*;<$''"BqrFRW$E5zUZZ'#LLN3   $Ah :r   )r  r  r  N)r   r   r   r   r   r$  r   r&   r   r   r  r    s    0 r   r  c                   V    \ rS rSrSrSSS\R                  4S jrS rS r	S	 r
S
 rSrg)RepeatTimeri  u  
This is yet another timer object. It is adapted to Faiss by
taking a number of openmp threads to set on input. It should be called
in an explicit loop as:

timer = RepeatTimer(warmup=1, nt=1, runs=6)

for _ in timer:
    # perform operation

print(f"time={timer.get_ms():.1f} ± {timer.get_ms_std():.1f} ms")

the same timer can be re-used. In that case it is reset each time it
enters a loop. It focuses on ms-scale times because for second scale
it's usually less relevant to repeat the operation.
r   r>   r   c                 v    X:  d   eXl         X l        X0l        X@l        [        R
                  " 5       U l        g r   )r   rx   r  r  r  omp_get_max_threadsr  )r   r   rx   r  r  s        r   r   RepeatTimer.__init__  s1    }}	  446r   c                     [        U 5      $ r   )r  r   s    r   __iter__RepeatTimer.__iter__  s    r   c                 H    [         R                  " U R                  5      S-  $ )N  )r   rN   r!  r   s    r   msRepeatTimer.ms  s    wwtzz"T))r   c                 ~    [        U R                  5      S:  a#  [        R                  " U R                  5      S-  $ S$ )Nr   r/  rI   )r6   r!  r   stdr   s    r   ms_stdRepeatTimer.ms_std  s.    ,/

Oa,?rvvdjj!D(HSHr   c                 ,    [        U R                  5      $ )zIeffective number of runs (may be lower than runs - warmup due to timeout))r6   r!  r   s    r   nrunsRepeatTimer.nruns  s    4::r   )r  rx   r  r  r   N)r   r   r   r   r   r   infr   r,  r0  r4  r7  r   r&   r   r   r'  r'    s0       BQ 7*Ir   r'  )rG   )rG   zref,new)gh㈵>)numpyr   r   r  r  multiprocessing.poolr   r   r"   rE   rC   r_   rb   r|   r   r   r   r   r   r  r'  r&   r   r   <module>r<     s        +
	&%P,\ %.	G\I,H:< <~D: D:T   2$ $r   