faiss 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/README.md +23 -21
  4. data/ext/faiss/extconf.rb +11 -0
  5. data/ext/faiss/index.cpp +4 -4
  6. data/ext/faiss/index_binary.cpp +6 -6
  7. data/ext/faiss/product_quantizer.cpp +4 -4
  8. data/lib/faiss/version.rb +1 -1
  9. data/vendor/faiss/faiss/AutoTune.cpp +13 -0
  10. data/vendor/faiss/faiss/IVFlib.cpp +101 -2
  11. data/vendor/faiss/faiss/IVFlib.h +26 -2
  12. data/vendor/faiss/faiss/Index.cpp +36 -3
  13. data/vendor/faiss/faiss/Index.h +43 -6
  14. data/vendor/faiss/faiss/Index2Layer.cpp +6 -2
  15. data/vendor/faiss/faiss/Index2Layer.h +6 -1
  16. data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +219 -16
  17. data/vendor/faiss/faiss/IndexAdditiveQuantizer.h +63 -5
  18. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +299 -0
  19. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.h +199 -0
  20. data/vendor/faiss/faiss/IndexBinary.cpp +20 -4
  21. data/vendor/faiss/faiss/IndexBinary.h +18 -3
  22. data/vendor/faiss/faiss/IndexBinaryFlat.cpp +9 -2
  23. data/vendor/faiss/faiss/IndexBinaryFlat.h +4 -2
  24. data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +4 -1
  25. data/vendor/faiss/faiss/IndexBinaryFromFloat.h +2 -1
  26. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +5 -1
  27. data/vendor/faiss/faiss/IndexBinaryHNSW.h +2 -1
  28. data/vendor/faiss/faiss/IndexBinaryHash.cpp +17 -4
  29. data/vendor/faiss/faiss/IndexBinaryHash.h +8 -4
  30. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +28 -13
  31. data/vendor/faiss/faiss/IndexBinaryIVF.h +10 -7
  32. data/vendor/faiss/faiss/IndexFastScan.cpp +626 -0
  33. data/vendor/faiss/faiss/IndexFastScan.h +145 -0
  34. data/vendor/faiss/faiss/IndexFlat.cpp +34 -21
  35. data/vendor/faiss/faiss/IndexFlat.h +7 -4
  36. data/vendor/faiss/faiss/IndexFlatCodes.cpp +35 -1
  37. data/vendor/faiss/faiss/IndexFlatCodes.h +12 -0
  38. data/vendor/faiss/faiss/IndexHNSW.cpp +66 -138
  39. data/vendor/faiss/faiss/IndexHNSW.h +4 -2
  40. data/vendor/faiss/faiss/IndexIDMap.cpp +247 -0
  41. data/vendor/faiss/faiss/IndexIDMap.h +107 -0
  42. data/vendor/faiss/faiss/IndexIVF.cpp +121 -33
  43. data/vendor/faiss/faiss/IndexIVF.h +35 -16
  44. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +84 -7
  45. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.h +63 -1
  46. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +590 -0
  47. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.h +171 -0
  48. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +1290 -0
  49. data/vendor/faiss/faiss/IndexIVFFastScan.h +213 -0
  50. data/vendor/faiss/faiss/IndexIVFFlat.cpp +37 -17
  51. data/vendor/faiss/faiss/IndexIVFFlat.h +4 -2
  52. data/vendor/faiss/faiss/IndexIVFPQ.cpp +234 -50
  53. data/vendor/faiss/faiss/IndexIVFPQ.h +5 -1
  54. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +23 -852
  55. data/vendor/faiss/faiss/IndexIVFPQFastScan.h +7 -112
  56. data/vendor/faiss/faiss/IndexIVFPQR.cpp +3 -3
  57. data/vendor/faiss/faiss/IndexIVFPQR.h +1 -1
  58. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +3 -1
  59. data/vendor/faiss/faiss/IndexIVFSpectralHash.h +2 -1
  60. data/vendor/faiss/faiss/IndexLSH.cpp +4 -2
  61. data/vendor/faiss/faiss/IndexLSH.h +2 -1
  62. data/vendor/faiss/faiss/IndexLattice.cpp +7 -1
  63. data/vendor/faiss/faiss/IndexLattice.h +3 -1
  64. data/vendor/faiss/faiss/IndexNNDescent.cpp +4 -3
  65. data/vendor/faiss/faiss/IndexNNDescent.h +2 -1
  66. data/vendor/faiss/faiss/IndexNSG.cpp +37 -3
  67. data/vendor/faiss/faiss/IndexNSG.h +25 -1
  68. data/vendor/faiss/faiss/IndexPQ.cpp +106 -69
  69. data/vendor/faiss/faiss/IndexPQ.h +19 -5
  70. data/vendor/faiss/faiss/IndexPQFastScan.cpp +15 -450
  71. data/vendor/faiss/faiss/IndexPQFastScan.h +15 -78
  72. data/vendor/faiss/faiss/IndexPreTransform.cpp +47 -8
  73. data/vendor/faiss/faiss/IndexPreTransform.h +15 -3
  74. data/vendor/faiss/faiss/IndexRefine.cpp +8 -4
  75. data/vendor/faiss/faiss/IndexRefine.h +4 -2
  76. data/vendor/faiss/faiss/IndexReplicas.cpp +4 -2
  77. data/vendor/faiss/faiss/IndexReplicas.h +2 -1
  78. data/vendor/faiss/faiss/IndexRowwiseMinMax.cpp +438 -0
  79. data/vendor/faiss/faiss/IndexRowwiseMinMax.h +92 -0
  80. data/vendor/faiss/faiss/IndexScalarQuantizer.cpp +26 -15
  81. data/vendor/faiss/faiss/IndexScalarQuantizer.h +6 -7
  82. data/vendor/faiss/faiss/IndexShards.cpp +4 -1
  83. data/vendor/faiss/faiss/IndexShards.h +2 -1
  84. data/vendor/faiss/faiss/MetaIndexes.cpp +5 -178
  85. data/vendor/faiss/faiss/MetaIndexes.h +3 -81
  86. data/vendor/faiss/faiss/VectorTransform.cpp +43 -0
  87. data/vendor/faiss/faiss/VectorTransform.h +22 -4
  88. data/vendor/faiss/faiss/clone_index.cpp +23 -1
  89. data/vendor/faiss/faiss/clone_index.h +3 -0
  90. data/vendor/faiss/faiss/cppcontrib/SaDecodeKernels.h +300 -0
  91. data/vendor/faiss/faiss/cppcontrib/detail/CoarseBitType.h +24 -0
  92. data/vendor/faiss/faiss/cppcontrib/detail/UintReader.h +195 -0
  93. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-avx2-inl.h +2058 -0
  94. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-inl.h +408 -0
  95. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-neon-inl.h +2147 -0
  96. data/vendor/faiss/faiss/cppcontrib/sa_decode/MinMax-inl.h +460 -0
  97. data/vendor/faiss/faiss/cppcontrib/sa_decode/MinMaxFP16-inl.h +465 -0
  98. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-avx2-inl.h +1618 -0
  99. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-inl.h +251 -0
  100. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-neon-inl.h +1452 -0
  101. data/vendor/faiss/faiss/gpu/GpuAutoTune.cpp +1 -0
  102. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +0 -4
  103. data/vendor/faiss/faiss/gpu/GpuIndex.h +28 -4
  104. data/vendor/faiss/faiss/gpu/GpuIndexBinaryFlat.h +2 -1
  105. data/vendor/faiss/faiss/gpu/GpuIndexFlat.h +10 -8
  106. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +75 -14
  107. data/vendor/faiss/faiss/gpu/GpuIndexIVFFlat.h +19 -32
  108. data/vendor/faiss/faiss/gpu/GpuIndexIVFPQ.h +22 -31
  109. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +22 -28
  110. data/vendor/faiss/faiss/gpu/GpuResources.cpp +14 -0
  111. data/vendor/faiss/faiss/gpu/GpuResources.h +16 -3
  112. data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +3 -3
  113. data/vendor/faiss/faiss/gpu/impl/IndexUtils.h +32 -0
  114. data/vendor/faiss/faiss/gpu/test/TestGpuIndexBinaryFlat.cpp +1 -0
  115. data/vendor/faiss/faiss/gpu/test/TestGpuIndexFlat.cpp +311 -75
  116. data/vendor/faiss/faiss/gpu/test/TestUtils.cpp +10 -0
  117. data/vendor/faiss/faiss/gpu/test/TestUtils.h +3 -0
  118. data/vendor/faiss/faiss/gpu/test/demo_ivfpq_indexing_gpu.cpp +2 -2
  119. data/vendor/faiss/faiss/gpu/utils/DeviceUtils.h +5 -4
  120. data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +116 -47
  121. data/vendor/faiss/faiss/impl/AdditiveQuantizer.h +44 -13
  122. data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +0 -54
  123. data/vendor/faiss/faiss/impl/AuxIndexStructures.h +0 -76
  124. data/vendor/faiss/faiss/impl/DistanceComputer.h +64 -0
  125. data/vendor/faiss/faiss/impl/HNSW.cpp +123 -27
  126. data/vendor/faiss/faiss/impl/HNSW.h +19 -16
  127. data/vendor/faiss/faiss/impl/IDSelector.cpp +125 -0
  128. data/vendor/faiss/faiss/impl/IDSelector.h +135 -0
  129. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +6 -28
  130. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.h +6 -1
  131. data/vendor/faiss/faiss/impl/LookupTableScaler.h +77 -0
  132. data/vendor/faiss/faiss/impl/NNDescent.cpp +1 -0
  133. data/vendor/faiss/faiss/impl/NSG.cpp +1 -1
  134. data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.cpp +383 -0
  135. data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.h +154 -0
  136. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +225 -145
  137. data/vendor/faiss/faiss/impl/ProductQuantizer.h +29 -10
  138. data/vendor/faiss/faiss/impl/Quantizer.h +43 -0
  139. data/vendor/faiss/faiss/impl/ResidualQuantizer.cpp +192 -36
  140. data/vendor/faiss/faiss/impl/ResidualQuantizer.h +40 -20
  141. data/vendor/faiss/faiss/impl/ResultHandler.h +96 -0
  142. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +97 -173
  143. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +18 -18
  144. data/vendor/faiss/faiss/impl/index_read.cpp +240 -9
  145. data/vendor/faiss/faiss/impl/index_write.cpp +237 -5
  146. data/vendor/faiss/faiss/impl/kmeans1d.cpp +6 -4
  147. data/vendor/faiss/faiss/impl/pq4_fast_scan.cpp +56 -16
  148. data/vendor/faiss/faiss/impl/pq4_fast_scan.h +25 -8
  149. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_1.cpp +66 -25
  150. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_qbs.cpp +75 -27
  151. data/vendor/faiss/faiss/index_factory.cpp +196 -7
  152. data/vendor/faiss/faiss/index_io.h +5 -0
  153. data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -0
  154. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +4 -1
  155. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +2 -1
  156. data/vendor/faiss/faiss/python/python_callbacks.cpp +27 -0
  157. data/vendor/faiss/faiss/python/python_callbacks.h +15 -0
  158. data/vendor/faiss/faiss/utils/Heap.h +31 -15
  159. data/vendor/faiss/faiss/utils/distances.cpp +380 -56
  160. data/vendor/faiss/faiss/utils/distances.h +113 -15
  161. data/vendor/faiss/faiss/utils/distances_simd.cpp +726 -6
  162. data/vendor/faiss/faiss/utils/extra_distances.cpp +12 -7
  163. data/vendor/faiss/faiss/utils/extra_distances.h +3 -1
  164. data/vendor/faiss/faiss/utils/fp16-fp16c.h +21 -0
  165. data/vendor/faiss/faiss/utils/fp16-inl.h +101 -0
  166. data/vendor/faiss/faiss/utils/fp16.h +11 -0
  167. data/vendor/faiss/faiss/utils/hamming-inl.h +54 -0
  168. data/vendor/faiss/faiss/utils/hamming.cpp +0 -48
  169. data/vendor/faiss/faiss/utils/ordered_key_value.h +10 -0
  170. data/vendor/faiss/faiss/utils/quantize_lut.cpp +62 -0
  171. data/vendor/faiss/faiss/utils/quantize_lut.h +20 -0
  172. data/vendor/faiss/faiss/utils/random.cpp +53 -0
  173. data/vendor/faiss/faiss/utils/random.h +5 -0
  174. data/vendor/faiss/faiss/utils/simdlib_avx2.h +4 -0
  175. data/vendor/faiss/faiss/utils/simdlib_emulated.h +6 -1
  176. data/vendor/faiss/faiss/utils/simdlib_neon.h +7 -2
  177. metadata +37 -3
@@ -26,10 +26,12 @@
26
26
 
27
27
  #include <faiss/Index2Layer.h>
28
28
  #include <faiss/IndexAdditiveQuantizer.h>
29
+ #include <faiss/IndexAdditiveQuantizerFastScan.h>
29
30
  #include <faiss/IndexFlat.h>
30
31
  #include <faiss/IndexHNSW.h>
31
32
  #include <faiss/IndexIVF.h>
32
33
  #include <faiss/IndexIVFAdditiveQuantizer.h>
34
+ #include <faiss/IndexIVFAdditiveQuantizerFastScan.h>
33
35
  #include <faiss/IndexIVFFlat.h>
34
36
  #include <faiss/IndexIVFPQ.h>
35
37
  #include <faiss/IndexIVFPQFastScan.h>
@@ -42,6 +44,7 @@
42
44
  #include <faiss/IndexPQFastScan.h>
43
45
  #include <faiss/IndexPreTransform.h>
44
46
  #include <faiss/IndexRefine.h>
47
+ #include <faiss/IndexRowwiseMinMax.h>
45
48
  #include <faiss/IndexScalarQuantizer.h>
46
49
  #include <faiss/MetaIndexes.h>
47
50
  #include <faiss/VectorTransform.h>
@@ -149,11 +152,15 @@ std::map<std::string, AdditiveQuantizer::Search_type_t> aq_search_type = {
149
152
  {"_Nqint4", AdditiveQuantizer::ST_norm_qint4},
150
153
  {"_Ncqint8", AdditiveQuantizer::ST_norm_cqint8},
151
154
  {"_Ncqint4", AdditiveQuantizer::ST_norm_cqint4},
155
+ {"_Nlsq2x4", AdditiveQuantizer::ST_norm_lsq2x4},
156
+ {"_Nrq2x4", AdditiveQuantizer::ST_norm_rq2x4},
152
157
  };
153
158
 
154
159
  const std::string aq_def_pattern = "[0-9]+x[0-9]+(_[0-9]+x[0-9]+)*";
155
160
  const std::string aq_norm_pattern =
156
- "(|_Nnone|_Nfloat|_Nqint8|_Nqint4|_Ncqint8|_Ncqint4)";
161
+ "(|_Nnone|_Nfloat|_Nqint8|_Nqint4|_Ncqint8|_Ncqint4|_Nlsq2x4|_Nrq2x4)";
162
+
163
+ const std::string paq_def_pattern = "([0-9]+)x([0-9]+)x([0-9]+)";
157
164
 
158
165
  AdditiveQuantizer::Search_type_t aq_parse_search_type(
159
166
  std::string stok,
@@ -169,7 +176,7 @@ AdditiveQuantizer::Search_type_t aq_parse_search_type(
169
176
  std::vector<size_t> aq_parse_nbits(std::string stok) {
170
177
  std::vector<size_t> nbits;
171
178
  std::smatch sm;
172
- while (std::regex_search(stok, sm, std::regex("([0-9]+)x([0-9]+)"))) {
179
+ while (std::regex_search(stok, sm, std::regex("[^q]([0-9]+)x([0-9]+)"))) {
173
180
  int M = std::stoi(sm[1].str());
174
181
  int nbit = std::stoi(sm[2].str());
175
182
  nbits.resize(nbits.size() + M, nbit);
@@ -341,6 +348,53 @@ IndexIVF* parse_IndexIVF(
341
348
  }
342
349
  return index_ivf;
343
350
  }
351
+ if (match("(PRQ|PLSQ)" + paq_def_pattern + aq_norm_pattern)) {
352
+ int nsplits = mres_to_int(sm[2]);
353
+ int Msub = mres_to_int(sm[3]);
354
+ int nbit = mres_to_int(sm[4]);
355
+ auto st = aq_parse_search_type(sm[sm.size() - 1].str(), mt);
356
+ IndexIVF* index_ivf;
357
+ if (sm[1].str() == "PRQ") {
358
+ index_ivf = new IndexIVFProductResidualQuantizer(
359
+ get_q(), d, nlist, nsplits, Msub, nbit, mt, st);
360
+ } else {
361
+ index_ivf = new IndexIVFProductLocalSearchQuantizer(
362
+ get_q(), d, nlist, nsplits, Msub, nbit, mt, st);
363
+ }
364
+ return index_ivf;
365
+ }
366
+ if (match("(RQ|LSQ)([0-9]+)x4fs(r?)(_[0-9]+)?" + aq_norm_pattern)) {
367
+ int M = std::stoi(sm[2].str());
368
+ int bbs = mres_to_int(sm[4], 32, 1);
369
+ auto st = aq_parse_search_type(sm[sm.size() - 1].str(), mt);
370
+ IndexIVFAdditiveQuantizerFastScan* index_ivf;
371
+ if (sm[1].str() == "RQ") {
372
+ index_ivf = new IndexIVFResidualQuantizerFastScan(
373
+ get_q(), d, nlist, M, 4, mt, st, bbs);
374
+ } else {
375
+ index_ivf = new IndexIVFLocalSearchQuantizerFastScan(
376
+ get_q(), d, nlist, M, 4, mt, st, bbs);
377
+ }
378
+ index_ivf->by_residual = (sm[3].str() == "r");
379
+ return index_ivf;
380
+ }
381
+ if (match("(PRQ|PLSQ)([0-9]+)x([0-9]+)x4fs(r?)(_[0-9]+)?" +
382
+ aq_norm_pattern)) {
383
+ int nsplits = std::stoi(sm[2].str());
384
+ int Msub = std::stoi(sm[3].str());
385
+ int bbs = mres_to_int(sm[5], 32, 1);
386
+ auto st = aq_parse_search_type(sm[sm.size() - 1].str(), mt);
387
+ IndexIVFAdditiveQuantizerFastScan* index_ivf;
388
+ if (sm[1].str() == "PRQ") {
389
+ index_ivf = new IndexIVFProductResidualQuantizerFastScan(
390
+ get_q(), d, nlist, nsplits, Msub, 4, mt, st, bbs);
391
+ } else {
392
+ index_ivf = new IndexIVFProductLocalSearchQuantizerFastScan(
393
+ get_q(), d, nlist, nsplits, Msub, 4, mt, st, bbs);
394
+ }
395
+ index_ivf->by_residual = (sm[4].str() == "r");
396
+ return index_ivf;
397
+ }
344
398
  if (match("(ITQ|PCA|PCAR)([0-9]+)?,SH([-0-9.e]+)?([gcm])?")) {
345
399
  int outdim = mres_to_int(sm[2], d); // is also the number of bits
346
400
  std::unique_ptr<VectorTransform> vt;
@@ -421,6 +475,37 @@ IndexHNSW* parse_IndexHNSW(
421
475
  return nullptr;
422
476
  }
423
477
 
478
+ /***************************************************************
479
+ * Parse IndexNSG
480
+ */
481
+
482
+ IndexNSG* parse_IndexNSG(
483
+ const std::string code_string,
484
+ int d,
485
+ MetricType mt,
486
+ int nsg_R) {
487
+ std::smatch sm;
488
+ auto match = [&sm, &code_string](const std::string& pattern) {
489
+ return re_match(code_string, pattern, sm);
490
+ };
491
+
492
+ if (match("Flat|")) {
493
+ return new IndexNSGFlat(d, nsg_R, mt);
494
+ }
495
+ if (match("PQ([0-9]+)(np)?")) {
496
+ int M = std::stoi(sm[1].str());
497
+ IndexNSGPQ* ipq = new IndexNSGPQ(d, M, nsg_R);
498
+ dynamic_cast<IndexPQ*>(ipq->storage)->do_polysemous_training =
499
+ sm[2].str() != "np";
500
+ return ipq;
501
+ }
502
+ if (match(sq_pattern)) {
503
+ return new IndexNSGSQ(d, sq_types[sm[1].str()], nsg_R, mt);
504
+ }
505
+
506
+ return nullptr;
507
+ }
508
+
424
509
  /***************************************************************
425
510
  * Parse basic indexes
426
511
  */
@@ -454,11 +539,6 @@ Index* parse_other_indexes(
454
539
  return new IndexLattice(d, M, nbit, r2);
455
540
  }
456
541
 
457
- // IndexNSGFlat
458
- if (match("NSG([0-9]+)(,Flat)?")) {
459
- return new IndexNSGFlat(d, std::stoi(sm[1].str()), metric);
460
- }
461
-
462
542
  // IndexScalarQuantizer
463
543
  if (match(sq_pattern)) {
464
544
  return new IndexScalarQuantizer(d, sq_types[description], metric);
@@ -505,6 +585,60 @@ Index* parse_other_indexes(
505
585
  return new IndexLocalSearchQuantizer(d, M, nbit, metric, st);
506
586
  }
507
587
 
588
+ // IndexProductResidualQuantizer
589
+ if (match("PRQ" + paq_def_pattern + aq_norm_pattern)) {
590
+ int nsplits = mres_to_int(sm[1]);
591
+ int Msub = mres_to_int(sm[2]);
592
+ int nbit = mres_to_int(sm[3]);
593
+ auto st = aq_parse_search_type(sm[sm.size() - 1].str(), metric);
594
+ return new IndexProductResidualQuantizer(
595
+ d, nsplits, Msub, nbit, metric, st);
596
+ }
597
+
598
+ // IndexProductLocalSearchQuantizer
599
+ if (match("PLSQ" + paq_def_pattern + aq_norm_pattern)) {
600
+ int nsplits = mres_to_int(sm[1]);
601
+ int Msub = mres_to_int(sm[2]);
602
+ int nbit = mres_to_int(sm[3]);
603
+ auto st = aq_parse_search_type(sm[sm.size() - 1].str(), metric);
604
+ return new IndexProductLocalSearchQuantizer(
605
+ d, nsplits, Msub, nbit, metric, st);
606
+ }
607
+
608
+ // IndexAdditiveQuantizerFastScan
609
+ // RQ{M}x4fs_{bbs}_{search_type}
610
+ pattern = "(LSQ|RQ)([0-9]+)x4fs(_[0-9]+)?" + aq_norm_pattern;
611
+ if (match(pattern)) {
612
+ int M = std::stoi(sm[2].str());
613
+ int bbs = mres_to_int(sm[3], 32, 1);
614
+ auto st = aq_parse_search_type(sm[sm.size() - 1].str(), metric);
615
+
616
+ if (sm[1].str() == "RQ") {
617
+ return new IndexResidualQuantizerFastScan(d, M, 4, metric, st, bbs);
618
+ } else if (sm[1].str() == "LSQ") {
619
+ return new IndexLocalSearchQuantizerFastScan(
620
+ d, M, 4, metric, st, bbs);
621
+ }
622
+ }
623
+
624
+ // IndexProductAdditiveQuantizerFastScan
625
+ // PRQ{nsplits}x{Msub}x4fs_{bbs}_{search_type}
626
+ pattern = "(PLSQ|PRQ)([0-9]+)x([0-9]+)x4fs(_[0-9]+)?" + aq_norm_pattern;
627
+ if (match(pattern)) {
628
+ int nsplits = std::stoi(sm[2].str());
629
+ int Msub = std::stoi(sm[3].str());
630
+ int bbs = mres_to_int(sm[4], 32, 1);
631
+ auto st = aq_parse_search_type(sm[sm.size() - 1].str(), metric);
632
+
633
+ if (sm[1].str() == "PRQ") {
634
+ return new IndexProductResidualQuantizerFastScan(
635
+ d, nsplits, Msub, 4, metric, st, bbs);
636
+ } else if (sm[1].str() == "PLSQ") {
637
+ return new IndexProductLocalSearchQuantizerFastScan(
638
+ d, nsplits, Msub, 4, metric, st, bbs);
639
+ }
640
+ }
641
+
508
642
  return nullptr;
509
643
  }
510
644
 
@@ -604,6 +738,14 @@ std::unique_ptr<Index> index_factory_sub(
604
738
 
605
739
  // IndexIDMap -- it turns out is was used both as a prefix and a suffix, so
606
740
  // support both
741
+ if (re_match(description, "(.+),IDMap2", sm) ||
742
+ re_match(description, "IDMap2,(.+)", sm)) {
743
+ IndexIDMap2* idmap2 = new IndexIDMap2(
744
+ index_factory_sub(d, sm[1].str(), metric).release());
745
+ idmap2->own_fields = true;
746
+ return std::unique_ptr<Index>(idmap2);
747
+ }
748
+
607
749
  if (re_match(description, "(.+),IDMap", sm) ||
608
750
  re_match(description, "IDMap,(.+)", sm)) {
609
751
  IndexIDMap* idmap = new IndexIDMap(
@@ -642,6 +784,53 @@ std::unique_ptr<Index> index_factory_sub(
642
784
  return std::unique_ptr<Index>(index);
643
785
  }
644
786
 
787
+ // NSG variants (it was unclear in the old version that the separator was a
788
+ // "," so we support both "_" and ",")
789
+ if (re_match(description, "NSG([0-9]*)([,_].*)?", sm)) {
790
+ int nsg_R = mres_to_int(sm[1], 32);
791
+ // We also accept empty code string (synonym of Flat)
792
+ std::string code_string =
793
+ sm[2].length() > 0 ? sm[2].str().substr(1) : "";
794
+ if (verbose) {
795
+ printf("parsing NSG string %s code_string=%s nsg_R=%d\n",
796
+ description.c_str(),
797
+ code_string.c_str(),
798
+ nsg_R);
799
+ }
800
+
801
+ IndexNSG* index = parse_IndexNSG(code_string, d, metric, nsg_R);
802
+ FAISS_THROW_IF_NOT_FMT(
803
+ index,
804
+ "could not parse NSG code description %s in %s",
805
+ code_string.c_str(),
806
+ description.c_str());
807
+ return std::unique_ptr<Index>(index);
808
+ }
809
+
810
+ // IndexRowwiseMinMax, fp32 version
811
+ if (description.compare(0, 7, "MinMax,") == 0) {
812
+ size_t comma = description.find(",");
813
+ std::string sub_index_string = description.substr(comma + 1);
814
+ auto sub_index = index_factory_sub(d, sub_index_string, metric);
815
+
816
+ auto index = new IndexRowwiseMinMax(sub_index.release());
817
+ index->own_fields = true;
818
+
819
+ return std::unique_ptr<Index>(index);
820
+ }
821
+
822
+ // IndexRowwiseMinMax, fp16 version
823
+ if (description.compare(0, 11, "MinMaxFP16,") == 0) {
824
+ size_t comma = description.find(",");
825
+ std::string sub_index_string = description.substr(comma + 1);
826
+ auto sub_index = index_factory_sub(d, sub_index_string, metric);
827
+
828
+ auto index = new IndexRowwiseMinMaxFP16(sub_index.release());
829
+ index->own_fields = true;
830
+
831
+ return std::unique_ptr<Index>(index);
832
+ }
833
+
645
834
  // IndexIVF
646
835
  {
647
836
  size_t nlist;
@@ -50,6 +50,8 @@ const int IO_FLAG_READ_ONLY = 2;
50
50
  const int IO_FLAG_ONDISK_SAME_DIR = 4;
51
51
  // don't load IVF data to RAM, only list sizes
52
52
  const int IO_FLAG_SKIP_IVF_DATA = 8;
53
+ // don't initialize precomputed table after loading
54
+ const int IO_FLAG_SKIP_PRECOMPUTE_TABLE = 16;
53
55
  // try to memmap data (useful to load an ArrayInvertedLists as an
54
56
  // OnDiskInvertedLists)
55
57
  const int IO_FLAG_MMAP = IO_FLAG_SKIP_IVF_DATA | 0x646f0000;
@@ -63,7 +65,10 @@ IndexBinary* read_index_binary(FILE* f, int io_flags = 0);
63
65
  IndexBinary* read_index_binary(IOReader* reader, int io_flags = 0);
64
66
 
65
67
  void write_VectorTransform(const VectorTransform* vt, const char* fname);
68
+ void write_VectorTransform(const VectorTransform* vt, IOWriter* f);
69
+
66
70
  VectorTransform* read_VectorTransform(const char* fname);
71
+ VectorTransform* read_VectorTransform(IOReader* f);
67
72
 
68
73
  ProductQuantizer* read_ProductQuantizer(const char* fname);
69
74
  ProductQuantizer* read_ProductQuantizer(IOReader* reader);
@@ -14,6 +14,7 @@
14
14
 
15
15
  #include <faiss/impl/AuxIndexStructures.h>
16
16
  #include <faiss/impl/FaissAssert.h>
17
+ #include <faiss/impl/IDSelector.h>
17
18
 
18
19
  namespace faiss {
19
20
 
@@ -28,7 +28,10 @@ InvertedLists::~InvertedLists() {}
28
28
  InvertedLists::idx_t InvertedLists::get_single_id(size_t list_no, size_t offset)
29
29
  const {
30
30
  assert(offset < list_size(list_no));
31
- return get_ids(list_no)[offset];
31
+ const idx_t* ids = get_ids(list_no);
32
+ idx_t id = ids[offset];
33
+ release_ids(list_no, ids);
34
+ return id;
32
35
  }
33
36
 
34
37
  void InvertedLists::release_codes(size_t, const uint8_t*) const {}
@@ -278,13 +278,14 @@ void OnDiskInvertedLists::do_mmap() {
278
278
  uint8_t* ptro =
279
279
  (uint8_t*)mmap(nullptr, totsize, prot, MAP_SHARED, fileno(f), 0);
280
280
 
281
+ fclose(f);
282
+
281
283
  FAISS_THROW_IF_NOT_FMT(
282
284
  ptro != MAP_FAILED,
283
285
  "could not mmap %s: %s",
284
286
  filename.c_str(),
285
287
  strerror(errno));
286
288
  ptr = ptro;
287
- fclose(f);
288
289
  }
289
290
 
290
291
  void OnDiskInvertedLists::update_totsize(size_t new_size) {
@@ -107,3 +107,30 @@ PyCallbackIOReader::~PyCallbackIOReader() {
107
107
  PyThreadLock gil;
108
108
  Py_DECREF(callback);
109
109
  }
110
+
111
+ /***********************************************************
112
+ * Callbacks for IDSelector
113
+ ***********************************************************/
114
+
115
+ PyCallbackIDSelector::PyCallbackIDSelector(PyObject* callback)
116
+ : callback(callback) {
117
+ PyThreadLock gil;
118
+ Py_INCREF(callback);
119
+ }
120
+
121
+ bool PyCallbackIDSelector::is_member(idx_t id) const {
122
+ FAISS_THROW_IF_NOT((id >> 32) == 0);
123
+ PyThreadLock gil;
124
+ PyObject* result = PyObject_CallFunction(callback, "(n)", int(id));
125
+ if (result == NULL) {
126
+ FAISS_THROW_MSG("propagate py error");
127
+ }
128
+ bool b = PyObject_IsTrue(result);
129
+ Py_DECREF(result);
130
+ return b;
131
+ }
132
+
133
+ PyCallbackIDSelector::~PyCallbackIDSelector() {
134
+ PyThreadLock gil;
135
+ Py_DECREF(callback);
136
+ }
@@ -7,6 +7,7 @@
7
7
 
8
8
  #pragma once
9
9
 
10
+ #include <faiss/impl/IDSelector.h>
10
11
  #include <faiss/impl/io.h>
11
12
  #include <faiss/invlists/InvertedLists.h>
12
13
  #include "Python.h"
@@ -43,3 +44,17 @@ struct PyCallbackIOReader : faiss::IOReader {
43
44
 
44
45
  ~PyCallbackIOReader() override;
45
46
  };
47
+
48
+ /***********************************************************
49
+ * Callbacks for IDSelector
50
+ ***********************************************************/
51
+
52
+ struct PyCallbackIDSelector : faiss::IDSelector {
53
+ PyObject* callback;
54
+
55
+ explicit PyCallbackIDSelector(PyObject* callback);
56
+
57
+ bool is_member(idx_t id) const override;
58
+
59
+ ~PyCallbackIDSelector() override;
60
+ };
@@ -47,21 +47,25 @@ inline void heap_pop(size_t k, typename C::T* bh_val, typename C::TI* bh_ids) {
47
47
  bh_val--; /* Use 1-based indexing for easier node->child translation */
48
48
  bh_ids--;
49
49
  typename C::T val = bh_val[k];
50
+ typename C::TI id = bh_ids[k];
50
51
  size_t i = 1, i1, i2;
51
52
  while (1) {
52
53
  i1 = i << 1;
53
54
  i2 = i1 + 1;
54
55
  if (i1 > k)
55
56
  break;
56
- if (i2 == k + 1 || C::cmp(bh_val[i1], bh_val[i2])) {
57
- if (C::cmp(val, bh_val[i1]))
57
+ if ((i2 == k + 1) ||
58
+ C::cmp2(bh_val[i1], bh_val[i2], bh_ids[i1], bh_ids[i2])) {
59
+ if (C::cmp2(val, bh_val[i1], id, bh_ids[i1])) {
58
60
  break;
61
+ }
59
62
  bh_val[i] = bh_val[i1];
60
63
  bh_ids[i] = bh_ids[i1];
61
64
  i = i1;
62
65
  } else {
63
- if (C::cmp(val, bh_val[i2]))
66
+ if (C::cmp2(val, bh_val[i2], id, bh_ids[i2])) {
64
67
  break;
68
+ }
65
69
  bh_val[i] = bh_val[i2];
66
70
  bh_ids[i] = bh_ids[i2];
67
71
  i = i2;
@@ -80,24 +84,28 @@ inline void heap_push(
80
84
  typename C::T* bh_val,
81
85
  typename C::TI* bh_ids,
82
86
  typename C::T val,
83
- typename C::TI ids) {
87
+ typename C::TI id) {
84
88
  bh_val--; /* Use 1-based indexing for easier node->child translation */
85
89
  bh_ids--;
86
90
  size_t i = k, i_father;
87
91
  while (i > 1) {
88
92
  i_father = i >> 1;
89
- if (!C::cmp(val, bh_val[i_father])) /* the heap structure is ok */
93
+ if (!C::cmp2(val, bh_val[i_father], id, bh_ids[i_father])) {
94
+ /* the heap structure is ok */
90
95
  break;
96
+ }
91
97
  bh_val[i] = bh_val[i_father];
92
98
  bh_ids[i] = bh_ids[i_father];
93
99
  i = i_father;
94
100
  }
95
101
  bh_val[i] = val;
96
- bh_ids[i] = ids;
102
+ bh_ids[i] = id;
97
103
  }
98
104
 
99
- /** Replace the top element from the heap defined by bh_val[0..k-1] and
100
- * bh_ids[0..k-1].
105
+ /**
106
+ * Replaces the top element from the heap defined by bh_val[0..k-1] and
107
+ * bh_ids[0..k-1], and for identical bh_val[] values also sorts by bh_ids[]
108
+ * values.
101
109
  */
102
110
  template <class C>
103
111
  inline void heap_replace_top(
@@ -105,31 +113,39 @@ inline void heap_replace_top(
105
113
  typename C::T* bh_val,
106
114
  typename C::TI* bh_ids,
107
115
  typename C::T val,
108
- typename C::TI ids) {
116
+ typename C::TI id) {
109
117
  bh_val--; /* Use 1-based indexing for easier node->child translation */
110
118
  bh_ids--;
111
119
  size_t i = 1, i1, i2;
112
120
  while (1) {
113
121
  i1 = i << 1;
114
122
  i2 = i1 + 1;
115
- if (i1 > k)
123
+ if (i1 > k) {
116
124
  break;
117
- if (i2 == k + 1 || C::cmp(bh_val[i1], bh_val[i2])) {
118
- if (C::cmp(val, bh_val[i1]))
125
+ }
126
+
127
+ // Note that C::cmp2() is a bool function answering
128
+ // `(a1 > b1) || ((a1 == b1) && (a2 > b2))` for max
129
+ // heap and same with the `<` sign for min heap.
130
+ if ((i2 == k + 1) ||
131
+ C::cmp2(bh_val[i1], bh_val[i2], bh_ids[i1], bh_ids[i2])) {
132
+ if (C::cmp2(val, bh_val[i1], id, bh_ids[i1])) {
119
133
  break;
134
+ }
120
135
  bh_val[i] = bh_val[i1];
121
136
  bh_ids[i] = bh_ids[i1];
122
137
  i = i1;
123
138
  } else {
124
- if (C::cmp(val, bh_val[i2]))
139
+ if (C::cmp2(val, bh_val[i2], id, bh_ids[i2])) {
125
140
  break;
141
+ }
126
142
  bh_val[i] = bh_val[i2];
127
143
  bh_ids[i] = bh_ids[i2];
128
144
  i = i2;
129
145
  }
130
146
  }
131
147
  bh_val[i] = val;
132
- bh_ids[i] = ids;
148
+ bh_ids[i] = id;
133
149
  }
134
150
 
135
151
  /* Partial instanciation for heaps with TI = int64_t */
@@ -294,7 +310,7 @@ inline void maxheap_addn(
294
310
  * Heap finalization (reorder elements)
295
311
  *******************************************************************/
296
312
 
297
- /* This function maps a binary heap into an sorted structure.
313
+ /* This function maps a binary heap into a sorted structure.
298
314
  It returns the number */
299
315
  template <typename C>
300
316
  inline size_t heap_reorder(