faiss 0.3.0 → 0.3.2

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 (216) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -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 +1 -2
  12. data/vendor/faiss/faiss/Clustering.cpp +39 -22
  13. data/vendor/faiss/faiss/Clustering.h +40 -21
  14. data/vendor/faiss/faiss/IVFlib.cpp +26 -12
  15. data/vendor/faiss/faiss/Index.cpp +1 -1
  16. data/vendor/faiss/faiss/Index.h +40 -10
  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/IndexBinaryHNSW.h +1 -1
  25. data/vendor/faiss/faiss/IndexBinaryHash.cpp +25 -50
  26. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +107 -188
  27. data/vendor/faiss/faiss/IndexFastScan.cpp +95 -146
  28. data/vendor/faiss/faiss/IndexFastScan.h +9 -8
  29. data/vendor/faiss/faiss/IndexFlat.cpp +206 -10
  30. data/vendor/faiss/faiss/IndexFlat.h +20 -1
  31. data/vendor/faiss/faiss/IndexFlatCodes.cpp +170 -5
  32. data/vendor/faiss/faiss/IndexFlatCodes.h +23 -4
  33. data/vendor/faiss/faiss/IndexHNSW.cpp +231 -382
  34. data/vendor/faiss/faiss/IndexHNSW.h +62 -49
  35. data/vendor/faiss/faiss/IndexIDMap.cpp +69 -28
  36. data/vendor/faiss/faiss/IndexIDMap.h +24 -2
  37. data/vendor/faiss/faiss/IndexIVF.cpp +162 -56
  38. data/vendor/faiss/faiss/IndexIVF.h +46 -6
  39. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +33 -26
  40. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.h +6 -2
  41. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +19 -46
  42. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.h +4 -3
  43. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +502 -401
  44. data/vendor/faiss/faiss/IndexIVFFastScan.h +63 -26
  45. data/vendor/faiss/faiss/IndexIVFFlat.cpp +15 -5
  46. data/vendor/faiss/faiss/IndexIVFFlat.h +3 -2
  47. data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +172 -0
  48. data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.h +56 -0
  49. data/vendor/faiss/faiss/IndexIVFPQ.cpp +79 -125
  50. data/vendor/faiss/faiss/IndexIVFPQ.h +6 -7
  51. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +39 -52
  52. data/vendor/faiss/faiss/IndexIVFPQFastScan.h +4 -3
  53. data/vendor/faiss/faiss/IndexIVFPQR.cpp +45 -29
  54. data/vendor/faiss/faiss/IndexIVFPQR.h +5 -2
  55. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +25 -27
  56. data/vendor/faiss/faiss/IndexIVFSpectralHash.h +6 -6
  57. data/vendor/faiss/faiss/IndexLSH.cpp +14 -16
  58. data/vendor/faiss/faiss/IndexLattice.cpp +1 -19
  59. data/vendor/faiss/faiss/IndexLattice.h +3 -22
  60. data/vendor/faiss/faiss/IndexNNDescent.cpp +3 -33
  61. data/vendor/faiss/faiss/IndexNNDescent.h +1 -1
  62. data/vendor/faiss/faiss/IndexNSG.cpp +11 -27
  63. data/vendor/faiss/faiss/IndexNSG.h +11 -11
  64. data/vendor/faiss/faiss/IndexNeuralNetCodec.cpp +56 -0
  65. data/vendor/faiss/faiss/IndexNeuralNetCodec.h +49 -0
  66. data/vendor/faiss/faiss/IndexPQ.cpp +72 -88
  67. data/vendor/faiss/faiss/IndexPQ.h +1 -4
  68. data/vendor/faiss/faiss/IndexPQFastScan.cpp +1 -1
  69. data/vendor/faiss/faiss/IndexPreTransform.cpp +25 -31
  70. data/vendor/faiss/faiss/IndexPreTransform.h +1 -1
  71. data/vendor/faiss/faiss/IndexRefine.cpp +54 -24
  72. data/vendor/faiss/faiss/IndexRefine.h +7 -0
  73. data/vendor/faiss/faiss/IndexReplicas.cpp +23 -26
  74. data/vendor/faiss/faiss/IndexScalarQuantizer.cpp +25 -17
  75. data/vendor/faiss/faiss/IndexScalarQuantizer.h +6 -4
  76. data/vendor/faiss/faiss/IndexShards.cpp +21 -29
  77. data/vendor/faiss/faiss/IndexShardsIVF.cpp +1 -2
  78. data/vendor/faiss/faiss/MatrixStats.cpp +17 -32
  79. data/vendor/faiss/faiss/MatrixStats.h +21 -9
  80. data/vendor/faiss/faiss/MetaIndexes.cpp +35 -35
  81. data/vendor/faiss/faiss/MetricType.h +7 -2
  82. data/vendor/faiss/faiss/VectorTransform.cpp +13 -26
  83. data/vendor/faiss/faiss/VectorTransform.h +7 -7
  84. data/vendor/faiss/faiss/clone_index.cpp +15 -10
  85. data/vendor/faiss/faiss/clone_index.h +3 -0
  86. data/vendor/faiss/faiss/cppcontrib/detail/UintReader.h +95 -17
  87. data/vendor/faiss/faiss/cppcontrib/factory_tools.cpp +152 -0
  88. data/vendor/faiss/faiss/cppcontrib/factory_tools.h +24 -0
  89. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-inl.h +83 -30
  90. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +123 -8
  91. data/vendor/faiss/faiss/gpu/GpuCloner.h +22 -0
  92. data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +13 -0
  93. data/vendor/faiss/faiss/gpu/GpuDistance.h +46 -38
  94. data/vendor/faiss/faiss/gpu/GpuFaissAssert.h +1 -1
  95. data/vendor/faiss/faiss/gpu/GpuIndex.h +30 -12
  96. data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +282 -0
  97. data/vendor/faiss/faiss/gpu/GpuIndexFlat.h +4 -4
  98. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +14 -9
  99. data/vendor/faiss/faiss/gpu/GpuIndexIVFFlat.h +20 -3
  100. data/vendor/faiss/faiss/gpu/GpuIndexIVFPQ.h +22 -11
  101. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +1 -3
  102. data/vendor/faiss/faiss/gpu/GpuResources.cpp +24 -3
  103. data/vendor/faiss/faiss/gpu/GpuResources.h +39 -11
  104. data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +142 -17
  105. data/vendor/faiss/faiss/gpu/StandardGpuResources.h +57 -3
  106. data/vendor/faiss/faiss/gpu/impl/InterleavedCodes.cpp +26 -21
  107. data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +7 -1
  108. data/vendor/faiss/faiss/gpu/test/TestCodePacking.cpp +8 -5
  109. data/vendor/faiss/faiss/gpu/test/TestGpuIndexBinaryFlat.cpp +25 -0
  110. data/vendor/faiss/faiss/gpu/test/TestGpuIndexFlat.cpp +129 -9
  111. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +332 -40
  112. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFPQ.cpp +299 -208
  113. data/vendor/faiss/faiss/gpu/test/TestGpuMemoryException.cpp +1 -0
  114. data/vendor/faiss/faiss/gpu/test/demo_ivfpq_indexing_gpu.cpp +1 -1
  115. data/vendor/faiss/faiss/gpu/utils/DeviceUtils.h +6 -0
  116. data/vendor/faiss/faiss/gpu/utils/RaftUtils.h +75 -0
  117. data/vendor/faiss/faiss/gpu/utils/Timer.cpp +4 -1
  118. data/vendor/faiss/faiss/gpu/utils/Timer.h +1 -1
  119. data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +3 -1
  120. data/vendor/faiss/faiss/impl/AdditiveQuantizer.h +5 -5
  121. data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +26 -1
  122. data/vendor/faiss/faiss/impl/AuxIndexStructures.h +10 -3
  123. data/vendor/faiss/faiss/impl/DistanceComputer.h +70 -1
  124. data/vendor/faiss/faiss/impl/FaissAssert.h +4 -2
  125. data/vendor/faiss/faiss/impl/FaissException.h +13 -34
  126. data/vendor/faiss/faiss/impl/HNSW.cpp +605 -186
  127. data/vendor/faiss/faiss/impl/HNSW.h +52 -30
  128. data/vendor/faiss/faiss/impl/IDSelector.h +4 -4
  129. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +11 -9
  130. data/vendor/faiss/faiss/impl/LookupTableScaler.h +34 -0
  131. data/vendor/faiss/faiss/impl/NNDescent.cpp +42 -27
  132. data/vendor/faiss/faiss/impl/NSG.cpp +0 -29
  133. data/vendor/faiss/faiss/impl/NSG.h +1 -1
  134. data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +14 -12
  135. data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.h +1 -1
  136. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +25 -22
  137. data/vendor/faiss/faiss/impl/ProductQuantizer.h +6 -2
  138. data/vendor/faiss/faiss/impl/Quantizer.h +1 -1
  139. data/vendor/faiss/faiss/impl/ResidualQuantizer.cpp +27 -1015
  140. data/vendor/faiss/faiss/impl/ResidualQuantizer.h +5 -63
  141. data/vendor/faiss/faiss/impl/ResultHandler.h +347 -172
  142. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +1104 -147
  143. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +3 -8
  144. data/vendor/faiss/faiss/impl/code_distance/code_distance-avx2.h +285 -42
  145. data/vendor/faiss/faiss/impl/code_distance/code_distance-avx512.h +248 -0
  146. data/vendor/faiss/faiss/impl/code_distance/code_distance-generic.h +21 -14
  147. data/vendor/faiss/faiss/impl/code_distance/code_distance.h +22 -12
  148. data/vendor/faiss/faiss/impl/index_read.cpp +74 -34
  149. data/vendor/faiss/faiss/impl/index_read_utils.h +37 -0
  150. data/vendor/faiss/faiss/impl/index_write.cpp +88 -51
  151. data/vendor/faiss/faiss/impl/io.cpp +23 -15
  152. data/vendor/faiss/faiss/impl/io.h +4 -4
  153. data/vendor/faiss/faiss/impl/io_macros.h +6 -0
  154. data/vendor/faiss/faiss/impl/lattice_Zn.cpp +1 -1
  155. data/vendor/faiss/faiss/impl/platform_macros.h +40 -1
  156. data/vendor/faiss/faiss/impl/pq4_fast_scan.cpp +14 -0
  157. data/vendor/faiss/faiss/impl/pq4_fast_scan.h +7 -6
  158. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_1.cpp +52 -38
  159. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_qbs.cpp +487 -49
  160. data/vendor/faiss/faiss/impl/residual_quantizer_encode_steps.cpp +960 -0
  161. data/vendor/faiss/faiss/impl/residual_quantizer_encode_steps.h +176 -0
  162. data/vendor/faiss/faiss/impl/simd_result_handlers.h +481 -225
  163. data/vendor/faiss/faiss/index_factory.cpp +41 -20
  164. data/vendor/faiss/faiss/index_io.h +12 -5
  165. data/vendor/faiss/faiss/invlists/BlockInvertedLists.cpp +28 -8
  166. data/vendor/faiss/faiss/invlists/BlockInvertedLists.h +3 -0
  167. data/vendor/faiss/faiss/invlists/DirectMap.cpp +10 -2
  168. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +73 -17
  169. data/vendor/faiss/faiss/invlists/InvertedLists.h +26 -8
  170. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +24 -9
  171. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.h +2 -1
  172. data/vendor/faiss/faiss/python/python_callbacks.cpp +4 -4
  173. data/vendor/faiss/faiss/utils/Heap.cpp +3 -1
  174. data/vendor/faiss/faiss/utils/Heap.h +105 -0
  175. data/vendor/faiss/faiss/utils/NeuralNet.cpp +342 -0
  176. data/vendor/faiss/faiss/utils/NeuralNet.h +147 -0
  177. data/vendor/faiss/faiss/utils/WorkerThread.h +1 -0
  178. data/vendor/faiss/faiss/utils/bf16.h +36 -0
  179. data/vendor/faiss/faiss/utils/distances.cpp +147 -123
  180. data/vendor/faiss/faiss/utils/distances.h +86 -9
  181. data/vendor/faiss/faiss/utils/distances_fused/avx512.cpp +5 -5
  182. data/vendor/faiss/faiss/utils/distances_fused/avx512.h +2 -2
  183. data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +2 -2
  184. data/vendor/faiss/faiss/utils/distances_fused/distances_fused.h +1 -1
  185. data/vendor/faiss/faiss/utils/distances_fused/simdlib_based.cpp +5 -5
  186. data/vendor/faiss/faiss/utils/distances_fused/simdlib_based.h +1 -1
  187. data/vendor/faiss/faiss/utils/distances_simd.cpp +1589 -243
  188. data/vendor/faiss/faiss/utils/extra_distances-inl.h +70 -0
  189. data/vendor/faiss/faiss/utils/extra_distances.cpp +85 -137
  190. data/vendor/faiss/faiss/utils/extra_distances.h +3 -2
  191. data/vendor/faiss/faiss/utils/fp16-arm.h +29 -0
  192. data/vendor/faiss/faiss/utils/fp16.h +2 -0
  193. data/vendor/faiss/faiss/utils/hamming.cpp +163 -111
  194. data/vendor/faiss/faiss/utils/hamming.h +58 -0
  195. data/vendor/faiss/faiss/utils/hamming_distance/avx2-inl.h +16 -89
  196. data/vendor/faiss/faiss/utils/hamming_distance/common.h +1 -0
  197. data/vendor/faiss/faiss/utils/hamming_distance/generic-inl.h +19 -88
  198. data/vendor/faiss/faiss/utils/hamming_distance/hamdis-inl.h +58 -0
  199. data/vendor/faiss/faiss/utils/hamming_distance/neon-inl.h +14 -104
  200. data/vendor/faiss/faiss/utils/partitioning.cpp +3 -4
  201. data/vendor/faiss/faiss/utils/prefetch.h +77 -0
  202. data/vendor/faiss/faiss/utils/quantize_lut.cpp +0 -14
  203. data/vendor/faiss/faiss/utils/random.cpp +43 -0
  204. data/vendor/faiss/faiss/utils/random.h +25 -0
  205. data/vendor/faiss/faiss/utils/simdlib.h +10 -1
  206. data/vendor/faiss/faiss/utils/simdlib_avx2.h +0 -6
  207. data/vendor/faiss/faiss/utils/simdlib_avx512.h +296 -0
  208. data/vendor/faiss/faiss/utils/simdlib_neon.h +77 -79
  209. data/vendor/faiss/faiss/utils/simdlib_ppc64.h +1084 -0
  210. data/vendor/faiss/faiss/utils/sorting.cpp +140 -5
  211. data/vendor/faiss/faiss/utils/sorting.h +27 -0
  212. data/vendor/faiss/faiss/utils/transpose/transpose-avx512-inl.h +176 -0
  213. data/vendor/faiss/faiss/utils/utils.cpp +120 -7
  214. data/vendor/faiss/faiss/utils/utils.h +60 -20
  215. metadata +23 -4
  216. data/vendor/faiss/faiss/impl/code_distance/code_distance_avx512.h +0 -102
@@ -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
  #pragma once
11
9
 
12
10
  #include <queue>
@@ -42,10 +40,13 @@ namespace faiss {
42
40
  struct VisitedTable;
43
41
  struct DistanceComputer; // from AuxIndexStructures
44
42
  struct HNSWStats;
43
+ template <class C>
44
+ struct ResultHandler;
45
45
 
46
46
  struct SearchParametersHNSW : SearchParameters {
47
47
  int efSearch = 16;
48
48
  bool check_relative_distance = true;
49
+ bool bounded_queue = true;
49
50
 
50
51
  ~SearchParametersHNSW() {}
51
52
  };
@@ -54,6 +55,9 @@ struct HNSW {
54
55
  /// internal storage of vectors (32 bits: this is expensive)
55
56
  using storage_idx_t = int32_t;
56
57
 
58
+ // for now we do only these distances
59
+ using C = CMax<float, int64_t>;
60
+
57
61
  typedef std::pair<float, storage_idx_t> Node;
58
62
 
59
63
  /** Heap structure that allows fast
@@ -138,9 +142,6 @@ struct HNSW {
138
142
  /// enough?
139
143
  bool check_relative_distance = true;
140
144
 
141
- /// number of entry points in levels > 0.
142
- int upper_beam = 1;
143
-
144
145
  /// use bounded queue during exploration
145
146
  bool search_bounded_queue = true;
146
147
 
@@ -181,7 +182,8 @@ struct HNSW {
181
182
  float d_nearest,
182
183
  int level,
183
184
  omp_lock_t* locks,
184
- VisitedTable& vt);
185
+ VisitedTable& vt,
186
+ bool keep_max_size_level0 = false);
185
187
 
186
188
  /** add point pt_id on all levels <= pt_level and build the link
187
189
  * structure for them. */
@@ -190,29 +192,27 @@ struct HNSW {
190
192
  int pt_level,
191
193
  int pt_id,
192
194
  std::vector<omp_lock_t>& locks,
193
- VisitedTable& vt);
195
+ VisitedTable& vt,
196
+ bool keep_max_size_level0 = false);
194
197
 
195
198
  /// search interface for 1 point, single thread
196
199
  HNSWStats search(
197
200
  DistanceComputer& qdis,
198
- int k,
199
- idx_t* I,
200
- float* D,
201
+ ResultHandler<C>& res,
201
202
  VisitedTable& vt,
202
203
  const SearchParametersHNSW* params = nullptr) const;
203
204
 
204
205
  /// search only in level 0 from a given vertex
205
206
  void search_level_0(
206
207
  DistanceComputer& qdis,
207
- int k,
208
- idx_t* idxi,
209
- float* simi,
208
+ ResultHandler<C>& res,
210
209
  idx_t nprobe,
211
210
  const storage_idx_t* nearest_i,
212
211
  const float* nearest_d,
213
212
  int search_type,
214
213
  HNSWStats& search_stats,
215
- VisitedTable& vt) const;
214
+ VisitedTable& vt,
215
+ const SearchParametersHNSW* params = nullptr) const;
216
216
 
217
217
  void reset();
218
218
 
@@ -225,38 +225,60 @@ struct HNSW {
225
225
  DistanceComputer& qdis,
226
226
  std::priority_queue<NodeDistFarther>& input,
227
227
  std::vector<NodeDistFarther>& output,
228
- int max_size);
228
+ int max_size,
229
+ bool keep_max_size_level0 = false);
230
+
231
+ void permute_entries(const idx_t* map);
229
232
  };
230
233
 
231
234
  struct HNSWStats {
232
- size_t n1, n2, n3;
233
- size_t ndis;
234
- size_t nreorder;
235
-
236
- HNSWStats(
237
- size_t n1 = 0,
238
- size_t n2 = 0,
239
- size_t n3 = 0,
240
- size_t ndis = 0,
241
- size_t nreorder = 0)
242
- : n1(n1), n2(n2), n3(n3), ndis(ndis), nreorder(nreorder) {}
235
+ size_t n1 = 0; /// number of vectors searched
236
+ size_t n2 =
237
+ 0; /// number of queries for which the candidate list is exhausted
238
+ size_t ndis = 0; /// number of distances computed
239
+ size_t nhops = 0; /// number of hops aka number of edges traversed
243
240
 
244
241
  void reset() {
245
- n1 = n2 = n3 = 0;
242
+ n1 = n2 = 0;
246
243
  ndis = 0;
247
- nreorder = 0;
244
+ nhops = 0;
248
245
  }
249
246
 
250
247
  void combine(const HNSWStats& other) {
251
248
  n1 += other.n1;
252
249
  n2 += other.n2;
253
- n3 += other.n3;
254
250
  ndis += other.ndis;
255
- nreorder += other.nreorder;
251
+ nhops += other.nhops;
256
252
  }
257
253
  };
258
254
 
259
255
  // global var that collects them all
260
256
  FAISS_API extern HNSWStats hnsw_stats;
261
257
 
258
+ int search_from_candidates(
259
+ const HNSW& hnsw,
260
+ DistanceComputer& qdis,
261
+ ResultHandler<HNSW::C>& res,
262
+ HNSW::MinimaxHeap& candidates,
263
+ VisitedTable& vt,
264
+ HNSWStats& stats,
265
+ int level,
266
+ int nres_in = 0,
267
+ const SearchParametersHNSW* params = nullptr);
268
+
269
+ HNSWStats greedy_update_nearest(
270
+ const HNSW& hnsw,
271
+ DistanceComputer& qdis,
272
+ int level,
273
+ HNSW::storage_idx_t& nearest,
274
+ float& d_nearest);
275
+
276
+ std::priority_queue<HNSW::Node> search_from_candidate_unbounded(
277
+ const HNSW& hnsw,
278
+ const HNSW::Node& node,
279
+ DistanceComputer& qdis,
280
+ int ef,
281
+ VisitedTable* vt,
282
+ HNSWStats& stats);
283
+
262
284
  } // namespace faiss
@@ -10,7 +10,7 @@
10
10
  #include <unordered_set>
11
11
  #include <vector>
12
12
 
13
- #include <faiss/Index.h>
13
+ #include <faiss/MetricType.h>
14
14
 
15
15
  /** IDSelector is intended to define a subset of vectors to handle (for removal
16
16
  * or as subset to search) */
@@ -140,7 +140,7 @@ struct IDSelectorAnd : IDSelector {
140
140
  : lhs(lhs), rhs(rhs) {}
141
141
  bool is_member(idx_t id) const final {
142
142
  return lhs->is_member(id) && rhs->is_member(id);
143
- };
143
+ }
144
144
  virtual ~IDSelectorAnd() {}
145
145
  };
146
146
 
@@ -153,7 +153,7 @@ struct IDSelectorOr : IDSelector {
153
153
  : lhs(lhs), rhs(rhs) {}
154
154
  bool is_member(idx_t id) const final {
155
155
  return lhs->is_member(id) || rhs->is_member(id);
156
- };
156
+ }
157
157
  virtual ~IDSelectorOr() {}
158
158
  };
159
159
 
@@ -166,7 +166,7 @@ struct IDSelectorXOr : IDSelector {
166
166
  : lhs(lhs), rhs(rhs) {}
167
167
  bool is_member(idx_t id) const final {
168
168
  return lhs->is_member(id) ^ rhs->is_member(id);
169
- };
169
+ }
170
170
  virtual ~IDSelectorXOr() {}
171
171
  };
172
172
 
@@ -104,10 +104,10 @@ int dgemm_(
104
104
 
105
105
  namespace {
106
106
 
107
- void fmat_inverse(float* a, int n) {
108
- int info;
109
- int lwork = n * n;
110
- std::vector<int> ipiv(n);
107
+ void fmat_inverse(float* a, FINTEGER n) {
108
+ FINTEGER info;
109
+ FINTEGER lwork = n * n;
110
+ std::vector<FINTEGER> ipiv(n);
111
111
  std::vector<float> workspace(lwork);
112
112
 
113
113
  sgetrf_(&n, &n, a, &n, ipiv.data(), &info);
@@ -123,10 +123,10 @@ void dfvec_add(size_t d, const double* a, const float* b, double* c) {
123
123
  }
124
124
  }
125
125
 
126
- void dmat_inverse(double* a, int n) {
127
- int info;
128
- int lwork = n * n;
129
- std::vector<int> ipiv(n);
126
+ void dmat_inverse(double* a, FINTEGER n) {
127
+ FINTEGER info;
128
+ FINTEGER lwork = n * n;
129
+ std::vector<FINTEGER> ipiv(n);
130
130
  std::vector<double> workspace(lwork);
131
131
 
132
132
  dgetrf_(&n, &n, a, &n, ipiv.data(), &info);
@@ -628,7 +628,9 @@ void LocalSearchQuantizer::icm_encode_step(
628
628
  {
629
629
  size_t binary_idx = (other_m + 1) * M * K * K +
630
630
  m * K * K + code2 * K + code;
631
- _mm_prefetch(binaries + binary_idx, _MM_HINT_T0);
631
+ _mm_prefetch(
632
+ (const char*)(binaries + binary_idx),
633
+ _MM_HINT_T0);
632
634
  }
633
635
  }
634
636
  #endif
@@ -38,6 +38,23 @@ struct DummyScaler {
38
38
  return simd16uint16(0);
39
39
  }
40
40
 
41
+ #ifdef __AVX512F__
42
+ inline simd64uint8 lookup(const simd64uint8&, const simd64uint8&) const {
43
+ FAISS_THROW_MSG("DummyScaler::lookup should not be called.");
44
+ return simd64uint8(0);
45
+ }
46
+
47
+ inline simd32uint16 scale_lo(const simd64uint8&) const {
48
+ FAISS_THROW_MSG("DummyScaler::scale_lo should not be called.");
49
+ return simd32uint16(0);
50
+ }
51
+
52
+ inline simd32uint16 scale_hi(const simd64uint8&) const {
53
+ FAISS_THROW_MSG("DummyScaler::scale_hi should not be called.");
54
+ return simd32uint16(0);
55
+ }
56
+ #endif
57
+
41
58
  template <class dist_t>
42
59
  inline dist_t scale_one(const dist_t&) const {
43
60
  FAISS_THROW_MSG("DummyScaler::scale_one should not be called.");
@@ -67,6 +84,23 @@ struct NormTableScaler {
67
84
  return (simd16uint16(res) >> 8) * scale_simd;
68
85
  }
69
86
 
87
+ #ifdef __AVX512F__
88
+ inline simd64uint8 lookup(const simd64uint8& lut, const simd64uint8& c)
89
+ const {
90
+ return lut.lookup_4_lanes(c);
91
+ }
92
+
93
+ inline simd32uint16 scale_lo(const simd64uint8& res) const {
94
+ auto scale_simd_wide = simd32uint16(scale_simd, scale_simd);
95
+ return simd32uint16(res) * scale_simd_wide;
96
+ }
97
+
98
+ inline simd32uint16 scale_hi(const simd64uint8& res) const {
99
+ auto scale_simd_wide = simd32uint16(scale_simd, scale_simd);
100
+ return (simd32uint16(res) >> 8) * scale_simd_wide;
101
+ }
102
+ #endif
103
+
70
104
  // for non-SIMD implem 2, 3, 4
71
105
  template <class dist_t>
72
106
  inline dist_t scale_one(const dist_t& x) const {
@@ -154,15 +154,20 @@ NNDescent::NNDescent(const int d, const int K) : K(K), d(d) {
154
154
  NNDescent::~NNDescent() {}
155
155
 
156
156
  void NNDescent::join(DistanceComputer& qdis) {
157
+ idx_t check_period = InterruptCallback::get_period_hint(d * search_L);
158
+ for (idx_t i0 = 0; i0 < (idx_t)ntotal; i0 += check_period) {
159
+ idx_t i1 = std::min(i0 + check_period, (idx_t)ntotal);
157
160
  #pragma omp parallel for default(shared) schedule(dynamic, 100)
158
- for (int n = 0; n < ntotal; n++) {
159
- graph[n].join([&](int i, int j) {
160
- if (i != j) {
161
- float dist = qdis.symmetric_dis(i, j);
162
- graph[i].insert(j, dist);
163
- graph[j].insert(i, dist);
164
- }
165
- });
161
+ for (idx_t n = i0; n < i1; n++) {
162
+ graph[n].join([&](int i, int j) {
163
+ if (i != j) {
164
+ float dist = qdis.symmetric_dis(i, j);
165
+ graph[i].insert(j, dist);
166
+ graph[j].insert(i, dist);
167
+ }
168
+ });
169
+ }
170
+ InterruptCallback::check();
166
171
  }
167
172
  }
168
173
 
@@ -195,8 +200,9 @@ void NNDescent::update() {
195
200
  int l = 0;
196
201
 
197
202
  while ((l < maxl) && (c < S)) {
198
- if (nn.pool[l].flag)
203
+ if (nn.pool[l].flag) {
199
204
  ++c;
205
+ }
200
206
  ++l;
201
207
  }
202
208
  nn.M = l;
@@ -305,8 +311,9 @@ void NNDescent::generate_eval_set(
305
311
  for (int i = 0; i < c.size(); i++) {
306
312
  std::vector<Neighbor> tmp;
307
313
  for (int j = 0; j < N; j++) {
308
- if (c[i] == j)
314
+ if (c[i] == j) {
309
315
  continue; // skip itself
316
+ }
310
317
  float dist = qdis.symmetric_dis(c[i], j);
311
318
  tmp.push_back(Neighbor(j, dist, true));
312
319
  }
@@ -360,8 +367,9 @@ void NNDescent::init_graph(DistanceComputer& qdis) {
360
367
 
361
368
  for (int j = 0; j < S; j++) {
362
369
  int id = tmp[j];
363
- if (id == i)
370
+ if (id == i) {
364
371
  continue;
372
+ }
365
373
  float dist = qdis.symmetric_dis(i, id);
366
374
 
367
375
  graph[i].pool.push_back(Neighbor(id, dist, true));
@@ -374,6 +382,10 @@ void NNDescent::init_graph(DistanceComputer& qdis) {
374
382
 
375
383
  void NNDescent::build(DistanceComputer& qdis, const int n, bool verbose) {
376
384
  FAISS_THROW_IF_NOT_MSG(L >= K, "L should be >= K in NNDescent.build");
385
+ FAISS_THROW_IF_NOT_FMT(
386
+ n > NUM_EVAL_POINTS,
387
+ "NNDescent.build cannot build a graph smaller than %d",
388
+ int(NUM_EVAL_POINTS));
377
389
 
378
390
  if (verbose) {
379
391
  printf("Parameters: K=%d, S=%d, R=%d, L=%d, iter=%d\n",
@@ -403,7 +415,7 @@ void NNDescent::build(DistanceComputer& qdis, const int n, bool verbose) {
403
415
  has_built = true;
404
416
 
405
417
  if (verbose) {
406
- printf("Addes %d points into the index\n", ntotal);
418
+ printf("Added %d points into the index\n", ntotal);
407
419
  }
408
420
  }
409
421
 
@@ -414,30 +426,30 @@ void NNDescent::search(
414
426
  float* dists,
415
427
  VisitedTable& vt) const {
416
428
  FAISS_THROW_IF_NOT_MSG(has_built, "The index is not build yet.");
417
- int L = std::max(search_L, topk);
429
+ int L_2 = std::max(search_L, topk);
418
430
 
419
431
  // candidate pool, the K best items is the result.
420
- std::vector<Neighbor> retset(L + 1);
432
+ std::vector<Neighbor> retset(L_2 + 1);
421
433
 
422
- // Randomly choose L points to initialize the candidate pool
423
- std::vector<int> init_ids(L);
434
+ // Randomly choose L_2 points to initialize the candidate pool
435
+ std::vector<int> init_ids(L_2);
424
436
  std::mt19937 rng(random_seed);
425
437
 
426
- gen_random(rng, init_ids.data(), L, ntotal);
427
- for (int i = 0; i < L; i++) {
438
+ gen_random(rng, init_ids.data(), L_2, ntotal);
439
+ for (int i = 0; i < L_2; i++) {
428
440
  int id = init_ids[i];
429
441
  float dist = qdis(id);
430
442
  retset[i] = Neighbor(id, dist, true);
431
443
  }
432
444
 
433
445
  // Maintain the candidate pool in ascending order
434
- std::sort(retset.begin(), retset.begin() + L);
446
+ std::sort(retset.begin(), retset.begin() + L_2);
435
447
 
436
448
  int k = 0;
437
449
 
438
- // Stop until the smallest position updated is >= L
439
- while (k < L) {
440
- int nk = L;
450
+ // Stop until the smallest position updated is >= L_2
451
+ while (k < L_2) {
452
+ int nk = L_2;
441
453
 
442
454
  if (retset[k].flag) {
443
455
  retset[k].flag = false;
@@ -445,25 +457,28 @@ void NNDescent::search(
445
457
 
446
458
  for (int m = 0; m < K; ++m) {
447
459
  int id = final_graph[n * K + m];
448
- if (vt.get(id))
460
+ if (vt.get(id)) {
449
461
  continue;
462
+ }
450
463
 
451
464
  vt.set(id);
452
465
  float dist = qdis(id);
453
- if (dist >= retset[L - 1].distance)
466
+ if (dist >= retset[L_2 - 1].distance) {
454
467
  continue;
468
+ }
455
469
 
456
470
  Neighbor nn(id, dist, true);
457
- int r = insert_into_pool(retset.data(), L, nn);
471
+ int r = insert_into_pool(retset.data(), L_2, nn);
458
472
 
459
473
  if (r < nk)
460
474
  nk = r;
461
475
  }
462
476
  }
463
- if (nk <= k)
477
+ if (nk <= k) {
464
478
  k = nk;
465
- else
479
+ } else {
466
480
  ++k;
481
+ }
467
482
  }
468
483
  for (size_t i = 0; i < topk; i++) {
469
484
  indices[i] = retset[i].id;
@@ -25,35 +25,6 @@ namespace {
25
25
  // It needs to be smaller than 0
26
26
  constexpr int EMPTY_ID = -1;
27
27
 
28
- /* Wrap the distance computer into one that negates the
29
- distances. This makes supporting INNER_PRODUCE search easier */
30
-
31
- struct NegativeDistanceComputer : DistanceComputer {
32
- /// owned by this
33
- DistanceComputer* basedis;
34
-
35
- explicit NegativeDistanceComputer(DistanceComputer* basedis)
36
- : basedis(basedis) {}
37
-
38
- void set_query(const float* x) override {
39
- basedis->set_query(x);
40
- }
41
-
42
- /// compute distance of vector i to current query
43
- float operator()(idx_t i) override {
44
- return -(*basedis)(i);
45
- }
46
-
47
- /// compute distance between two stored vectors
48
- float symmetric_dis(idx_t i, idx_t j) override {
49
- return -basedis->symmetric_dis(i, j);
50
- }
51
-
52
- ~NegativeDistanceComputer() override {
53
- delete basedis;
54
- }
55
- };
56
-
57
28
  } // namespace
58
29
 
59
30
  DistanceComputer* storage_distance_computer(const Index* storage) {
@@ -54,7 +54,7 @@ namespace nsg {
54
54
 
55
55
  template <class node_t>
56
56
  struct Graph {
57
- node_t* data; ///< the flattened adjacency matrix
57
+ node_t* data; ///< the flattened adjacency matrix, size N-by-K
58
58
  int K; ///< nb of neighbors per node
59
59
  int N; ///< total nb of nodes
60
60
  bool own_fields; ///< the underlying data owned by itself or not
@@ -12,11 +12,11 @@
12
12
  #include <omp.h>
13
13
  #include <stdint.h>
14
14
 
15
+ #include <algorithm>
15
16
  #include <cmath>
16
17
  #include <cstdlib>
17
18
  #include <cstring>
18
-
19
- #include <algorithm>
19
+ #include <memory>
20
20
 
21
21
  #include <faiss/utils/distances.h>
22
22
  #include <faiss/utils/hamming.h>
@@ -683,18 +683,21 @@ struct RankingScore2 : Score3Computer<float, double> {
683
683
  double accum_gt_weight_diff(
684
684
  const std::vector<int>& a,
685
685
  const std::vector<int>& b) {
686
- int nb = b.size(), na = a.size();
686
+ const auto nb_2 = b.size();
687
+ const auto na = a.size();
687
688
 
688
689
  double accu = 0;
689
- int j = 0;
690
- for (int i = 0; i < na; i++) {
691
- int ai = a[i];
692
- while (j < nb && ai >= b[j])
690
+ size_t j = 0;
691
+ for (size_t i = 0; i < na; i++) {
692
+ const auto ai = a[i];
693
+ while (j < nb_2 && ai >= b[j]) {
693
694
  j++;
695
+ }
694
696
 
695
697
  double accu_i = 0;
696
- for (int k = j; k < b.size(); k++)
698
+ for (auto k = j; k < b.size(); k++) {
697
699
  accu_i += rank_weight(b[k] - ai);
700
+ }
698
701
 
699
702
  accu += rank_weight(ai) * accu_i;
700
703
  }
@@ -882,14 +885,13 @@ void PolysemousTraining::optimize_ranking(
882
885
 
883
886
  double t0 = getmillisecs();
884
887
 
885
- PermutationObjective* obj = new RankingScore2(
888
+ std::unique_ptr<PermutationObjective> obj(new RankingScore2(
886
889
  nbits,
887
890
  nq,
888
891
  nb,
889
892
  codes.data(),
890
893
  codes.data() + nq,
891
- gt_distances.data());
892
- ScopeDeleter1<PermutationObjective> del(obj);
894
+ gt_distances.data()));
893
895
 
894
896
  if (verbose > 0) {
895
897
  printf(" m=%d, nq=%zd, nb=%zd, initialize RankingScore "
@@ -900,7 +902,7 @@ void PolysemousTraining::optimize_ranking(
900
902
  getmillisecs() - t0);
901
903
  }
902
904
 
903
- SimulatedAnnealingOptimizer optim(obj, *this);
905
+ SimulatedAnnealingOptimizer optim(obj.get(), *this);
904
906
 
905
907
  if (log_pattern.size()) {
906
908
  char fname[256];
@@ -151,4 +151,4 @@ struct ProductResidualQuantizer : ProductAdditiveQuantizer {
151
151
  ProductResidualQuantizer();
152
152
  };
153
153
 
154
- }; // namespace faiss
154
+ } // namespace faiss
@@ -61,6 +61,7 @@ void ProductQuantizer::set_derived_values() {
61
61
  "The dimension of the vector (d) should be a multiple of the number of subquantizers (M)");
62
62
  dsub = d / M;
63
63
  code_size = (nbits * M + 7) / 8;
64
+ FAISS_THROW_IF_MSG(nbits > 24, "nbits larger than 24 is not practical.");
64
65
  ksub = 1 << nbits;
65
66
  centroids.resize(d * ksub);
66
67
  verbose = false;
@@ -135,11 +136,10 @@ void ProductQuantizer::train(size_t n, const float* x) {
135
136
  }
136
137
  }
137
138
 
138
- float* xslice = new float[n * dsub];
139
- ScopeDeleter<float> del(xslice);
139
+ std::unique_ptr<float[]> xslice(new float[n * dsub]);
140
140
  for (int m = 0; m < M; m++) {
141
141
  for (int j = 0; j < n; j++)
142
- memcpy(xslice + j * dsub,
142
+ memcpy(xslice.get() + j * dsub,
143
143
  x + j * d + m * dsub,
144
144
  dsub * sizeof(float));
145
145
 
@@ -153,11 +153,19 @@ void ProductQuantizer::train(size_t n, const float* x) {
153
153
  switch (final_train_type) {
154
154
  case Train_hypercube:
155
155
  init_hypercube(
156
- dsub, nbits, n, xslice, clus.centroids.data());
156
+ dsub,
157
+ nbits,
158
+ n,
159
+ xslice.get(),
160
+ clus.centroids.data());
157
161
  break;
158
162
  case Train_hypercube_pca:
159
163
  init_hypercube_pca(
160
- dsub, nbits, n, xslice, clus.centroids.data());
164
+ dsub,
165
+ nbits,
166
+ n,
167
+ xslice.get(),
168
+ clus.centroids.data());
161
169
  break;
162
170
  case Train_hot_start:
163
171
  memcpy(clus.centroids.data(),
@@ -172,7 +180,7 @@ void ProductQuantizer::train(size_t n, const float* x) {
172
180
  printf("Training PQ slice %d/%zd\n", m, M);
173
181
  }
174
182
  IndexFlatL2 index(dsub);
175
- clus.train(n, xslice, assign_index ? *assign_index : index);
183
+ clus.train(n, xslice.get(), assign_index ? *assign_index : index);
176
184
  set_params(clus.centroids.data(), m);
177
185
  }
178
186
 
@@ -306,7 +314,8 @@ void ProductQuantizer::decode(const uint8_t* code, float* x) const {
306
314
  }
307
315
 
308
316
  void ProductQuantizer::decode(const uint8_t* code, float* x, size_t n) const {
309
- for (size_t i = 0; i < n; i++) {
317
+ #pragma omp parallel for if (n > 100)
318
+ for (int64_t i = 0; i < n; i++) {
310
319
  this->decode(code + code_size * i, x + d * i);
311
320
  }
312
321
  }
@@ -342,21 +351,20 @@ void ProductQuantizer::compute_codes_with_assign_index(
342
351
  assign_index->reset();
343
352
  assign_index->add(ksub, get_centroids(m, 0));
344
353
  size_t bs = 65536;
345
- float* xslice = new float[bs * dsub];
346
- ScopeDeleter<float> del(xslice);
347
- idx_t* assign = new idx_t[bs];
348
- ScopeDeleter<idx_t> del2(assign);
354
+
355
+ std::unique_ptr<float[]> xslice(new float[bs * dsub]);
356
+ std::unique_ptr<idx_t[]> assign(new idx_t[bs]);
349
357
 
350
358
  for (size_t i0 = 0; i0 < n; i0 += bs) {
351
359
  size_t i1 = std::min(i0 + bs, n);
352
360
 
353
361
  for (size_t i = i0; i < i1; i++) {
354
- memcpy(xslice + (i - i0) * dsub,
362
+ memcpy(xslice.get() + (i - i0) * dsub,
355
363
  x + i * d + m * dsub,
356
364
  dsub * sizeof(float));
357
365
  }
358
366
 
359
- assign_index->assign(i1 - i0, xslice, assign);
367
+ assign_index->assign(i1 - i0, xslice.get(), assign.get());
360
368
 
361
369
  if (nbits == 8) {
362
370
  uint8_t* c = codes + code_size * i0 + m;
@@ -405,15 +413,14 @@ void ProductQuantizer::compute_codes(const float* x, uint8_t* codes, size_t n)
405
413
  for (int64_t i = 0; i < n; i++)
406
414
  compute_code(x + i * d, codes + i * code_size);
407
415
 
408
- } else { // worthwile to use BLAS
409
- float* dis_tables = new float[n * ksub * M];
410
- ScopeDeleter<float> del(dis_tables);
411
- compute_distance_tables(n, x, dis_tables);
416
+ } else { // worthwhile to use BLAS
417
+ std::unique_ptr<float[]> dis_tables(new float[n * ksub * M]);
418
+ compute_distance_tables(n, x, dis_tables.get());
412
419
 
413
420
  #pragma omp parallel for
414
421
  for (int64_t i = 0; i < n; i++) {
415
422
  uint8_t* code = codes + i * code_size;
416
- const float* tab = dis_tables + i * ksub * M;
423
+ const float* tab = dis_tables.get() + i * ksub * M;
417
424
  compute_code_from_distance_table(tab, code);
418
425
  }
419
426
  }
@@ -774,10 +781,6 @@ void ProductQuantizer::search_ip(
774
781
  init_finalize_heap);
775
782
  }
776
783
 
777
- static float sqr(float x) {
778
- return x * x;
779
- }
780
-
781
784
  void ProductQuantizer::compute_sdc_table() {
782
785
  sdc_table.resize(M * ksub * ksub);
783
786