faiss 0.3.0 → 0.3.1

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 (171) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +1 -1
  5. data/ext/faiss/extconf.rb +9 -2
  6. data/ext/faiss/index.cpp +1 -1
  7. data/ext/faiss/index_binary.cpp +2 -2
  8. data/ext/faiss/product_quantizer.cpp +1 -1
  9. data/lib/faiss/version.rb +1 -1
  10. data/vendor/faiss/faiss/AutoTune.cpp +7 -7
  11. data/vendor/faiss/faiss/AutoTune.h +0 -1
  12. data/vendor/faiss/faiss/Clustering.cpp +4 -18
  13. data/vendor/faiss/faiss/Clustering.h +31 -21
  14. data/vendor/faiss/faiss/IVFlib.cpp +22 -11
  15. data/vendor/faiss/faiss/Index.cpp +1 -1
  16. data/vendor/faiss/faiss/Index.h +20 -5
  17. data/vendor/faiss/faiss/Index2Layer.cpp +7 -7
  18. data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +176 -166
  19. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +15 -15
  20. data/vendor/faiss/faiss/IndexBinary.cpp +9 -4
  21. data/vendor/faiss/faiss/IndexBinary.h +8 -19
  22. data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +2 -1
  23. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +24 -31
  24. data/vendor/faiss/faiss/IndexBinaryHash.cpp +25 -50
  25. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +106 -187
  26. data/vendor/faiss/faiss/IndexFastScan.cpp +90 -159
  27. data/vendor/faiss/faiss/IndexFastScan.h +9 -8
  28. data/vendor/faiss/faiss/IndexFlat.cpp +195 -3
  29. data/vendor/faiss/faiss/IndexFlat.h +20 -1
  30. data/vendor/faiss/faiss/IndexFlatCodes.cpp +11 -0
  31. data/vendor/faiss/faiss/IndexFlatCodes.h +3 -1
  32. data/vendor/faiss/faiss/IndexHNSW.cpp +112 -316
  33. data/vendor/faiss/faiss/IndexHNSW.h +12 -48
  34. data/vendor/faiss/faiss/IndexIDMap.cpp +69 -28
  35. data/vendor/faiss/faiss/IndexIDMap.h +24 -2
  36. data/vendor/faiss/faiss/IndexIVF.cpp +159 -53
  37. data/vendor/faiss/faiss/IndexIVF.h +37 -5
  38. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +18 -26
  39. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.h +3 -2
  40. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +19 -46
  41. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.h +4 -3
  42. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +433 -405
  43. data/vendor/faiss/faiss/IndexIVFFastScan.h +56 -26
  44. data/vendor/faiss/faiss/IndexIVFFlat.cpp +15 -5
  45. data/vendor/faiss/faiss/IndexIVFFlat.h +3 -2
  46. data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +172 -0
  47. data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.h +56 -0
  48. data/vendor/faiss/faiss/IndexIVFPQ.cpp +78 -122
  49. data/vendor/faiss/faiss/IndexIVFPQ.h +6 -7
  50. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +18 -50
  51. data/vendor/faiss/faiss/IndexIVFPQFastScan.h +4 -3
  52. data/vendor/faiss/faiss/IndexIVFPQR.cpp +45 -29
  53. data/vendor/faiss/faiss/IndexIVFPQR.h +5 -2
  54. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +25 -27
  55. data/vendor/faiss/faiss/IndexIVFSpectralHash.h +6 -6
  56. data/vendor/faiss/faiss/IndexLSH.cpp +14 -16
  57. data/vendor/faiss/faiss/IndexNNDescent.cpp +3 -4
  58. data/vendor/faiss/faiss/IndexNSG.cpp +11 -27
  59. data/vendor/faiss/faiss/IndexNSG.h +10 -10
  60. data/vendor/faiss/faiss/IndexPQ.cpp +72 -88
  61. data/vendor/faiss/faiss/IndexPQ.h +1 -4
  62. data/vendor/faiss/faiss/IndexPQFastScan.cpp +1 -1
  63. data/vendor/faiss/faiss/IndexPreTransform.cpp +25 -31
  64. data/vendor/faiss/faiss/IndexRefine.cpp +49 -19
  65. data/vendor/faiss/faiss/IndexRefine.h +7 -0
  66. data/vendor/faiss/faiss/IndexReplicas.cpp +23 -26
  67. data/vendor/faiss/faiss/IndexScalarQuantizer.cpp +22 -16
  68. data/vendor/faiss/faiss/IndexScalarQuantizer.h +6 -4
  69. data/vendor/faiss/faiss/IndexShards.cpp +21 -29
  70. data/vendor/faiss/faiss/IndexShardsIVF.cpp +1 -2
  71. data/vendor/faiss/faiss/MatrixStats.cpp +17 -32
  72. data/vendor/faiss/faiss/MatrixStats.h +21 -9
  73. data/vendor/faiss/faiss/MetaIndexes.cpp +35 -35
  74. data/vendor/faiss/faiss/VectorTransform.cpp +13 -26
  75. data/vendor/faiss/faiss/VectorTransform.h +7 -7
  76. data/vendor/faiss/faiss/clone_index.cpp +15 -10
  77. data/vendor/faiss/faiss/clone_index.h +3 -0
  78. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +87 -4
  79. data/vendor/faiss/faiss/gpu/GpuCloner.h +22 -0
  80. data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +7 -0
  81. data/vendor/faiss/faiss/gpu/GpuDistance.h +46 -38
  82. data/vendor/faiss/faiss/gpu/GpuIndex.h +28 -4
  83. data/vendor/faiss/faiss/gpu/GpuIndexFlat.h +4 -4
  84. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +8 -9
  85. data/vendor/faiss/faiss/gpu/GpuIndexIVFFlat.h +18 -3
  86. data/vendor/faiss/faiss/gpu/GpuIndexIVFPQ.h +22 -11
  87. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +1 -3
  88. data/vendor/faiss/faiss/gpu/GpuResources.cpp +24 -3
  89. data/vendor/faiss/faiss/gpu/GpuResources.h +39 -11
  90. data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +117 -17
  91. data/vendor/faiss/faiss/gpu/StandardGpuResources.h +57 -3
  92. data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +1 -1
  93. data/vendor/faiss/faiss/gpu/test/TestGpuIndexBinaryFlat.cpp +25 -0
  94. data/vendor/faiss/faiss/gpu/test/TestGpuIndexFlat.cpp +129 -9
  95. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +267 -40
  96. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFPQ.cpp +299 -208
  97. data/vendor/faiss/faiss/gpu/test/TestGpuMemoryException.cpp +1 -0
  98. data/vendor/faiss/faiss/gpu/utils/RaftUtils.h +75 -0
  99. data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +3 -1
  100. data/vendor/faiss/faiss/impl/AdditiveQuantizer.h +5 -5
  101. data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +1 -1
  102. data/vendor/faiss/faiss/impl/AuxIndexStructures.h +1 -2
  103. data/vendor/faiss/faiss/impl/DistanceComputer.h +24 -1
  104. data/vendor/faiss/faiss/impl/FaissException.h +13 -34
  105. data/vendor/faiss/faiss/impl/HNSW.cpp +321 -70
  106. data/vendor/faiss/faiss/impl/HNSW.h +9 -8
  107. data/vendor/faiss/faiss/impl/IDSelector.h +4 -4
  108. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +3 -1
  109. data/vendor/faiss/faiss/impl/NNDescent.cpp +29 -19
  110. data/vendor/faiss/faiss/impl/NSG.h +1 -1
  111. data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +14 -12
  112. data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.h +1 -1
  113. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +24 -22
  114. data/vendor/faiss/faiss/impl/ProductQuantizer.h +1 -1
  115. data/vendor/faiss/faiss/impl/Quantizer.h +1 -1
  116. data/vendor/faiss/faiss/impl/ResidualQuantizer.cpp +27 -1015
  117. data/vendor/faiss/faiss/impl/ResidualQuantizer.h +5 -63
  118. data/vendor/faiss/faiss/impl/ResultHandler.h +232 -176
  119. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +444 -104
  120. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +0 -8
  121. data/vendor/faiss/faiss/impl/code_distance/code_distance-avx2.h +280 -42
  122. data/vendor/faiss/faiss/impl/code_distance/code_distance-generic.h +21 -14
  123. data/vendor/faiss/faiss/impl/code_distance/code_distance.h +22 -12
  124. data/vendor/faiss/faiss/impl/index_read.cpp +45 -19
  125. data/vendor/faiss/faiss/impl/index_write.cpp +60 -41
  126. data/vendor/faiss/faiss/impl/io.cpp +10 -10
  127. data/vendor/faiss/faiss/impl/lattice_Zn.cpp +1 -1
  128. data/vendor/faiss/faiss/impl/platform_macros.h +18 -1
  129. data/vendor/faiss/faiss/impl/pq4_fast_scan.cpp +3 -0
  130. data/vendor/faiss/faiss/impl/pq4_fast_scan.h +7 -6
  131. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_1.cpp +52 -38
  132. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_qbs.cpp +40 -49
  133. data/vendor/faiss/faiss/impl/residual_quantizer_encode_steps.cpp +960 -0
  134. data/vendor/faiss/faiss/impl/residual_quantizer_encode_steps.h +176 -0
  135. data/vendor/faiss/faiss/impl/simd_result_handlers.h +374 -202
  136. data/vendor/faiss/faiss/index_factory.cpp +10 -7
  137. data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
  138. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +27 -9
  139. data/vendor/faiss/faiss/invlists/InvertedLists.h +12 -3
  140. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +3 -3
  141. data/vendor/faiss/faiss/python/python_callbacks.cpp +1 -1
  142. data/vendor/faiss/faiss/utils/Heap.cpp +3 -1
  143. data/vendor/faiss/faiss/utils/WorkerThread.h +1 -0
  144. data/vendor/faiss/faiss/utils/distances.cpp +128 -74
  145. data/vendor/faiss/faiss/utils/distances.h +81 -4
  146. data/vendor/faiss/faiss/utils/distances_fused/avx512.cpp +5 -5
  147. data/vendor/faiss/faiss/utils/distances_fused/avx512.h +2 -2
  148. data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +2 -2
  149. data/vendor/faiss/faiss/utils/distances_fused/distances_fused.h +1 -1
  150. data/vendor/faiss/faiss/utils/distances_fused/simdlib_based.cpp +5 -5
  151. data/vendor/faiss/faiss/utils/distances_fused/simdlib_based.h +1 -1
  152. data/vendor/faiss/faiss/utils/distances_simd.cpp +428 -70
  153. data/vendor/faiss/faiss/utils/fp16-arm.h +29 -0
  154. data/vendor/faiss/faiss/utils/fp16.h +2 -0
  155. data/vendor/faiss/faiss/utils/hamming.cpp +162 -110
  156. data/vendor/faiss/faiss/utils/hamming.h +58 -0
  157. data/vendor/faiss/faiss/utils/hamming_distance/avx2-inl.h +16 -89
  158. data/vendor/faiss/faiss/utils/hamming_distance/common.h +1 -0
  159. data/vendor/faiss/faiss/utils/hamming_distance/generic-inl.h +15 -87
  160. data/vendor/faiss/faiss/utils/hamming_distance/hamdis-inl.h +57 -0
  161. data/vendor/faiss/faiss/utils/hamming_distance/neon-inl.h +14 -104
  162. data/vendor/faiss/faiss/utils/partitioning.cpp +3 -4
  163. data/vendor/faiss/faiss/utils/prefetch.h +77 -0
  164. data/vendor/faiss/faiss/utils/quantize_lut.cpp +0 -14
  165. data/vendor/faiss/faiss/utils/simdlib_avx2.h +0 -6
  166. data/vendor/faiss/faiss/utils/simdlib_neon.h +72 -77
  167. data/vendor/faiss/faiss/utils/sorting.cpp +140 -5
  168. data/vendor/faiss/faiss/utils/sorting.h +27 -0
  169. data/vendor/faiss/faiss/utils/utils.cpp +112 -6
  170. data/vendor/faiss/faiss/utils/utils.h +57 -20
  171. metadata +10 -3
@@ -12,17 +12,34 @@
12
12
 
13
13
  namespace faiss {
14
14
 
15
+ namespace {
16
+
17
+ // IndexBinary needs to update the code_size when d is set...
18
+
19
+ void sync_d(Index* index) {}
20
+
21
+ void sync_d(IndexBinary* index) {
22
+ FAISS_THROW_IF_NOT(index->d % 8 == 0);
23
+ index->code_size = index->d / 8;
24
+ }
25
+
26
+ } // anonymous namespace
27
+
15
28
  template <typename IndexT>
16
29
  IndexReplicasTemplate<IndexT>::IndexReplicasTemplate(bool threaded)
17
30
  : ThreadedIndex<IndexT>(threaded) {}
18
31
 
19
32
  template <typename IndexT>
20
33
  IndexReplicasTemplate<IndexT>::IndexReplicasTemplate(idx_t d, bool threaded)
21
- : ThreadedIndex<IndexT>(d, threaded) {}
34
+ : ThreadedIndex<IndexT>(d, threaded) {
35
+ sync_d(this);
36
+ }
22
37
 
23
38
  template <typename IndexT>
24
39
  IndexReplicasTemplate<IndexT>::IndexReplicasTemplate(int d, bool threaded)
25
- : ThreadedIndex<IndexT>(d, threaded) {}
40
+ : ThreadedIndex<IndexT>(d, threaded) {
41
+ sync_d(this);
42
+ }
26
43
 
27
44
  template <typename IndexT>
28
45
  void IndexReplicasTemplate<IndexT>::onAfterAddIndex(IndexT* index) {
@@ -168,6 +185,8 @@ void IndexReplicasTemplate<IndexT>::syncWithSubIndexes() {
168
185
  }
169
186
 
170
187
  auto firstIndex = this->at(0);
188
+ this->d = firstIndex->d;
189
+ sync_d(this);
171
190
  this->metric_type = firstIndex->metric_type;
172
191
  this->is_trained = firstIndex->is_trained;
173
192
  this->ntotal = firstIndex->ntotal;
@@ -181,30 +200,8 @@ void IndexReplicasTemplate<IndexT>::syncWithSubIndexes() {
181
200
  }
182
201
  }
183
202
 
184
- // No metric_type for IndexBinary
185
- template <>
186
- void IndexReplicasTemplate<IndexBinary>::syncWithSubIndexes() {
187
- if (!this->count()) {
188
- this->is_trained = false;
189
- this->ntotal = 0;
190
-
191
- return;
192
- }
193
-
194
- auto firstIndex = this->at(0);
195
- this->is_trained = firstIndex->is_trained;
196
- this->ntotal = firstIndex->ntotal;
197
-
198
- for (int i = 1; i < this->count(); ++i) {
199
- auto index = this->at(i);
200
- FAISS_THROW_IF_NOT(this->d == index->d);
201
- FAISS_THROW_IF_NOT(this->is_trained == index->is_trained);
202
- FAISS_THROW_IF_NOT(this->ntotal == index->ntotal);
203
- }
204
- }
205
-
206
203
  // explicit instantiations
207
- template struct IndexReplicasTemplate<Index>;
208
- template struct IndexReplicasTemplate<IndexBinary>;
204
+ template class IndexReplicasTemplate<Index>;
205
+ template class IndexReplicasTemplate<IndexBinary>;
209
206
 
210
207
  } // namespace faiss
@@ -60,10 +60,9 @@ void IndexScalarQuantizer::search(
60
60
 
61
61
  #pragma omp parallel
62
62
  {
63
- InvertedListScanner* scanner =
64
- sq.select_InvertedListScanner(metric_type, nullptr, true, sel);
63
+ std::unique_ptr<InvertedListScanner> scanner(
64
+ sq.select_InvertedListScanner(metric_type, nullptr, true, sel));
65
65
 
66
- ScopeDeleter1<InvertedListScanner> del(scanner);
67
66
  scanner->list_no = 0; // directly the list number
68
67
 
69
68
  #pragma omp for
@@ -122,21 +121,28 @@ IndexIVFScalarQuantizer::IndexIVFScalarQuantizer(
122
121
  size_t nlist,
123
122
  ScalarQuantizer::QuantizerType qtype,
124
123
  MetricType metric,
125
- bool encode_residual)
126
- : IndexIVF(quantizer, d, nlist, 0, metric),
127
- sq(d, qtype),
128
- by_residual(encode_residual) {
124
+ bool by_residual)
125
+ : IndexIVF(quantizer, d, nlist, 0, metric), sq(d, qtype) {
129
126
  code_size = sq.code_size;
127
+ this->by_residual = by_residual;
130
128
  // was not known at construction time
131
129
  invlists->code_size = code_size;
132
130
  is_trained = false;
133
131
  }
134
132
 
135
- IndexIVFScalarQuantizer::IndexIVFScalarQuantizer()
136
- : IndexIVF(), by_residual(true) {}
133
+ IndexIVFScalarQuantizer::IndexIVFScalarQuantizer() : IndexIVF() {
134
+ by_residual = true;
135
+ }
137
136
 
138
- void IndexIVFScalarQuantizer::train_residual(idx_t n, const float* x) {
139
- sq.train_residual(n, x, quantizer, by_residual, verbose);
137
+ void IndexIVFScalarQuantizer::train_encoder(
138
+ idx_t n,
139
+ const float* x,
140
+ const idx_t* assign) {
141
+ sq.train(n, x);
142
+ }
143
+
144
+ idx_t IndexIVFScalarQuantizer::train_encoder_num_vectors() const {
145
+ return 100000;
140
146
  }
141
147
 
142
148
  void IndexIVFScalarQuantizer::encode_vectors(
@@ -201,15 +207,15 @@ void IndexIVFScalarQuantizer::add_core(
201
207
  idx_t n,
202
208
  const float* x,
203
209
  const idx_t* xids,
204
- const idx_t* coarse_idx) {
210
+ const idx_t* coarse_idx,
211
+ void* inverted_list_context) {
205
212
  FAISS_THROW_IF_NOT(is_trained);
206
213
 
207
- size_t nadd = 0;
208
214
  std::unique_ptr<ScalarQuantizer::SQuantizer> squant(sq.select_quantizer());
209
215
 
210
216
  DirectMapAdd dm_add(direct_map, n, xids);
211
217
 
212
- #pragma omp parallel reduction(+ : nadd)
218
+ #pragma omp parallel
213
219
  {
214
220
  std::vector<float> residual(d);
215
221
  std::vector<uint8_t> one_code(code_size);
@@ -231,10 +237,10 @@ void IndexIVFScalarQuantizer::add_core(
231
237
  memset(one_code.data(), 0, code_size);
232
238
  squant->encode_vector(xi, one_code.data());
233
239
 
234
- size_t ofs = invlists->add_entry(list_no, id, one_code.data());
240
+ size_t ofs = invlists->add_entry(
241
+ list_no, id, one_code.data(), inverted_list_context);
235
242
 
236
243
  dm_add.add(i, list_no, ofs);
237
- nadd++;
238
244
 
239
245
  } else if (rank == 0 && list_no == -1) {
240
246
  dm_add.add(i, -1, 0);
@@ -65,7 +65,6 @@ struct IndexScalarQuantizer : IndexFlatCodes {
65
65
 
66
66
  struct IndexIVFScalarQuantizer : IndexIVF {
67
67
  ScalarQuantizer sq;
68
- bool by_residual;
69
68
 
70
69
  IndexIVFScalarQuantizer(
71
70
  Index* quantizer,
@@ -73,11 +72,13 @@ struct IndexIVFScalarQuantizer : IndexIVF {
73
72
  size_t nlist,
74
73
  ScalarQuantizer::QuantizerType qtype,
75
74
  MetricType metric = METRIC_L2,
76
- bool encode_residual = true);
75
+ bool by_residual = true);
77
76
 
78
77
  IndexIVFScalarQuantizer();
79
78
 
80
- void train_residual(idx_t n, const float* x) override;
79
+ void train_encoder(idx_t n, const float* x, const idx_t* assign) override;
80
+
81
+ idx_t train_encoder_num_vectors() const override;
81
82
 
82
83
  void encode_vectors(
83
84
  idx_t n,
@@ -90,7 +91,8 @@ struct IndexIVFScalarQuantizer : IndexIVF {
90
91
  idx_t n,
91
92
  const float* x,
92
93
  const idx_t* xids,
93
- const idx_t* precomputed_idx) override;
94
+ const idx_t* precomputed_idx,
95
+ void* inverted_list_context = nullptr) override;
94
96
 
95
97
  InvertedListScanner* get_InvertedListScanner(
96
98
  bool store_pairs,
@@ -5,8 +5,6 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- // -*- c++ -*-
9
-
10
8
  #include <faiss/IndexShards.h>
11
9
 
12
10
  #include <cinttypes>
@@ -22,6 +20,15 @@ namespace faiss {
22
20
  // subroutines
23
21
  namespace {
24
22
 
23
+ // IndexBinary needs to update the code_size when d is set...
24
+
25
+ void sync_d(Index* index) {}
26
+
27
+ void sync_d(IndexBinary* index) {
28
+ FAISS_THROW_IF_NOT(index->d % 8 == 0);
29
+ index->code_size = index->d / 8;
30
+ }
31
+
25
32
  // add translation to all valid labels
26
33
  void translate_labels(int64_t n, idx_t* labels, int64_t translation) {
27
34
  if (translation == 0)
@@ -40,20 +47,26 @@ IndexShardsTemplate<IndexT>::IndexShardsTemplate(
40
47
  idx_t d,
41
48
  bool threaded,
42
49
  bool successive_ids)
43
- : ThreadedIndex<IndexT>(d, threaded), successive_ids(successive_ids) {}
50
+ : ThreadedIndex<IndexT>(d, threaded), successive_ids(successive_ids) {
51
+ sync_d(this);
52
+ }
44
53
 
45
54
  template <typename IndexT>
46
55
  IndexShardsTemplate<IndexT>::IndexShardsTemplate(
47
56
  int d,
48
57
  bool threaded,
49
58
  bool successive_ids)
50
- : ThreadedIndex<IndexT>(d, threaded), successive_ids(successive_ids) {}
59
+ : ThreadedIndex<IndexT>(d, threaded), successive_ids(successive_ids) {
60
+ sync_d(this);
61
+ }
51
62
 
52
63
  template <typename IndexT>
53
64
  IndexShardsTemplate<IndexT>::IndexShardsTemplate(
54
65
  bool threaded,
55
66
  bool successive_ids)
56
- : ThreadedIndex<IndexT>(threaded), successive_ids(successive_ids) {}
67
+ : ThreadedIndex<IndexT>(threaded), successive_ids(successive_ids) {
68
+ sync_d(this);
69
+ }
57
70
 
58
71
  template <typename IndexT>
59
72
  void IndexShardsTemplate<IndexT>::onAfterAddIndex(IndexT* index /* unused */) {
@@ -78,6 +91,8 @@ void IndexShardsTemplate<IndexT>::syncWithSubIndexes() {
78
91
  }
79
92
 
80
93
  auto firstIndex = this->at(0);
94
+ this->d = firstIndex->d;
95
+ sync_d(this);
81
96
  this->metric_type = firstIndex->metric_type;
82
97
  this->is_trained = firstIndex->is_trained;
83
98
  this->ntotal = firstIndex->ntotal;
@@ -92,29 +107,6 @@ void IndexShardsTemplate<IndexT>::syncWithSubIndexes() {
92
107
  }
93
108
  }
94
109
 
95
- // No metric_type for IndexBinary
96
- template <>
97
- void IndexShardsTemplate<IndexBinary>::syncWithSubIndexes() {
98
- if (!this->count()) {
99
- this->is_trained = false;
100
- this->ntotal = 0;
101
-
102
- return;
103
- }
104
-
105
- auto firstIndex = this->at(0);
106
- this->is_trained = firstIndex->is_trained;
107
- this->ntotal = firstIndex->ntotal;
108
-
109
- for (int i = 1; i < this->count(); ++i) {
110
- auto index = this->at(i);
111
- FAISS_THROW_IF_NOT(this->d == index->d);
112
- FAISS_THROW_IF_NOT(this->is_trained == index->is_trained);
113
-
114
- this->ntotal += index->ntotal;
115
- }
116
- }
117
-
118
110
  template <typename IndexT>
119
111
  void IndexShardsTemplate<IndexT>::train(idx_t n, const component_t* x) {
120
112
  auto fn = [n, x](int no, IndexT* index) {
@@ -155,7 +147,7 @@ void IndexShardsTemplate<IndexT>::add_with_ids(
155
147
  "request them to be shifted");
156
148
  FAISS_THROW_IF_NOT_MSG(
157
149
  this->ntotal == 0,
158
- "when adding to IndexShards with sucessive_ids, "
150
+ "when adding to IndexShards with successive_ids, "
159
151
  "only add() in a single pass is supported");
160
152
  }
161
153
 
@@ -111,7 +111,7 @@ void IndexShardsIVF::add_with_ids(
111
111
  "request them to be shifted");
112
112
  FAISS_THROW_IF_NOT_MSG(
113
113
  this->ntotal == 0,
114
- "when adding to IndexShards with sucessive_ids, "
114
+ "when adding to IndexShards with successive_ids, "
115
115
  "only add() in a single pass is supported");
116
116
  }
117
117
 
@@ -137,7 +137,6 @@ void IndexShardsIVF::add_with_ids(
137
137
  auto fn = [n, ids, x, nshard, d, Iq](int no, Index* index) {
138
138
  idx_t i0 = (idx_t)no * n / nshard;
139
139
  idx_t i1 = ((idx_t)no + 1) * n / nshard;
140
- const float* x0 = x + i0 * d;
141
140
  auto index_ivf = dynamic_cast<IndexIVF*>(index);
142
141
 
143
142
  if (index->verbose) {
@@ -9,9 +9,10 @@
9
9
 
10
10
  #include <faiss/MatrixStats.h>
11
11
 
12
- #include <stdarg.h> /* va_list, va_start, va_arg, va_end */
12
+ #include <cstdarg> /* va_list, va_start, va_arg, va_end */
13
13
 
14
14
  #include <faiss/utils/utils.h>
15
+ #include <cinttypes>
15
16
  #include <cmath>
16
17
  #include <cstdio>
17
18
 
@@ -21,18 +22,6 @@ namespace faiss {
21
22
  * MatrixStats
22
23
  *********************************************************************/
23
24
 
24
- MatrixStats::PerDimStats::PerDimStats()
25
- : n(0),
26
- n_nan(0),
27
- n_inf(0),
28
- n0(0),
29
- min(HUGE_VALF),
30
- max(-HUGE_VALF),
31
- sum(0),
32
- sum2(0),
33
- mean(NAN),
34
- stddev(NAN) {}
35
-
36
25
  void MatrixStats::PerDimStats::add(float x) {
37
26
  n++;
38
27
  if (std::isnan(x)) {
@@ -74,19 +63,12 @@ void MatrixStats::do_comment(const char* fmt, ...) {
74
63
  buf += size;
75
64
  }
76
65
 
77
- MatrixStats::MatrixStats(size_t n, size_t d, const float* x)
78
- : n(n),
79
- d(d),
80
- n_collision(0),
81
- n_valid(0),
82
- n0(0),
83
- min_norm2(HUGE_VAL),
84
- max_norm2(0) {
66
+ MatrixStats::MatrixStats(size_t n, size_t d, const float* x) : n(n), d(d) {
85
67
  std::vector<char> comment_buf(10000);
86
68
  buf = comment_buf.data();
87
69
  nbuf = comment_buf.size();
88
70
 
89
- do_comment("analyzing %ld vectors of size %ld\n", n, d);
71
+ do_comment("analyzing %zd vectors of size %zd\n", n, d);
90
72
 
91
73
  if (d > 1024) {
92
74
  do_comment(
@@ -94,6 +76,9 @@ MatrixStats::MatrixStats(size_t n, size_t d, const float* x)
94
76
  "please consider dimensionality reducution (with PCAMatrix)\n");
95
77
  }
96
78
 
79
+ hash_value = hash_bytes((const uint8_t*)x, n * d * sizeof(*x));
80
+ do_comment("hash value 0x%016" PRIx64 "\n", hash_value);
81
+
97
82
  size_t nbytes = sizeof(x[0]) * d;
98
83
  per_dim_stats.resize(d);
99
84
 
@@ -156,7 +141,7 @@ MatrixStats::MatrixStats(size_t n, size_t d, const float* x)
156
141
 
157
142
  if (n_collision > 0) {
158
143
  do_comment(
159
- "%ld collisions in hash table, "
144
+ "%zd collisions in hash table, "
160
145
  "counts may be invalid\n",
161
146
  n_collision);
162
147
  }
@@ -167,14 +152,14 @@ MatrixStats::MatrixStats(size_t n, size_t d, const float* x)
167
152
  max = it->second;
168
153
  }
169
154
  }
170
- do_comment("vector %ld has %ld copies\n", max.first, max.count);
155
+ do_comment("vector %zd has %zd copies\n", max.first, max.count);
171
156
  }
172
157
 
173
158
  { // norm stats
174
159
  min_norm2 = sqrt(min_norm2);
175
160
  max_norm2 = sqrt(max_norm2);
176
161
  do_comment(
177
- "range of L2 norms=[%g, %g] (%ld null vectors)\n",
162
+ "range of L2 norms=[%g, %g] (%zd null vectors)\n",
178
163
  min_norm2,
179
164
  max_norm2,
180
165
  n0);
@@ -182,7 +167,7 @@ MatrixStats::MatrixStats(size_t n, size_t d, const float* x)
182
167
  if (max_norm2 < min_norm2 * 1.0001) {
183
168
  do_comment(
184
169
  "vectors are normalized, inner product and "
185
- "L2 search are equivalent\n");
170
+ "L2 search are equivalent\n");
186
171
  }
187
172
 
188
173
  if (max_norm2 > min_norm2 * 100) {
@@ -196,12 +181,12 @@ MatrixStats::MatrixStats(size_t n, size_t d, const float* x)
196
181
 
197
182
  double max_std = 0, min_std = HUGE_VAL;
198
183
 
199
- size_t n_dangerous_range = 0, n_0_range = 0, n0 = 0;
184
+ size_t n_dangerous_range = 0, n_0_range = 0, n0_2 = 0;
200
185
 
201
186
  for (size_t j = 0; j < d; j++) {
202
187
  PerDimStats& st = per_dim_stats[j];
203
188
  st.compute_mean_std();
204
- n0 += st.n0;
189
+ n0_2 += st.n0;
205
190
 
206
191
  if (st.max == st.min) {
207
192
  n_0_range++;
@@ -215,19 +200,19 @@ MatrixStats::MatrixStats(size_t n, size_t d, const float* x)
215
200
  min_std = st.stddev;
216
201
  }
217
202
 
218
- if (n0 == 0) {
203
+ if (n0_2 == 0) {
219
204
  do_comment("matrix contains no 0s\n");
220
205
  } else {
221
206
  do_comment(
222
207
  "matrix contains %.2f %% 0 entries\n",
223
- n0 * 100.0 / (n * d));
208
+ n0_2 * 100.0 / (n * d));
224
209
  }
225
210
 
226
211
  if (n_0_range == 0) {
227
212
  do_comment("no constant dimensions\n");
228
213
  } else {
229
214
  do_comment(
230
- "%ld dimensions are constant: they can be removed\n",
215
+ "%zd dimensions are constant: they can be removed\n",
231
216
  n_0_range);
232
217
  }
233
218
 
@@ -235,7 +220,7 @@ MatrixStats::MatrixStats(size_t n, size_t d, const float* x)
235
220
  do_comment("no dimension has a too large mean\n");
236
221
  } else {
237
222
  do_comment(
238
- "%ld dimensions are too large "
223
+ "%zd dimensions are too large "
239
224
  "wrt. their variance, may loose precision "
240
225
  "in IndexFlatL2 (use CenteringTransform)\n",
241
226
  n_dangerous_range);
@@ -10,6 +10,7 @@
10
10
  #pragma once
11
11
 
12
12
  #include <stdint.h>
13
+ #include <cmath>
13
14
  #include <string>
14
15
  #include <unordered_map>
15
16
  #include <vector>
@@ -26,20 +27,31 @@ struct MatrixStats {
26
27
  std::string comments;
27
28
 
28
29
  // raw statistics
29
- size_t n, d;
30
- size_t n_collision, n_valid, n0;
31
- double min_norm2, max_norm2;
30
+ size_t n = 0, d = 0;
31
+ size_t n_collision = 0;
32
+ size_t n_valid = 0;
33
+ size_t n0 = 0;
34
+ double min_norm2 = HUGE_VALF;
35
+ double max_norm2 = 0;
36
+ uint64_t hash_value = 0;
32
37
 
33
38
  struct PerDimStats {
34
- size_t n, n_nan, n_inf, n0;
39
+ /// counts of various special entries
40
+ size_t n = 0;
41
+ size_t n_nan = 0;
42
+ size_t n_inf = 0;
43
+ size_t n0 = 0;
35
44
 
36
- float min, max;
37
- double sum, sum2;
45
+ /// to get min/max and stddev values
46
+ float min = HUGE_VALF;
47
+ float max = -HUGE_VALF;
48
+ double sum = 0;
49
+ double sum2 = 0;
38
50
 
39
- size_t n_valid;
40
- double mean, stddev;
51
+ size_t n_valid = 0;
52
+ double mean = NAN;
53
+ double stddev = NAN;
41
54
 
42
- PerDimStats();
43
55
  void add(float x);
44
56
  void compute_mean_std();
45
57
  };
@@ -9,8 +9,8 @@
9
9
 
10
10
  #include <faiss/MetaIndexes.h>
11
11
 
12
- #include <stdint.h>
13
12
  #include <cinttypes>
13
+ #include <cstdint>
14
14
  #include <cstdio>
15
15
  #include <limits>
16
16
 
@@ -70,37 +70,37 @@ void IndexSplitVectors::search(
70
70
  sum_d == d, "not enough indexes compared to # dimensions");
71
71
 
72
72
  int64_t nshard = sub_indexes.size();
73
- float* all_distances = new float[nshard * k * n];
74
- idx_t* all_labels = new idx_t[nshard * k * n];
75
- ScopeDeleter<float> del(all_distances);
76
- ScopeDeleter<idx_t> del2(all_labels);
77
-
78
- auto query_func = [n,
79
- x,
80
- k,
81
- distances,
82
- labels,
83
- all_distances,
84
- all_labels,
85
- this](int no) {
86
- const IndexSplitVectors* index = this;
87
- float* distances1 = no == 0 ? distances : all_distances + no * k * n;
88
- idx_t* labels1 = no == 0 ? labels : all_labels + no * k * n;
89
- if (index->verbose)
90
- printf("begin query shard %d on %" PRId64 " points\n", no, n);
91
- const Index* sub_index = index->sub_indexes[no];
92
- int64_t sub_d = sub_index->d, d = index->d;
93
- idx_t ofs = 0;
94
- for (int i = 0; i < no; i++)
95
- ofs += index->sub_indexes[i]->d;
96
- float* sub_x = new float[sub_d * n];
97
- ScopeDeleter<float> del1(sub_x);
98
- for (idx_t i = 0; i < n; i++)
99
- memcpy(sub_x + i * sub_d, x + ofs + i * d, sub_d * sizeof(sub_x));
100
- sub_index->search(n, sub_x, k, distances1, labels1);
101
- if (index->verbose)
102
- printf("end query shard %d\n", no);
103
- };
73
+
74
+ std::unique_ptr<float[]> all_distances(new float[nshard * k * n]);
75
+ std::unique_ptr<idx_t[]> all_labels(new idx_t[nshard * k * n]);
76
+
77
+ auto query_func =
78
+ [n, x, k, distances, labels, &all_distances, &all_labels, this](
79
+ int no) {
80
+ const IndexSplitVectors* index = this;
81
+ float* distances1 =
82
+ no == 0 ? distances : all_distances.get() + no * k * n;
83
+ idx_t* labels1 =
84
+ no == 0 ? labels : all_labels.get() + no * k * n;
85
+ if (index->verbose)
86
+ printf("begin query shard %d on %" PRId64 " points\n",
87
+ no,
88
+ n);
89
+ const Index* sub_index = index->sub_indexes[no];
90
+ int64_t sub_d = sub_index->d, d = index->d;
91
+ idx_t ofs = 0;
92
+ for (int i = 0; i < no; i++)
93
+ ofs += index->sub_indexes[i]->d;
94
+
95
+ std::unique_ptr<float[]> sub_x(new float[sub_d * n]);
96
+ for (idx_t i = 0; i < n; i++)
97
+ memcpy(sub_x.get() + i * sub_d,
98
+ x + ofs + i * d,
99
+ sub_d * sizeof(float));
100
+ sub_index->search(n, sub_x.get(), k, distances1, labels1);
101
+ if (index->verbose)
102
+ printf("end query shard %d\n", no);
103
+ };
104
104
 
105
105
  if (!threaded) {
106
106
  for (int i = 0; i < nshard; i++) {
@@ -125,8 +125,8 @@ void IndexSplitVectors::search(
125
125
  int64_t factor = 1;
126
126
  for (int i = 0; i < nshard; i++) {
127
127
  if (i > 0) { // results of 0 are already in the table
128
- const float* distances_i = all_distances + i * k * n;
129
- const idx_t* labels_i = all_labels + i * k * n;
128
+ const float* distances_i = all_distances.get() + i * k * n;
129
+ const idx_t* labels_i = all_labels.get() + i * k * n;
130
130
  for (int64_t j = 0; j < n; j++) {
131
131
  if (labels[j] >= 0 && labels_i[j] >= 0) {
132
132
  labels[j] += labels_i[j] * factor;
@@ -238,6 +238,6 @@ void IndexRandom::reset() {
238
238
  ntotal = 0;
239
239
  }
240
240
 
241
- IndexRandom::~IndexRandom() {}
241
+ IndexRandom::~IndexRandom() = default;
242
242
 
243
243
  } // namespace faiss
@@ -441,13 +441,10 @@ void eig(size_t d_in, double* cov, double* eigenvalues, int verbose) {
441
441
 
442
442
  } // namespace
443
443
 
444
- void PCAMatrix::train(idx_t n, const float* x) {
445
- const float* x_in = x;
446
-
447
- x = fvecs_maybe_subsample(
448
- d_in, (size_t*)&n, max_points_per_d * d_in, x, verbose);
449
-
450
- ScopeDeleter<float> del_x(x != x_in ? x : nullptr);
444
+ void PCAMatrix::train(idx_t n, const float* x_in) {
445
+ const float* x = fvecs_maybe_subsample(
446
+ d_in, (size_t*)&n, max_points_per_d * d_in, x_in, verbose);
447
+ TransformedVectors tv(x_in, x);
451
448
 
452
449
  // compute mean
453
450
  mean.clear();
@@ -884,14 +881,13 @@ ITQTransform::ITQTransform(int d_in, int d_out, bool do_pca)
884
881
  is_trained = false;
885
882
  }
886
883
 
887
- void ITQTransform::train(idx_t n, const float* x) {
884
+ void ITQTransform::train(idx_t n, const float* x_in) {
888
885
  FAISS_THROW_IF_NOT(!is_trained);
889
886
 
890
- const float* x_in = x;
891
887
  size_t max_train_points = std::max(d_in * max_train_per_dim, 32768);
892
- x = fvecs_maybe_subsample(d_in, (size_t*)&n, max_train_points, x);
893
-
894
- ScopeDeleter<float> del_x(x != x_in ? x : nullptr);
888
+ const float* x =
889
+ fvecs_maybe_subsample(d_in, (size_t*)&n, max_train_points, x_in);
890
+ TransformedVectors tv(x_in, x);
895
891
 
896
892
  std::unique_ptr<float[]> x_norm(new float[n * d_in]);
897
893
  { // normalize
@@ -988,25 +984,16 @@ void ITQTransform::check_identical(const VectorTransform& other_in) const {
988
984
  *********************************************/
989
985
 
990
986
  OPQMatrix::OPQMatrix(int d, int M, int d2)
991
- : LinearTransform(d, d2 == -1 ? d : d2, false),
992
- M(M),
993
- niter(50),
994
- niter_pq(4),
995
- niter_pq_0(40),
996
- verbose(false),
997
- pq(nullptr) {
987
+ : LinearTransform(d, d2 == -1 ? d : d2, false), M(M) {
998
988
  is_trained = false;
999
989
  // OPQ is quite expensive to train, so set this right.
1000
990
  max_train_points = 256 * 256;
1001
- pq = nullptr;
1002
991
  }
1003
992
 
1004
- void OPQMatrix::train(idx_t n, const float* x) {
1005
- const float* x_in = x;
1006
-
1007
- x = fvecs_maybe_subsample(d_in, (size_t*)&n, max_train_points, x, verbose);
1008
-
1009
- ScopeDeleter<float> del_x(x != x_in ? x : nullptr);
993
+ void OPQMatrix::train(idx_t n, const float* x_in) {
994
+ const float* x = fvecs_maybe_subsample(
995
+ d_in, (size_t*)&n, max_train_points, x_in, verbose);
996
+ TransformedVectors tv(x_in, x);
1010
997
 
1011
998
  // To support d_out > d_in, we pad input vectors with 0s to d_out
1012
999
  size_t d = d_out <= d_in ? d_in : d_out;