faiss 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/LICENSE.txt +18 -18
  4. data/README.md +1 -1
  5. data/lib/faiss/version.rb +1 -1
  6. data/vendor/faiss/Clustering.cpp +318 -53
  7. data/vendor/faiss/Clustering.h +39 -11
  8. data/vendor/faiss/DirectMap.cpp +267 -0
  9. data/vendor/faiss/DirectMap.h +120 -0
  10. data/vendor/faiss/IVFlib.cpp +24 -4
  11. data/vendor/faiss/IVFlib.h +4 -0
  12. data/vendor/faiss/Index.h +5 -24
  13. data/vendor/faiss/Index2Layer.cpp +0 -1
  14. data/vendor/faiss/IndexBinary.h +7 -3
  15. data/vendor/faiss/IndexBinaryFlat.cpp +5 -0
  16. data/vendor/faiss/IndexBinaryFlat.h +3 -0
  17. data/vendor/faiss/IndexBinaryHash.cpp +492 -0
  18. data/vendor/faiss/IndexBinaryHash.h +116 -0
  19. data/vendor/faiss/IndexBinaryIVF.cpp +160 -107
  20. data/vendor/faiss/IndexBinaryIVF.h +14 -4
  21. data/vendor/faiss/IndexFlat.h +2 -1
  22. data/vendor/faiss/IndexHNSW.cpp +68 -16
  23. data/vendor/faiss/IndexHNSW.h +3 -3
  24. data/vendor/faiss/IndexIVF.cpp +72 -76
  25. data/vendor/faiss/IndexIVF.h +24 -5
  26. data/vendor/faiss/IndexIVFFlat.cpp +19 -54
  27. data/vendor/faiss/IndexIVFFlat.h +1 -11
  28. data/vendor/faiss/IndexIVFPQ.cpp +49 -26
  29. data/vendor/faiss/IndexIVFPQ.h +9 -10
  30. data/vendor/faiss/IndexIVFPQR.cpp +2 -2
  31. data/vendor/faiss/IndexIVFSpectralHash.cpp +2 -2
  32. data/vendor/faiss/IndexLSH.h +4 -1
  33. data/vendor/faiss/IndexPreTransform.cpp +0 -1
  34. data/vendor/faiss/IndexScalarQuantizer.cpp +8 -1
  35. data/vendor/faiss/InvertedLists.cpp +0 -2
  36. data/vendor/faiss/MetaIndexes.cpp +0 -1
  37. data/vendor/faiss/MetricType.h +36 -0
  38. data/vendor/faiss/c_api/Clustering_c.cpp +13 -7
  39. data/vendor/faiss/c_api/Clustering_c.h +11 -5
  40. data/vendor/faiss/c_api/IndexIVF_c.cpp +7 -0
  41. data/vendor/faiss/c_api/IndexIVF_c.h +7 -0
  42. data/vendor/faiss/c_api/IndexPreTransform_c.cpp +21 -0
  43. data/vendor/faiss/c_api/IndexPreTransform_c.h +32 -0
  44. data/vendor/faiss/demos/demo_weighted_kmeans.cpp +185 -0
  45. data/vendor/faiss/gpu/GpuCloner.cpp +4 -0
  46. data/vendor/faiss/gpu/GpuClonerOptions.cpp +1 -1
  47. data/vendor/faiss/gpu/GpuDistance.h +93 -0
  48. data/vendor/faiss/gpu/GpuIndex.h +7 -0
  49. data/vendor/faiss/gpu/GpuIndexFlat.h +0 -10
  50. data/vendor/faiss/gpu/GpuIndexIVF.h +1 -0
  51. data/vendor/faiss/gpu/StandardGpuResources.cpp +8 -0
  52. data/vendor/faiss/gpu/test/TestGpuIndexFlat.cpp +49 -27
  53. data/vendor/faiss/gpu/test/TestGpuIndexIVFPQ.cpp +110 -2
  54. data/vendor/faiss/gpu/utils/DeviceUtils.h +6 -0
  55. data/vendor/faiss/impl/AuxIndexStructures.cpp +17 -0
  56. data/vendor/faiss/impl/AuxIndexStructures.h +14 -3
  57. data/vendor/faiss/impl/HNSW.cpp +0 -1
  58. data/vendor/faiss/impl/PolysemousTraining.h +5 -5
  59. data/vendor/faiss/impl/ProductQuantizer-inl.h +138 -0
  60. data/vendor/faiss/impl/ProductQuantizer.cpp +1 -113
  61. data/vendor/faiss/impl/ProductQuantizer.h +42 -47
  62. data/vendor/faiss/impl/index_read.cpp +103 -7
  63. data/vendor/faiss/impl/index_write.cpp +101 -5
  64. data/vendor/faiss/impl/io.cpp +111 -1
  65. data/vendor/faiss/impl/io.h +38 -0
  66. data/vendor/faiss/index_factory.cpp +0 -1
  67. data/vendor/faiss/tests/test_merge.cpp +0 -1
  68. data/vendor/faiss/tests/test_pq_encoding.cpp +6 -6
  69. data/vendor/faiss/tutorial/cpp/5-Multiple-GPUs.cpp +1 -0
  70. data/vendor/faiss/utils/distances.cpp +4 -5
  71. data/vendor/faiss/utils/distances_simd.cpp +0 -1
  72. data/vendor/faiss/utils/hamming.cpp +85 -3
  73. data/vendor/faiss/utils/hamming.h +20 -0
  74. data/vendor/faiss/utils/utils.cpp +0 -96
  75. data/vendor/faiss/utils/utils.h +0 -15
  76. metadata +11 -3
  77. data/lib/faiss/ext.bundle +0 -0
@@ -12,10 +12,12 @@
12
12
 
13
13
 
14
14
  #include <vector>
15
+ #include <unordered_map>
15
16
  #include <stdint.h>
16
17
 
17
18
  #include <faiss/Index.h>
18
19
  #include <faiss/InvertedLists.h>
20
+ #include <faiss/DirectMap.h>
19
21
  #include <faiss/Clustering.h>
20
22
  #include <faiss/utils/Heap.h>
21
23
 
@@ -32,7 +34,6 @@ struct Level1Quantizer {
32
34
  Index * quantizer; ///< quantizer that maps vectors to inverted lists
33
35
  size_t nlist; ///< number of possible key values
34
36
 
35
-
36
37
  /**
37
38
  * = 0: use the quantizer as index in a kmeans training
38
39
  * = 1: just pass on the training set to the train() of the quantizer
@@ -107,14 +108,18 @@ struct IndexIVF: Index, Level1Quantizer {
107
108
  /** Parallel mode determines how queries are parallelized with OpenMP
108
109
  *
109
110
  * 0 (default): parallelize over queries
110
- * 1: parallelize over over inverted lists
111
+ * 1: parallelize over inverted lists
111
112
  * 2: parallelize over both
113
+ *
114
+ * PARALLEL_MODE_NO_HEAP_INIT: binary or with the previous to
115
+ * prevent the heap to be initialized and finalized
112
116
  */
113
117
  int parallel_mode;
118
+ const int PARALLEL_MODE_NO_HEAP_INIT = 1024;
114
119
 
115
- /// map for direct access to the elements. Enables reconstruct().
116
- bool maintain_direct_map;
117
- std::vector <idx_t> direct_map;
120
+ /** optional map that maps back ids to invlist entries. This
121
+ * enables reconstruct() */
122
+ DirectMap direct_map;
118
123
 
119
124
  /** The Inverted file takes a quantizer (an Index) on input,
120
125
  * which implements the function mapping a vector to a list
@@ -195,8 +200,19 @@ struct IndexIVF: Index, Level1Quantizer {
195
200
  virtual InvertedListScanner *get_InvertedListScanner (
196
201
  bool store_pairs=false) const;
197
202
 
203
+ /** reconstruct a vector. Works only if maintain_direct_map is set to 1 or 2 */
198
204
  void reconstruct (idx_t key, float* recons) const override;
199
205
 
206
+ /** Update a subset of vectors.
207
+ *
208
+ * The index must have a direct_map
209
+ *
210
+ * @param nv nb of vectors to update
211
+ * @param idx vector indices to update, size nv
212
+ * @param v vectors of new values, size nv*d
213
+ */
214
+ virtual void update_vectors (int nv, const idx_t *idx, const float *v);
215
+
200
216
  /** Reconstruct a subset of the indexed vectors.
201
217
  *
202
218
  * Overrides default implementation to bypass reconstruct() which requires
@@ -268,6 +284,9 @@ struct IndexIVF: Index, Level1Quantizer {
268
284
  */
269
285
  void make_direct_map (bool new_maintain_direct_map=true);
270
286
 
287
+ void set_direct_map_type (DirectMap::Type type);
288
+
289
+
271
290
  /// replace the inverted lists, old one is deallocated if own_invlists
272
291
  void replace_invlists (InvertedLists *il, bool own=false);
273
292
 
@@ -45,8 +45,7 @@ void IndexIVFFlat::add_core (idx_t n, const float * x, const int64_t *xids,
45
45
  {
46
46
  FAISS_THROW_IF_NOT (is_trained);
47
47
  assert (invlists);
48
- FAISS_THROW_IF_NOT_MSG (!(maintain_direct_map && xids),
49
- "cannot have direct map and add with ids");
48
+ direct_map.check_can_add (xids);
50
49
  const int64_t * idx;
51
50
  ScopeDeleter<int64_t> del;
52
51
 
@@ -60,19 +59,21 @@ void IndexIVFFlat::add_core (idx_t n, const float * x, const int64_t *xids,
60
59
  }
61
60
  int64_t n_add = 0;
62
61
  for (size_t i = 0; i < n; i++) {
63
- int64_t id = xids ? xids[i] : ntotal + i;
64
- int64_t list_no = idx [i];
65
-
66
- if (list_no < 0)
67
- continue;
68
- const float *xi = x + i * d;
69
- size_t offset = invlists->add_entry (
70
- list_no, id, (const uint8_t*) xi);
62
+ idx_t id = xids ? xids[i] : ntotal + i;
63
+ idx_t list_no = idx [i];
64
+ size_t offset;
71
65
 
72
- if (maintain_direct_map)
73
- direct_map.push_back (list_no << 32 | offset);
74
- n_add++;
66
+ if (list_no >= 0) {
67
+ const float *xi = x + i * d;
68
+ offset = invlists->add_entry (
69
+ list_no, id, (const uint8_t*) xi);
70
+ n_add++;
71
+ } else {
72
+ offset = 0;
73
+ }
74
+ direct_map.add_single_id (id, list_no, offset);
75
75
  }
76
+
76
77
  if (verbose) {
77
78
  printf("IndexIVFFlat::add_core: added %ld / %ld vectors\n",
78
79
  n_add, n);
@@ -158,7 +159,7 @@ struct IVFFlatScanner: InvertedListScanner {
158
159
  fvec_inner_product (xi, yj, d) : fvec_L2sqr (xi, yj, d);
159
160
  if (C::cmp (simi[0], dis)) {
160
161
  heap_pop<C> (k, simi, idxi);
161
- int64_t id = store_pairs ? (list_no << 32 | j) : ids[j];
162
+ int64_t id = store_pairs ? lo_build (list_no, j) : ids[j];
162
163
  heap_push<C> (k, simi, idxi, dis, id);
163
164
  nup++;
164
165
  }
@@ -178,7 +179,7 @@ struct IVFFlatScanner: InvertedListScanner {
178
179
  float dis = metric == METRIC_INNER_PRODUCT ?
179
180
  fvec_inner_product (xi, yj, d) : fvec_L2sqr (xi, yj, d);
180
181
  if (C::cmp (radius, dis)) {
181
- int64_t id = store_pairs ? (list_no << 32 | j) : ids[j];
182
+ int64_t id = store_pairs ? lo_build (list_no, j) : ids[j];
182
183
  res.add (dis, id);
183
184
  }
184
185
  }
@@ -209,41 +210,6 @@ InvertedListScanner* IndexIVFFlat::get_InvertedListScanner
209
210
 
210
211
 
211
212
 
212
- void IndexIVFFlat::update_vectors (int n, idx_t *new_ids, const float *x)
213
- {
214
-
215
- FAISS_THROW_IF_NOT (maintain_direct_map);
216
- FAISS_THROW_IF_NOT (is_trained);
217
- std::vector<idx_t> assign (n);
218
- quantizer->assign (n, x, assign.data());
219
-
220
- for (size_t i = 0; i < n; i++) {
221
- idx_t id = new_ids[i];
222
- FAISS_THROW_IF_NOT_MSG (0 <= id && id < ntotal,
223
- "id to update out of range");
224
- { // remove old one
225
- int64_t dm = direct_map[id];
226
- int64_t ofs = dm & 0xffffffff;
227
- int64_t il = dm >> 32;
228
- size_t l = invlists->list_size (il);
229
- if (ofs != l - 1) { // move l - 1 to ofs
230
- int64_t id2 = invlists->get_single_id (il, l - 1);
231
- direct_map[id2] = (il << 32) | ofs;
232
- invlists->update_entry (il, ofs, id2,
233
- invlists->get_single_code (il, l - 1));
234
- }
235
- invlists->resize (il, l - 1);
236
- }
237
- { // insert new one
238
- int64_t il = assign[i];
239
- size_t l = invlists->list_size (il);
240
- int64_t dm = (il << 32) | l;
241
- direct_map[id] = dm;
242
- invlists->add_entry (il, id, (const uint8_t*)(x + i * d));
243
- }
244
- }
245
-
246
- }
247
213
 
248
214
  void IndexIVFFlat::reconstruct_from_offset (int64_t list_no, int64_t offset,
249
215
  float* recons) const
@@ -295,8 +261,7 @@ void IndexIVFFlatDedup::add_with_ids(
295
261
 
296
262
  FAISS_THROW_IF_NOT (is_trained);
297
263
  assert (invlists);
298
- FAISS_THROW_IF_NOT_MSG (
299
- !maintain_direct_map,
264
+ FAISS_THROW_IF_NOT_MSG (direct_map.no(),
300
265
  "IVFFlatDedup not implemented with direct_map");
301
266
  int64_t * idx = new int64_t [na];
302
267
  ScopeDeleter<int64_t> del (idx);
@@ -431,7 +396,7 @@ size_t IndexIVFFlatDedup::remove_ids(const IDSelector& sel)
431
396
 
432
397
  // mostly copied from IndexIVF.cpp
433
398
 
434
- FAISS_THROW_IF_NOT_MSG (!maintain_direct_map,
399
+ FAISS_THROW_IF_NOT_MSG (direct_map.no(),
435
400
  "direct map remove not implemented");
436
401
 
437
402
  std::vector<int64_t> toremove(nlist);
@@ -484,7 +449,7 @@ void IndexIVFFlatDedup::range_search(
484
449
  FAISS_THROW_MSG ("not implemented");
485
450
  }
486
451
 
487
- void IndexIVFFlatDedup::update_vectors (int , idx_t *, const float *)
452
+ void IndexIVFFlatDedup::update_vectors (int , const idx_t *, const float *)
488
453
  {
489
454
  FAISS_THROW_MSG ("not implemented");
490
455
  }
@@ -44,15 +44,6 @@ struct IndexIVFFlat: IndexIVF {
44
44
  InvertedListScanner *get_InvertedListScanner (bool store_pairs)
45
45
  const override;
46
46
 
47
- /** Update a subset of vectors.
48
- *
49
- * The index must have a direct_map
50
- *
51
- * @param nv nb of vectors to update
52
- * @param idx vector indices to update, size nv
53
- * @param v vectors of new values, size nv*d
54
- */
55
- virtual void update_vectors (int nv, idx_t *idx, const float *v);
56
47
 
57
48
  void reconstruct_from_offset (int64_t list_no, int64_t offset,
58
49
  float* recons) const override;
@@ -99,8 +90,7 @@ struct IndexIVFFlatDedup: IndexIVFFlat {
99
90
  RangeSearchResult* result) const override;
100
91
 
101
92
  /// not implemented
102
- void update_vectors (int nv, idx_t *idx, const float *v) override;
103
-
93
+ void update_vectors (int nv, const idx_t *idx, const float *v) override;
104
94
 
105
95
  /// not implemented
106
96
  void reconstruct_from_offset (int64_t list_no, int64_t offset,
@@ -36,8 +36,8 @@ namespace faiss {
36
36
  ******************************************/
37
37
 
38
38
  IndexIVFPQ::IndexIVFPQ (Index * quantizer, size_t d, size_t nlist,
39
- size_t M, size_t nbits_per_idx):
40
- IndexIVF (quantizer, d, nlist, 0, METRIC_L2),
39
+ size_t M, size_t nbits_per_idx, MetricType metric):
40
+ IndexIVF (quantizer, d, nlist, 0, metric),
41
41
  pq (d, M, nbits_per_idx)
42
42
  {
43
43
  FAISS_THROW_IF_NOT (nbits_per_idx <= 8);
@@ -278,6 +278,8 @@ void IndexIVFPQ::add_core_o (idx_t n, const float * x, const idx_t *xids,
278
278
 
279
279
  InterruptCallback::check();
280
280
 
281
+ direct_map.check_can_add (xids);
282
+
281
283
  FAISS_THROW_IF_NOT (is_trained);
282
284
  double t0 = getmillisecs ();
283
285
  const idx_t * idx;
@@ -312,13 +314,14 @@ void IndexIVFPQ::add_core_o (idx_t n, const float * x, const idx_t *xids,
312
314
  size_t n_ignore = 0;
313
315
  for (size_t i = 0; i < n; i++) {
314
316
  idx_t key = idx[i];
317
+ idx_t id = xids ? xids[i] : ntotal + i;
315
318
  if (key < 0) {
319
+ direct_map.add_single_id (id, -1, 0);
316
320
  n_ignore ++;
317
321
  if (residuals_2)
318
322
  memset (residuals_2, 0, sizeof(*residuals_2) * d);
319
323
  continue;
320
324
  }
321
- idx_t id = xids ? xids[i] : ntotal + i;
322
325
 
323
326
  uint8_t *code = xcodes + i * code_size;
324
327
  size_t offset = invlists->add_entry (key, id, code);
@@ -331,11 +334,9 @@ void IndexIVFPQ::add_core_o (idx_t n, const float * x, const idx_t *xids,
331
334
  res2[j] = xi[j] - res2[j];
332
335
  }
333
336
 
334
- if (maintain_direct_map)
335
- direct_map.push_back (key << 32 | offset);
337
+ direct_map.add_single_id (id, key, offset);
336
338
  }
337
339
 
338
-
339
340
  double t3 = getmillisecs ();
340
341
  if(verbose) {
341
342
  char comment[100] = {0};
@@ -802,7 +803,7 @@ struct KnnSearchResults {
802
803
  inline void add (idx_t j, float dis) {
803
804
  if (C::cmp (heap_sim[0], dis)) {
804
805
  heap_pop<C> (k, heap_sim, heap_ids);
805
- idx_t id = ids ? ids[j] : (key << 32 | j);
806
+ idx_t id = ids ? ids[j] : lo_build (key, j);
806
807
  heap_push<C> (k, heap_sim, heap_ids, dis, id);
807
808
  nup++;
808
809
  }
@@ -821,7 +822,7 @@ struct RangeSearchResults {
821
822
 
822
823
  inline void add (idx_t j, float dis) {
823
824
  if (C::cmp (radius, dis)) {
824
- idx_t id = ids ? ids[j] : (key << 32 | j);
825
+ idx_t id = ids ? ids[j] : lo_build (key, j);
825
826
  rres.add (dis, id);
826
827
  }
827
828
  }
@@ -834,7 +835,7 @@ struct RangeSearchResults {
834
835
  * The scanning functions call their favorite precompute_*
835
836
  * function to precompute the tables they need.
836
837
  *****************************************************/
837
- template <typename IDType, MetricType METRIC_TYPE>
838
+ template <typename IDType, MetricType METRIC_TYPE, class PQDecoder>
838
839
  struct IVFPQScannerT: QueryTables {
839
840
 
840
841
  const uint8_t * list_codes;
@@ -844,7 +845,6 @@ struct IVFPQScannerT: QueryTables {
844
845
  IVFPQScannerT (const IndexIVFPQ & ivfpq, const IVFSearchParameters *params):
845
846
  QueryTables (ivfpq, params)
846
847
  {
847
- FAISS_THROW_IF_NOT (pq.nbits == 8);
848
848
  assert(METRIC_TYPE == metric_type);
849
849
  }
850
850
 
@@ -872,12 +872,13 @@ struct IVFPQScannerT: QueryTables {
872
872
  SearchResultType & res) const
873
873
  {
874
874
  for (size_t j = 0; j < ncode; j++) {
875
-
875
+ PQDecoder decoder(codes, pq.nbits);
876
+ codes += pq.code_size;
876
877
  float dis = dis0;
877
878
  const float *tab = sim_table;
878
879
 
879
880
  for (size_t m = 0; m < pq.M; m++) {
880
- dis += tab[*codes++];
881
+ dis += tab[decoder.decode()];
881
882
  tab += pq.ksub;
882
883
  }
883
884
 
@@ -893,12 +894,14 @@ struct IVFPQScannerT: QueryTables {
893
894
  SearchResultType & res) const
894
895
  {
895
896
  for (size_t j = 0; j < ncode; j++) {
897
+ PQDecoder decoder(codes, pq.nbits);
898
+ codes += pq.code_size;
896
899
 
897
900
  float dis = dis0;
898
901
  const float *tab = sim_table_2;
899
902
 
900
903
  for (size_t m = 0; m < pq.M; m++) {
901
- int ci = *codes++;
904
+ int ci = decoder.decode();
902
905
  dis += sim_table_ptrs [m][ci] - 2 * tab [ci];
903
906
  tab += pq.ksub;
904
907
  }
@@ -963,12 +966,13 @@ struct IVFPQScannerT: QueryTables {
963
966
  int hd = hc.hamming (b_code);
964
967
  if (hd < ht) {
965
968
  n_hamming_pass ++;
969
+ PQDecoder decoder(codes, pq.nbits);
966
970
 
967
971
  float dis = dis0;
968
972
  const float *tab = sim_table;
969
973
 
970
974
  for (size_t m = 0; m < pq.M; m++) {
971
- dis += tab[*b_code++];
975
+ dis += tab[decoder.decode()];
972
976
  tab += pq.ksub;
973
977
  }
974
978
 
@@ -1023,16 +1027,18 @@ struct IVFPQScannerT: QueryTables {
1023
1027
  * much we precompute (2 = precompute distance tables, 1 = precompute
1024
1028
  * pointers to distances, 0 = compute distances one by one).
1025
1029
  * Currently only 2 is supported */
1026
- template<MetricType METRIC_TYPE, class C, int precompute_mode>
1030
+ template<MetricType METRIC_TYPE, class C, class PQDecoder>
1027
1031
  struct IVFPQScanner:
1028
- IVFPQScannerT<Index::idx_t, METRIC_TYPE>,
1032
+ IVFPQScannerT<Index::idx_t, METRIC_TYPE, PQDecoder>,
1029
1033
  InvertedListScanner
1030
1034
  {
1031
1035
  bool store_pairs;
1036
+ int precompute_mode;
1032
1037
 
1033
- IVFPQScanner(const IndexIVFPQ & ivfpq, bool store_pairs):
1034
- IVFPQScannerT<Index::idx_t, METRIC_TYPE>(ivfpq, nullptr),
1035
- store_pairs(store_pairs)
1038
+ IVFPQScanner(const IndexIVFPQ & ivfpq, bool store_pairs,
1039
+ int precompute_mode):
1040
+ IVFPQScannerT<Index::idx_t, METRIC_TYPE, PQDecoder>(ivfpq, nullptr),
1041
+ store_pairs(store_pairs), precompute_mode(precompute_mode)
1036
1042
  {
1037
1043
  }
1038
1044
 
@@ -1048,9 +1054,10 @@ struct IVFPQScanner:
1048
1054
  assert(precompute_mode == 2);
1049
1055
  float dis = this->dis0;
1050
1056
  const float *tab = this->sim_table;
1057
+ PQDecoder decoder(code, this->pq.nbits);
1051
1058
 
1052
1059
  for (size_t m = 0; m < this->pq.M; m++) {
1053
- dis += tab[*code++];
1060
+ dis += tab[decoder.decode()];
1054
1061
  tab += this->pq.ksub;
1055
1062
  }
1056
1063
  return dis;
@@ -1115,7 +1122,22 @@ struct IVFPQScanner:
1115
1122
  }
1116
1123
  };
1117
1124
 
1125
+ template<class PQDecoder>
1126
+ InvertedListScanner *get_InvertedListScanner1 (const IndexIVFPQ &index,
1127
+ bool store_pairs)
1128
+ {
1118
1129
 
1130
+ if (index.metric_type == METRIC_INNER_PRODUCT) {
1131
+ return new IVFPQScanner
1132
+ <METRIC_INNER_PRODUCT, CMin<float, idx_t>, PQDecoder>
1133
+ (index, store_pairs, 2);
1134
+ } else if (index.metric_type == METRIC_L2) {
1135
+ return new IVFPQScanner
1136
+ <METRIC_L2, CMax<float, idx_t>, PQDecoder>
1137
+ (index, store_pairs, 2);
1138
+ }
1139
+ return nullptr;
1140
+ }
1119
1141
 
1120
1142
 
1121
1143
  } // anonymous namespace
@@ -1123,12 +1145,13 @@ struct IVFPQScanner:
1123
1145
  InvertedListScanner *
1124
1146
  IndexIVFPQ::get_InvertedListScanner (bool store_pairs) const
1125
1147
  {
1126
- if (metric_type == METRIC_INNER_PRODUCT) {
1127
- return new IVFPQScanner<METRIC_INNER_PRODUCT, CMin<float, idx_t>, 2>
1128
- (*this, store_pairs);
1129
- } else if (metric_type == METRIC_L2) {
1130
- return new IVFPQScanner<METRIC_L2, CMax<float, idx_t>, 2>
1131
- (*this, store_pairs);
1148
+
1149
+ if (pq.nbits == 8) {
1150
+ return get_InvertedListScanner1<PQDecoder8> (*this, store_pairs);
1151
+ } else if (pq.nbits == 16) {
1152
+ return get_InvertedListScanner1<PQDecoder16> (*this, store_pairs);
1153
+ } else {
1154
+ return get_InvertedListScanner1<PQDecoderGeneric> (*this, store_pairs);
1132
1155
  }
1133
1156
  return nullptr;
1134
1157
 
@@ -42,14 +42,14 @@ struct IndexIVFPQ: IndexIVF {
42
42
  int polysemous_ht; ///< Hamming thresh for polysemous filtering
43
43
 
44
44
  /** Precompute table that speed up query preprocessing at some
45
- * memory cost
45
+ * memory cost (used only for by_residual with L2 metric)
46
46
  * =-1: force disable
47
47
  * =0: decide heuristically (default: use tables only if they are
48
48
  * < precomputed_tables_max_bytes)
49
49
  * =1: tables that work for all quantizers (size 256 * nlist * M)
50
50
  * =2: specific version for MultiIndexQuantizer (much more compact)
51
51
  */
52
- int use_precomputed_table; ///< if by_residual, build precompute tables
52
+ int use_precomputed_table;
53
53
  static size_t precomputed_table_max_bytes;
54
54
 
55
55
  /// if use_precompute_table
@@ -58,7 +58,7 @@ struct IndexIVFPQ: IndexIVF {
58
58
 
59
59
  IndexIVFPQ (
60
60
  Index * quantizer, size_t d, size_t nlist,
61
- size_t M, size_t nbits_per_idx);
61
+ size_t M, size_t nbits_per_idx, MetricType metric = METRIC_L2);
62
62
 
63
63
  void add_with_ids(idx_t n, const float* x, const idx_t* xids = nullptr)
64
64
  override;
@@ -93,9 +93,9 @@ struct IndexIVFPQ: IndexIVF {
93
93
  * the duplicates are returned in pre-allocated arrays (see the
94
94
  * max sizes).
95
95
  *
96
- * @params lims limits between groups of duplicates
96
+ * @param lims limits between groups of duplicates
97
97
  * (max size ntotal / 2 + 1)
98
- * @params ids ids[lims[i]] : ids[lims[i+1]-1] is a group of
98
+ * @param ids ids[lims[i]] : ids[lims[i+1]-1] is a group of
99
99
  * duplicates (max size ntotal)
100
100
  * @return n number of groups found
101
101
  */
@@ -135,15 +135,14 @@ struct IndexIVFPQ: IndexIVF {
135
135
  /// statistics are robust to internal threading, but not if
136
136
  /// IndexIVFPQ::search_preassigned is called by multiple threads
137
137
  struct IndexIVFPQStats {
138
- size_t nrefine; // nb of refines (IVFPQR)
138
+ size_t nrefine; ///< nb of refines (IVFPQR)
139
139
 
140
140
  size_t n_hamming_pass;
141
- // nb of passed Hamming distance tests (for polysemous)
141
+ ///< nb of passed Hamming distance tests (for polysemous)
142
142
 
143
- // timings measured with the CPU RTC
144
- // on all threads
143
+ // timings measured with the CPU RTC on all threads
145
144
  size_t search_cycles;
146
- size_t refine_cycles; // only for IVFPQR
145
+ size_t refine_cycles; ///< only for IVFPQR
147
146
 
148
147
  IndexIVFPQStats () {reset (); }
149
148
  void reset ();