faiss 0.6.4 → 0.6.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 (228) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/ext/faiss/extconf.rb +1 -1
  4. data/lib/faiss/version.rb +1 -1
  5. data/vendor/faiss/faiss/AutoTune.cpp +175 -0
  6. data/vendor/faiss/faiss/Clustering.cpp +150 -60
  7. data/vendor/faiss/faiss/Clustering.h +29 -0
  8. data/vendor/faiss/faiss/IVFlib.cpp +99 -0
  9. data/vendor/faiss/faiss/IVFlib.h +15 -0
  10. data/vendor/faiss/faiss/Index.cpp +44 -0
  11. data/vendor/faiss/faiss/Index.h +19 -14
  12. data/vendor/faiss/faiss/IndexBinary.cpp +8 -0
  13. data/vendor/faiss/faiss/IndexBinary.h +8 -0
  14. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +82 -4
  15. data/vendor/faiss/faiss/IndexBinaryHNSW.h +19 -0
  16. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +34 -0
  17. data/vendor/faiss/faiss/IndexFastScan.cpp +33 -17
  18. data/vendor/faiss/faiss/IndexFastScan.h +6 -3
  19. data/vendor/faiss/faiss/IndexFlat.cpp +56 -0
  20. data/vendor/faiss/faiss/IndexFlat.h +31 -0
  21. data/vendor/faiss/faiss/IndexFlatCodes.cpp +6 -1
  22. data/vendor/faiss/faiss/IndexHNSW.cpp +456 -10
  23. data/vendor/faiss/faiss/IndexHNSW.h +38 -0
  24. data/vendor/faiss/faiss/IndexIDMap.cpp +32 -0
  25. data/vendor/faiss/faiss/IndexIDMap.h +7 -0
  26. data/vendor/faiss/faiss/IndexIVF.cpp +281 -31
  27. data/vendor/faiss/faiss/IndexIVF.h +53 -1
  28. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +46 -14
  29. data/vendor/faiss/faiss/IndexIVFFastScan.h +4 -2
  30. data/vendor/faiss/faiss/IndexIVFFlat.cpp +33 -0
  31. data/vendor/faiss/faiss/IndexIVFFlat.h +16 -0
  32. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +1 -0
  33. data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +3 -20
  34. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +50 -14
  35. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -2
  36. data/vendor/faiss/faiss/IndexIVFSQFastScan.cpp +855 -0
  37. data/vendor/faiss/faiss/IndexIVFSQFastScan.h +145 -0
  38. data/vendor/faiss/faiss/IndexNNDescent.cpp +0 -3
  39. data/vendor/faiss/faiss/IndexPiPNN.cpp +201 -0
  40. data/vendor/faiss/faiss/IndexPiPNN.h +83 -0
  41. data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +6 -3
  42. data/vendor/faiss/faiss/IndexRaBitQFastScan.h +10 -4
  43. data/vendor/faiss/faiss/IndexReplicas.cpp +20 -0
  44. data/vendor/faiss/faiss/IndexReplicas.h +9 -0
  45. data/vendor/faiss/faiss/IndexSQFastScan.cpp +648 -0
  46. data/vendor/faiss/faiss/IndexSQFastScan.h +129 -0
  47. data/vendor/faiss/faiss/IndexShards.cpp +10 -0
  48. data/vendor/faiss/faiss/IndexShards.h +5 -0
  49. data/vendor/faiss/faiss/SuperKMeans.cpp +57 -15
  50. data/vendor/faiss/faiss/SuperKMeans.h +9 -4
  51. data/vendor/faiss/faiss/VectorTransform.cpp +3 -2
  52. data/vendor/faiss/faiss/clone_index.cpp +24 -0
  53. data/vendor/faiss/faiss/gpu/Dataset.h +112 -0
  54. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +16 -13
  55. data/vendor/faiss/faiss/gpu/GpuCloner.h +4 -0
  56. data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +3 -0
  57. data/vendor/faiss/faiss/gpu/GpuIndex.h +4 -13
  58. data/vendor/faiss/faiss/gpu/GpuIndexBinaryCagra.h +26 -13
  59. data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +45 -22
  60. data/vendor/faiss/faiss/gpu/GpuIndexFlat.h +11 -0
  61. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +6 -0
  62. data/vendor/faiss/faiss/gpu/test/TestGpuDatasetHeader.cpp +18 -0
  63. data/vendor/faiss/faiss/gpu/test/TestGpuIndexFlat.cpp +215 -0
  64. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +98 -0
  65. data/vendor/faiss/faiss/gpu/utils/DeviceUtils.h +11 -0
  66. data/vendor/faiss/faiss/gpu/utils/StackDeviceMemory.cpp +1 -1
  67. data/vendor/faiss/faiss/gpu_metal/MetalCloner.h +11 -0
  68. data/vendor/faiss/faiss/gpu_metal/MetalDistance.h +92 -0
  69. data/vendor/faiss/faiss/gpu_metal/MetalIndex.h +4 -0
  70. data/vendor/faiss/faiss/gpu_metal/MetalIndexBinaryFlat.h +69 -0
  71. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +38 -0
  72. data/vendor/faiss/faiss/gpu_metal/MetalKernels.h +106 -0
  73. data/vendor/faiss/faiss/gpu_metal/MetalPythonBridge.h +10 -0
  74. data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +2 -0
  75. data/vendor/faiss/faiss/impl/AuxIndexStructures.h +1 -6
  76. data/vendor/faiss/faiss/impl/ClusteringHelpers.cpp +134 -45
  77. data/vendor/faiss/faiss/impl/ClusteringHelpers.h +36 -0
  78. data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +286 -136
  79. data/vendor/faiss/faiss/impl/DistanceComputer.cpp +63 -0
  80. data/vendor/faiss/faiss/impl/DistanceComputer.h +3 -29
  81. data/vendor/faiss/faiss/impl/HNSW.cpp +46 -10
  82. data/vendor/faiss/faiss/impl/HNSW.h +72 -0
  83. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +6 -19
  84. data/vendor/faiss/faiss/impl/NNDescent.cpp +2 -1
  85. data/vendor/faiss/faiss/impl/NSG.cpp +3 -2
  86. data/vendor/faiss/faiss/impl/Panorama.h +3 -2
  87. data/vendor/faiss/faiss/impl/PiPNN.cpp +822 -0
  88. data/vendor/faiss/faiss/impl/PiPNN.h +122 -0
  89. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +54 -11
  90. data/vendor/faiss/faiss/impl/RaBitQUtils.h +1 -1
  91. data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +81 -57
  92. data/vendor/faiss/faiss/impl/RaBitQuantizer.h +15 -0
  93. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +29 -0
  94. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +1 -6
  95. data/vendor/faiss/faiss/impl/approx_topk/avx2.cpp +0 -4
  96. data/vendor/faiss/faiss/impl/approx_topk/neon.cpp +0 -4
  97. data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryHash_impl.h +5 -2
  98. data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +0 -4
  99. data/vendor/faiss/faiss/impl/binary_hamming/avx512.cpp +0 -4
  100. data/vendor/faiss/faiss/impl/binary_hamming/neon.cpp +0 -4
  101. data/vendor/faiss/faiss/impl/binary_hamming/rvv.cpp +0 -4
  102. data/vendor/faiss/faiss/impl/expanded_scanners.h +88 -0
  103. data/vendor/faiss/faiss/impl/fast_scan/FastScanDistancePostProcessing.h +4 -0
  104. data/vendor/faiss/faiss/impl/fast_scan/accumulate_loops.h +61 -64
  105. data/vendor/faiss/faiss/impl/fast_scan/accumulate_loops_512.h +13 -14
  106. data/vendor/faiss/faiss/impl/fast_scan/decompose_qbs.h +17 -129
  107. data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +25 -19
  108. data/vendor/faiss/faiss/impl/fast_scan/fast_scan.cpp +5 -0
  109. data/vendor/faiss/faiss/impl/fast_scan/impl-avx2.cpp +0 -4
  110. data/vendor/faiss/faiss/impl/fast_scan/impl-avx512.cpp +0 -4
  111. data/vendor/faiss/faiss/impl/fast_scan/impl-neon.cpp +0 -88
  112. data/vendor/faiss/faiss/impl/fast_scan/impl-riscv.cpp +0 -4
  113. data/vendor/faiss/faiss/impl/fast_scan/kernels_neon.h +155 -0
  114. data/vendor/faiss/faiss/impl/fast_scan/kernels_simd256.h +22 -1
  115. data/vendor/faiss/faiss/impl/fast_scan/kernels_simd512.h +3 -2
  116. data/vendor/faiss/faiss/impl/fast_scan/simd_result_handlers.h +41 -23
  117. data/vendor/faiss/faiss/impl/hnsw/avx2.cpp +0 -4
  118. data/vendor/faiss/faiss/impl/hnsw/avx512.cpp +0 -4
  119. data/vendor/faiss/faiss/impl/index_read.cpp +172 -0
  120. data/vendor/faiss/faiss/impl/index_write.cpp +95 -0
  121. data/vendor/faiss/faiss/impl/pipnn/HashPrune.cpp +159 -0
  122. data/vendor/faiss/faiss/impl/pipnn/HashPrune.h +69 -0
  123. data/vendor/faiss/faiss/impl/pipnn/Partition.cpp +587 -0
  124. data/vendor/faiss/faiss/impl/pipnn/Partition.h +93 -0
  125. data/vendor/faiss/faiss/impl/pipnn/kernels.cpp +326 -0
  126. data/vendor/faiss/faiss/impl/pipnn/kernels.h +92 -0
  127. data/vendor/faiss/faiss/impl/platform_macros.h +45 -0
  128. data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +0 -4
  129. data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQScanner_impl.h +79 -4
  130. data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +6 -0
  131. data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +0 -4
  132. data/vendor/faiss/faiss/impl/pq_code_distance/avx512.cpp +0 -4
  133. data/vendor/faiss/faiss/impl/pq_code_distance/neon.cpp +0 -4
  134. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-avx2.h +4 -0
  135. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-avx512.h +4 -1
  136. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +19 -0
  137. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.h +6 -6
  138. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-inl.h +131 -6
  139. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-sve.cpp +0 -4
  140. data/vendor/faiss/faiss/impl/pq_code_distance/pq_rvv_kernel.h +89 -0
  141. data/vendor/faiss/faiss/impl/pq_code_distance/pq_scan_impl.h +21 -10
  142. data/vendor/faiss/faiss/impl/pq_code_distance/rvv.cpp +45 -18
  143. data/vendor/faiss/faiss/impl/residual_quantizer_encode_steps.cpp +2 -1
  144. data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +0 -4
  145. data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +0 -4
  146. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +0 -4
  147. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +0 -4
  148. data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +5 -1
  149. data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +28 -52
  150. data/vendor/faiss/faiss/impl/scalar_quantizer/scanners.h +59 -11
  151. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +226 -77
  152. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +482 -103
  153. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +2 -149
  154. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +3 -698
  155. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +66 -57
  156. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +101 -96
  157. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-rvv.cpp +3185 -144
  158. data/vendor/faiss/faiss/impl/scalar_quantizer/sq8_coefficients.h +48 -0
  159. data/vendor/faiss/faiss/impl/scalar_quantizer/sq8_rvv_kernel.h +546 -0
  160. data/vendor/faiss/faiss/impl/scalar_quantizer/training.cpp +2 -2
  161. data/vendor/faiss/faiss/impl/simd_dispatch.h +7 -0
  162. data/vendor/faiss/faiss/impl/simdlib/simdlib_avx2.h +14 -0
  163. data/vendor/faiss/faiss/impl/simdlib/simdlib_dispatch.h +7 -8
  164. data/vendor/faiss/faiss/impl/sq_fastscan_utils.h +232 -0
  165. data/vendor/faiss/faiss/index_factory.cpp +76 -0
  166. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +3 -1
  167. data/vendor/faiss/faiss/svs/IndexSVSVamana.h +3 -2
  168. data/vendor/faiss/faiss/utils/AlignedTable.h +6 -1
  169. data/vendor/faiss/faiss/utils/Heap.cpp +4 -3
  170. data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +16 -5
  171. data/vendor/faiss/faiss/utils/bf16.h +36 -0
  172. data/vendor/faiss/faiss/utils/distances.cpp +226 -15
  173. data/vendor/faiss/faiss/utils/distances.h +34 -0
  174. data/vendor/faiss/faiss/utils/distances_dispatch.h +6 -4
  175. data/vendor/faiss/faiss/utils/distances_fused/avx512.cpp +2 -5
  176. data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +0 -14
  177. data/vendor/faiss/faiss/utils/distances_fused/rvv.cpp +25 -0
  178. data/vendor/faiss/faiss/utils/distances_fused/simdlib_based.cpp +0 -4
  179. data/vendor/faiss/faiss/utils/distances_fused/simdlib_based_neon.cpp +0 -4
  180. data/vendor/faiss/faiss/utils/distances_fused/simdlib_kernel-inl.h +2 -1
  181. data/vendor/faiss/faiss/utils/distances_simd.cpp +9 -0
  182. data/vendor/faiss/faiss/utils/fp16-fp16c.h +4 -0
  183. data/vendor/faiss/faiss/utils/fp16-inl.h +26 -52
  184. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx2.cpp +0 -4
  185. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512.cpp +0 -4
  186. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_vpopcnt.cpp +0 -4
  187. data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512.h +33 -5
  188. data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512_vpopcnt.h +15 -30
  189. data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-neon.h +0 -4
  190. data/vendor/faiss/faiss/utils/hamming_distance/hamming_impl.h +2 -1
  191. data/vendor/faiss/faiss/utils/hamming_distance/hamming_neon.cpp +0 -4
  192. data/vendor/faiss/faiss/utils/hamming_distance/hamming_rvv.cpp +0 -4
  193. data/vendor/faiss/faiss/utils/pq_code_distance.h +8 -4
  194. data/vendor/faiss/faiss/utils/prefetch.h +1 -26
  195. data/vendor/faiss/faiss/utils/quantize_lut.cpp +26 -27
  196. data/vendor/faiss/faiss/utils/quantize_lut.h +11 -0
  197. data/vendor/faiss/faiss/utils/rabitq_simd.h +51 -16
  198. data/vendor/faiss/faiss/utils/simd_impl/distances_aarch64.cpp +9 -4
  199. data/vendor/faiss/faiss/utils/simd_impl/distances_arm_sve.cpp +37 -5
  200. data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +64 -5
  201. data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +64 -5
  202. data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +353 -71
  203. data/vendor/faiss/faiss/utils/simd_impl/distances_rvv_kernel.h +68 -0
  204. data/vendor/faiss/faiss/utils/simd_impl/exhaustive_L2sqr_blas_cmax.h +93 -0
  205. data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels.h +76 -0
  206. data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels_avx2.cpp +52 -0
  207. data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels_avx512.cpp +52 -0
  208. data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels_neon.cpp +48 -0
  209. data/vendor/faiss/faiss/utils/simd_impl/masked_sum-avx2.h +44 -0
  210. data/vendor/faiss/faiss/utils/simd_impl/masked_sum-avx512.h +43 -0
  211. data/vendor/faiss/faiss/utils/simd_impl/masked_sum.h +38 -0
  212. data/vendor/faiss/faiss/utils/simd_impl/partitioning_avx2.cpp +0 -4
  213. data/vendor/faiss/faiss/utils/simd_impl/partitioning_neon.cpp +0 -4
  214. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +54 -15
  215. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +38 -21
  216. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512_vpopcnt.cpp +51 -14
  217. data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +297 -10
  218. data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +0 -4
  219. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_avx2.cpp +0 -4
  220. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_avx512.cpp +0 -4
  221. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_sve.cpp +0 -4
  222. data/vendor/faiss/faiss/utils/simd_levels.cpp +19 -3
  223. data/vendor/faiss/faiss/utils/simd_levels.h +74 -1
  224. data/vendor/faiss/faiss/utils/transpose/transpose-avx2-inl.h +0 -4
  225. data/vendor/faiss/faiss/utils/transpose/transpose-avx512-inl.h +0 -4
  226. data/vendor/faiss/faiss/utils/utils.cpp +80 -0
  227. data/vendor/faiss/faiss/utils/utils.h +24 -0
  228. metadata +33 -1
@@ -33,6 +33,7 @@ namespace faiss {
33
33
  namespace gpu {
34
34
 
35
35
  class BinaryCuvsCagra;
36
+ class Dataset;
36
37
 
37
38
  struct GpuIndexBinaryCagra : public IndexBinary {
38
39
  public:
@@ -49,22 +50,34 @@ struct GpuIndexBinaryCagra : public IndexBinary {
49
50
  /// stream and handle resources on the GPU
50
51
  std::shared_ptr<GpuResources> getResources();
51
52
 
52
- /// Trains CAGRA based on the given vector data and add them along with ids.
53
- /// NB: The use of the add function here is to build the CAGRA graph on
54
- /// the base dataset. Use this function when you want to add vectors with
55
- /// ids. Ref: https://github.com/facebookresearch/faiss/issues/4107
53
+ /// Pointer-based construction is unsupported. Use a caller-owned Dataset.
56
54
  void add(idx_t n, const uint8_t* x) override;
57
-
58
- /// Trains CAGRA based on the given vector data.
59
- /// NB: The use of the train function here is to build the CAGRA graph on
60
- /// the base dataset and is currently the only function to add the full set
61
- /// of vectors (without IDs) to the index. There is no external quantizer to
62
- /// be trained here.
63
55
  void train(idx_t n, const uint8_t* x) override;
64
56
 
65
- /// Initialize ourselves from the given CPU index; will overwrite
66
- /// all data in ourselves
67
- void copyFrom(const faiss::IndexBinaryHNSWCagra* index);
57
+ /// Build the full graph, borrowing UInt8 vectors with dim == d / 8.
58
+ /// The backing storage must remain alive and unchanged until all index
59
+ /// operations have completed. Does nothing if already trained; call reset()
60
+ /// before building again.
61
+ void train(const Dataset& dataset) override;
62
+ void add(const Dataset& dataset) override;
63
+
64
+ /// Rebind search storage without changing the graph. The vectors and their
65
+ /// ordering must match the training data. Requires compatible device data;
66
+ /// any padding must be zero and the caller retains ownership. Previous
67
+ /// work on the index stream completes before rebinding.
68
+ void updateDataset(const Dataset& dataset);
69
+ bool isSearchReady() const;
70
+
71
+ /// Copy the CPU graph. Without a Dataset, import only the graph and
72
+ /// metadata; attach vectors with updateDataset before search or copyTo.
73
+ /// If provided, dataset must describe writable, compatible storage on this
74
+ /// device with the CPU index's shape and UInt8 type. Copy CPU vectors into
75
+ /// that allocation, zero padding, and borrow it for search. The caller owns
76
+ /// the allocation and must keep it alive through index use. Copies complete
77
+ /// before return, so the CPU index can be released in either case.
78
+ void copyFrom(
79
+ const faiss::IndexBinaryHNSWCagra* index,
80
+ Dataset* dataset = nullptr);
68
81
 
69
82
  /// Copy ourselves to the given CPU index; will overwrite all data
70
83
  /// in the index instance
@@ -27,6 +27,11 @@
27
27
  #include <faiss/gpu/GpuIndex.h>
28
28
  #include <faiss/gpu/GpuIndexIVFPQ.h>
29
29
 
30
+ #ifndef SWIG
31
+ #include <faiss/gpu/Dataset.h>
32
+ #include <optional>
33
+ #endif
34
+
30
35
  #include <variant>
31
36
  #include <vector>
32
37
  #include "faiss/Index.h"
@@ -216,7 +221,6 @@ struct GpuIndexCagraConfig : public GpuIndexConfig {
216
221
  std::shared_ptr<IVFPQBuildCagraConfig> ivf_pq_params{nullptr};
217
222
  std::shared_ptr<IVFPQSearchCagraConfig> ivf_pq_search_params{nullptr};
218
223
  float refine_rate = 2.0f;
219
- bool store_dataset = true;
220
224
 
221
225
  /// Whether to use MST optimization to guarantee graph connectivity.
222
226
  bool guarantee_connectivity = false;
@@ -309,28 +313,43 @@ struct GpuIndexCagra : public GpuIndex {
309
313
  faiss::MetricType metric = faiss::METRIC_L2,
310
314
  GpuIndexCagraConfig config = GpuIndexCagraConfig());
311
315
 
312
- /// Trains CAGRA based on the given vector data and add them along with ids.
313
- /// NB: The use of the add function here is to build the CAGRA graph on
314
- /// the base dataset. Use this function when you want to add vectors with
315
- /// ids. Ref: https://github.com/facebookresearch/faiss/issues/4107
316
+ ~GpuIndexCagra() override;
317
+
318
+ /// Build the full graph while borrowing dataset storage. The backing
319
+ /// allocation must remain alive and unchanged through index use and all
320
+ /// outstanding GPU work. Does nothing if already trained; call reset()
321
+ /// before building again.
322
+ void train(const Dataset& dataset) override;
323
+
324
+ /// Equivalent to train(dataset); incremental insertion is unsupported.
325
+ void add(const Dataset& dataset) override;
326
+
327
+ /// Attach search-compatible device storage without changing the graph.
328
+ /// Shape, dtype and vector ordering must match the trained dataset. The
329
+ /// values must be the same; this method does not rebuild for changed data.
330
+ /// Previous work on this index's stream completes before rebinding.
331
+ void updateDataset(const Dataset& dataset);
332
+ bool isSearchReady() const;
333
+
334
+ /// Copy the CPU graph and metadata. With no dataset, import only the
335
+ /// graph: no vector storage is retained and GPU search is unavailable.
336
+ /// When supplied, dataset must describe writable CAGRA-compatible device
337
+ /// storage with matching shape and dtype on this index's device. Its
338
+ /// contents are overwritten with CPU vectors and its padding is zeroed.
339
+ /// The index borrows that allocation and becomes search-ready. The caller
340
+ /// retains ownership and must keep the allocation alive through index use
341
+ /// and queued GPU work. Copies finish before return, so the CPU index may
342
+ /// then be released in either mode.
343
+ void copyFrom(
344
+ const faiss::IndexHNSWCagra* index,
345
+ Dataset* dataset = nullptr);
346
+
347
+ /// Legacy pointer entry points throw: use the Dataset overloads.
316
348
  void add(idx_t n, const float* x) override;
317
349
  void add_ex(idx_t n, const void* x, NumericType numeric_type) override;
318
-
319
- /// Trains CAGRA based on the given vector data.
320
- /// NB: The use of the train function here is to build the CAGRA graph on
321
- /// the base dataset and is currently the only function to add the full set
322
- /// of vectors (without IDs) to the index. There is no external quantizer to
323
- /// be trained here.
324
350
  void train(idx_t n, const float* x) override;
325
351
  void train_ex(idx_t n, const void* x, NumericType numeric_type) override;
326
352
 
327
- /// Initialize ourselves from the given CPU index; will overwrite
328
- /// all data in ourselves
329
- void copyFrom(const faiss::IndexHNSWCagra* index);
330
- void copyFrom_ex(
331
- const faiss::IndexHNSWCagra* index,
332
- NumericType numeric_type);
333
-
334
353
  /// Copy ourselves to the given CPU index; will overwrite all data
335
354
  /// in the index instance
336
355
  void copyTo(faiss::IndexHNSWCagra* index) const;
@@ -372,7 +391,9 @@ struct GpuIndexCagra : public GpuIndex {
372
391
  /// more than one device: cuVS `all_neighbors` knn graph construction over
373
392
  /// overlapping clusters, followed by graph pruning. Leaves the result in
374
393
  /// merged_knngraph_ for copyTo(); index_ stays empty.
375
- void trainAllNeighbors_(idx_t n, const float* x);
394
+ #ifndef SWIG
395
+ void trainAllNeighbors_(const Dataset& dataset);
396
+ #endif
376
397
 
377
398
  /// Populate HNSW levels >= 1 of `index` by building a CAGRA graph over
378
399
  /// each level's node subset on the GPU. Requires the level table to be
@@ -385,9 +406,9 @@ struct GpuIndexCagra : public GpuIndex {
385
406
  /// Our configuration options
386
407
  const GpuIndexCagraConfig cagraConfig_;
387
408
 
388
- faiss::NumericType numeric_type_;
409
+ faiss::NumericType numeric_type_ = NumericType::Float32;
389
410
 
390
- /// Instance that we own; contains the inverted lists
411
+ /// Instance that owns the CAGRA graph and borrows dataset storage
391
412
  std::variant<
392
413
  std::monostate,
393
414
  std::shared_ptr<CuvsCagra<float>>,
@@ -398,7 +419,9 @@ struct GpuIndexCagra : public GpuIndex {
398
419
  /// Multi-GPU state: populated by trainAllNeighbors_(), used by copyTo()
399
420
  std::vector<idx_t> merged_knngraph_;
400
421
  idx_t merged_knngraph_degree_ = 0;
401
- const float* multi_gpu_dataset_ = nullptr;
422
+ #ifndef SWIG
423
+ std::optional<Dataset> multiGpuDataset_;
424
+ #endif
402
425
  };
403
426
 
404
427
  } // namespace gpu
@@ -131,6 +131,17 @@ class GpuIndexFlat : public GpuIndex {
131
131
  idx_t* labels,
132
132
  const SearchParameters* params) const override;
133
133
 
134
+ /// Called from GpuIndex for search; Float16 queries are searched without
135
+ /// conversion against float16 storage
136
+ void searchImpl_ex_(
137
+ idx_t n,
138
+ const void* x,
139
+ NumericType numeric_type,
140
+ int k,
141
+ float* distances,
142
+ idx_t* labels,
143
+ const SearchParameters* params) const override;
144
+
134
145
  protected:
135
146
  /// Our configuration options
136
147
  const GpuIndexFlatConfig flatConfig_;
@@ -32,6 +32,12 @@ struct GpuIndexIVFConfig : public GpuIndexConfig {
32
32
  /// throw an exception for indices not implemented on GPU. When set to
33
33
  /// true, it will fallback to a CPU implementation.
34
34
  bool allowCpuCoarseQuantizer = false;
35
+
36
+ /// Break a distance tie on the smaller id, so a search repeats. Honoured
37
+ /// by GpuIndexIVFFlat and GpuIndexIVFScalarQuantizer with the interleaved
38
+ /// layout for k up to 1024, and by the cuVS GpuIndexIVFScalarQuantizer
39
+ /// and GpuIndexIVFPQ for k and nprobe up to 256.
40
+ bool deterministic_tie_break = false;
35
41
  };
36
42
 
37
43
  /// Base class of all GPU IVF index types. This (for now) deliberately does not
@@ -0,0 +1,18 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ // Keep this translation unit ordinary C++ without CUDA, RAFT, or cuVS headers.
9
+ #include <faiss/gpu/Dataset.h>
10
+
11
+ #include <type_traits>
12
+
13
+ using faiss::gpu::Dataset;
14
+
15
+ static_assert(!std::is_copy_constructible_v<Dataset>);
16
+ static_assert(!std::is_copy_assignable_v<Dataset>);
17
+ static_assert(std::is_nothrow_move_constructible_v<Dataset>);
18
+ static_assert(std::is_nothrow_move_assignable_v<Dataset>);
@@ -5,14 +5,19 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
+ #include <faiss/Clustering.h>
8
9
  #include <faiss/IndexFlat.h>
9
10
  #include <faiss/gpu/GpuIndexFlat.h>
11
+ #include <faiss/gpu/GpuIndexIVFFlat.h>
10
12
  #include <faiss/gpu/StandardGpuResources.h>
11
13
  #include <faiss/gpu/impl/IndexUtils.h>
12
14
  #include <faiss/gpu/test/TestUtils.h>
13
15
  #include <faiss/gpu/utils/DeviceUtils.h>
14
16
  #include <faiss/impl/IDSelector.h>
17
+ #include <faiss/utils/fp16.h>
15
18
  #include <gtest/gtest.h>
19
+ #include <algorithm>
20
+ #include <cstdint>
16
21
  #include <sstream>
17
22
  #include <unordered_map>
18
23
  #include <vector>
@@ -807,6 +812,216 @@ TEST(TestCuvsGpuIndexFlat, IDSelector_IP) {
807
812
  }
808
813
  #endif
809
814
 
815
+ // Packs float vectors as IEEE binary16, the Float16 input of search_ex
816
+ std::vector<uint16_t> toFp16(const std::vector<float>& v) {
817
+ std::vector<uint16_t> out(v.size());
818
+ std::transform(v.begin(), v.end(), out.begin(), [](float f) {
819
+ return faiss::encode_fp16(f);
820
+ });
821
+ return out;
822
+ }
823
+
824
+ std::vector<float> fromFp16(const std::vector<uint16_t>& v) {
825
+ std::vector<float> out(v.size());
826
+ std::transform(v.begin(), v.end(), out.begin(), [](uint16_t h) {
827
+ return faiss::decode_fp16(h);
828
+ });
829
+ return out;
830
+ }
831
+
832
+ // A copy of host data on a GPU device
833
+ struct DeviceCopy {
834
+ DeviceCopy(int device, const void* src, size_t bytes) {
835
+ faiss::gpu::DeviceScope scope(device);
836
+ CUDA_VERIFY(cudaMalloc(&data, bytes));
837
+ CUDA_VERIFY(cudaMemcpy(data, src, bytes, cudaMemcpyHostToDevice));
838
+ }
839
+
840
+ DeviceCopy(const DeviceCopy&) = delete;
841
+ DeviceCopy& operator=(const DeviceCopy&) = delete;
842
+
843
+ ~DeviceCopy() {
844
+ CUDA_VERIFY(cudaFree(data));
845
+ }
846
+
847
+ void* data = nullptr;
848
+ };
849
+
850
+ // search_ex on Float16 queries must return exactly what search returns on the
851
+ // float32 queries rounded to fp16, as the rounded values are what the index
852
+ // computes with, whether the queries are on the host (paged or not) or on the
853
+ // device
854
+ void testSearchExFloat16(faiss::gpu::GpuIndex& index) {
855
+ int numQuery = faiss::gpu::randVal(1, 512);
856
+ int k = std::min(faiss::gpu::randVal(1, 50), int(index.ntotal));
857
+
858
+ auto queries = faiss::gpu::randVecs(numQuery, index.d);
859
+ auto queries16 = toFp16(queries);
860
+ auto roundedQueries = fromFp16(queries16);
861
+
862
+ std::vector<float> refDistances(numQuery * k);
863
+ std::vector<faiss::idx_t> refLabels(numQuery * k);
864
+ index.search(
865
+ numQuery,
866
+ roundedQueries.data(),
867
+ k,
868
+ refDistances.data(),
869
+ refLabels.data());
870
+
871
+ auto expectSearchExMatches = [&](const void* x, const std::string& where) {
872
+ std::vector<float> distances(numQuery * k, 0);
873
+ std::vector<faiss::idx_t> labels(numQuery * k, -1);
874
+ index.search_ex(
875
+ numQuery,
876
+ x,
877
+ faiss::NumericType::Float16,
878
+ k,
879
+ distances.data(),
880
+ labels.data());
881
+
882
+ EXPECT_EQ(labels, refLabels) << where;
883
+ EXPECT_EQ(distances, refDistances) << where;
884
+ };
885
+
886
+ expectSearchExMatches(queries16.data(), "host queries");
887
+
888
+ auto minPagingSize = index.getMinPagingSize();
889
+ index.setMinPagingSize(0);
890
+ expectSearchExMatches(queries16.data(), "paged host queries");
891
+ index.setMinPagingSize(minPagingSize);
892
+
893
+ DeviceCopy queries16Device(
894
+ index.getDevice(),
895
+ queries16.data(),
896
+ queries16.size() * sizeof(uint16_t));
897
+ expectSearchExMatches(queries16Device.data, "device queries");
898
+ }
899
+
900
+ // Covers both float32 storage (queries widened on the device) and float16
901
+ // storage (queries searched natively)
902
+ template <typename GpuIndexFlatT>
903
+ void testFlatSearchExFloat16() {
904
+ faiss::gpu::StandardGpuResources res;
905
+ res.noTempMemory();
906
+
907
+ int dim = faiss::gpu::randVal(50, 400);
908
+ int numVecs = faiss::gpu::randVal(1000, 5000);
909
+ auto vecs = faiss::gpu::randVecs(numVecs, dim);
910
+
911
+ for (bool useFloat16 : {false, true}) {
912
+ faiss::gpu::GpuIndexFlatConfig config;
913
+ config.device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
914
+ config.useFloat16 = useFloat16;
915
+
916
+ GpuIndexFlatT gpuIndex(&res, dim, config);
917
+ gpuIndex.add(numVecs, vecs.data());
918
+
919
+ SCOPED_TRACE(useFloat16 ? "useFloat16" : "float32 storage");
920
+ testSearchExFloat16(gpuIndex);
921
+ }
922
+ }
923
+
924
+ TEST(TestGpuIndexFlat, SearchExFloat16_L2) {
925
+ testFlatSearchExFloat16<faiss::gpu::GpuIndexFlatL2>();
926
+ }
927
+
928
+ TEST(TestGpuIndexFlat, SearchExFloat16_IP) {
929
+ testFlatSearchExFloat16<faiss::gpu::GpuIndexFlatIP>();
930
+ }
931
+
932
+ // Indexes without a native fp16 search widen the queries on the device
933
+ TEST(TestGpuIndexFlat, SearchExFloat16_IVFFlatDefault) {
934
+ faiss::gpu::StandardGpuResources res;
935
+ res.noTempMemory();
936
+
937
+ int dim = 64;
938
+ int numVecs = 5000;
939
+ auto vecs = faiss::gpu::randVecs(numVecs, dim);
940
+
941
+ faiss::gpu::GpuIndexIVFFlatConfig config;
942
+ config.device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
943
+
944
+ int numLists = 32;
945
+ faiss::gpu::GpuIndexIVFFlat gpuIndex(
946
+ &res, dim, numLists, faiss::METRIC_L2, config);
947
+ gpuIndex.nprobe = 4;
948
+ gpuIndex.train(numVecs, vecs.data());
949
+ gpuIndex.add(numVecs, vecs.data());
950
+
951
+ testSearchExFloat16(gpuIndex);
952
+ }
953
+
954
+ // k-means on fp16 data with a GPU assignment index must match k-means on the
955
+ // float32 rounding of that data with the same kind of index
956
+ TEST(TestGpuIndexFlat, ClusteringTrainExFloat16) {
957
+ faiss::gpu::StandardGpuResources res;
958
+ res.noTempMemory();
959
+
960
+ int dim = 32;
961
+ int numCentroids = 20;
962
+ // Fits in a single decode block, so that both runs search the same batches
963
+ int numVecs = 2000;
964
+ auto vecs = faiss::gpu::randVecs(numVecs, dim);
965
+ auto vecs16 = toFp16(vecs);
966
+ auto roundedVecs = fromFp16(vecs16);
967
+
968
+ faiss::ClusteringParameters cp;
969
+ cp.niter = 10;
970
+
971
+ for (bool useFloat16 : {false, true}) {
972
+ faiss::gpu::GpuIndexFlatConfig config;
973
+ config.device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
974
+ config.useFloat16 = useFloat16;
975
+
976
+ faiss::gpu::GpuIndexFlatL2 refIndex(&res, dim, config);
977
+ faiss::Clustering refClustering(dim, numCentroids, cp);
978
+ refClustering.train(numVecs, roundedVecs.data(), refIndex);
979
+
980
+ faiss::gpu::GpuIndexFlatL2 gpuIndex(&res, dim, config);
981
+ faiss::Clustering clustering(dim, numCentroids, cp);
982
+ clustering.train_ex(
983
+ numVecs, vecs16.data(), faiss::NumericType::Float16, gpuIndex);
984
+
985
+ ASSERT_EQ(clustering.centroids.size(), refClustering.centroids.size());
986
+ for (size_t i = 0; i < clustering.centroids.size(); ++i) {
987
+ EXPECT_NEAR(
988
+ clustering.centroids[i], refClustering.centroids[i], 1e-5f)
989
+ << "useFloat16 " << useFloat16 << " element " << i;
990
+ }
991
+ }
992
+ }
993
+
994
+ // add and reconstruct_n copy the whole vector set between host and device in
995
+ // one copy. On ROCm, a pageable copy of more than 64 KiB goes through 16 MiB
996
+ // pinned chunks: 17 vectors take one chunk, and 10,500 vectors take two full
997
+ // chunks and a partial one. Each size has its own resources, so the second
998
+ // size reuses the pinned chunks after the streams of the first are destroyed.
999
+ TEST(TestGpuIndexFlat, LargeHostCopyRoundTrip) {
1000
+ int dim = 1000;
1001
+ int device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
1002
+
1003
+ for (int numVecs : {17, 10500}) {
1004
+ faiss::gpu::StandardGpuResources res;
1005
+ res.noTempMemory();
1006
+
1007
+ faiss::gpu::GpuIndexFlatConfig config;
1008
+ config.device = device;
1009
+
1010
+ faiss::gpu::GpuIndexFlatL2 gpuIndex(&res, dim, config);
1011
+ std::vector<float> vecs = faiss::gpu::randVecs(numVecs, dim);
1012
+ gpuIndex.add(numVecs, vecs.data());
1013
+
1014
+ std::vector<float> out(vecs.size());
1015
+ gpuIndex.reconstruct_n(0, numVecs, out.data());
1016
+
1017
+ // Report the first difference; printing millions of values is useless
1018
+ size_t firstDiff =
1019
+ std::mismatch(out.begin(), out.end(), vecs.begin()).first -
1020
+ out.begin();
1021
+ EXPECT_EQ(firstDiff, out.size()) << "numVecs " << numVecs;
1022
+ }
1023
+ }
1024
+
810
1025
  int main(int argc, char** argv) {
811
1026
  testing::InitGoogleTest(&argc, argv);
812
1027
 
@@ -31,8 +31,11 @@
31
31
  #include <faiss/impl/IDSelector.h>
32
32
  #include <faiss/utils/distances.h>
33
33
  #include <gtest/gtest.h>
34
+ #include <algorithm>
34
35
  #include <cmath>
36
+ #include <random>
35
37
  #include <sstream>
38
+ #include <unordered_set>
36
39
  #include <vector>
37
40
 
38
41
  // FIXME: figure out a better way to test fp16
@@ -472,6 +475,101 @@ TEST(TestGpuIndexIVFFlat, Float32_32_CopyFrom) {
472
475
  #endif
473
476
  }
474
477
 
478
+ #if defined USE_NVIDIA_CUVS
479
+ class TestCuvsGpuIndexIVFFlatCopyFrom
480
+ : public testing::TestWithParam<faiss::MetricType> {};
481
+
482
+ TEST_P(TestCuvsGpuIndexIVFFlatCopyFrom, SearchLargeK) {
483
+ constexpr int numVecs = 16384;
484
+ constexpr int dim = 128;
485
+ constexpr int numCentroids = 32;
486
+ const auto metric = GetParam();
487
+ std::mt19937 rng(42);
488
+ std::uniform_int_distribution<int> random(-30, 30);
489
+ std::vector<float> vecs(numVecs * dim);
490
+ for (auto& value : vecs) {
491
+ value = random(rng);
492
+ }
493
+
494
+ faiss::IndexFlat quantizer(dim, metric);
495
+ faiss::IndexIVFFlat cpuIndex(&quantizer, dim, numCentroids, metric);
496
+ cpuIndex.cp.niter = 5;
497
+ cpuIndex.train(numVecs, vecs.data());
498
+ cpuIndex.add(numVecs, vecs.data());
499
+ cpuIndex.nprobe = numCentroids;
500
+
501
+ faiss::gpu::StandardGpuResources res;
502
+ faiss::gpu::GpuIndexIVFFlatConfig config;
503
+ config.use_cuvs = true;
504
+ config.indicesOptions = faiss::gpu::INDICES_64_BIT;
505
+ faiss::gpu::GpuIndexIVFFlat gpuIndex(
506
+ &res, dim, numCentroids, metric, config);
507
+ gpuIndex.copyFrom(&cpuIndex);
508
+
509
+ faiss::IndexFlat exact(dim, metric);
510
+ exact.add(numVecs, vecs.data());
511
+ // k > 256 takes the cuVS path that sizes its workspace from the
512
+ // accumulated list sizes. Cloning must populate those sizes first.
513
+ for (int k : {256, 257, 500, 3500}) {
514
+ SCOPED_TRACE(testing::Message() << "k=" << k);
515
+ for (int numQueries : {1, 4}) {
516
+ SCOPED_TRACE(testing::Message() << "numQueries=" << numQueries);
517
+ std::vector<float> expected(numQueries * k);
518
+ std::vector<float> distances(numQueries * k);
519
+ std::vector<faiss::idx_t> expectedIds(numQueries * k);
520
+ std::vector<faiss::idx_t> ids(numQueries * k);
521
+ exact.search(
522
+ numQueries,
523
+ vecs.data(),
524
+ k,
525
+ expected.data(),
526
+ expectedIds.data());
527
+ for (int repeat = 0; repeat < 2; ++repeat) {
528
+ gpuIndex.search(
529
+ numQueries,
530
+ vecs.data(),
531
+ k,
532
+ distances.data(),
533
+ ids.data());
534
+ for (int q = 0; q < numQueries; ++q) {
535
+ std::unordered_set<faiss::idx_t> uniqueIds;
536
+ for (int i = q * k; i < (q + 1) * k; ++i) {
537
+ ASSERT_GE(ids[i], 0);
538
+ ASSERT_LT(ids[i], numVecs);
539
+ EXPECT_TRUE(uniqueIds.insert(ids[i]).second);
540
+ float score = 0;
541
+ for (int j = 0; j < dim; ++j) {
542
+ float a = vecs[q * dim + j];
543
+ float b = vecs[ids[i] * dim + j];
544
+ score += metric == faiss::METRIC_L2
545
+ ? (a - b) * (a - b)
546
+ : a * b;
547
+ }
548
+ EXPECT_FLOAT_EQ(score, distances[i]);
549
+ }
550
+ // cuVS need not return sorted results, and tied scores
551
+ // may select different IDs at the top-k boundary.
552
+ std::vector<float> actual(
553
+ distances.begin() + q * k,
554
+ distances.begin() + (q + 1) * k);
555
+ auto begin = expected.begin() + q * k;
556
+ std::sort(begin, begin + k);
557
+ std::sort(actual.begin(), actual.end());
558
+ for (int i = 0; i < k; ++i) {
559
+ EXPECT_FLOAT_EQ(begin[i], actual[i]);
560
+ }
561
+ }
562
+ }
563
+ }
564
+ }
565
+ }
566
+
567
+ INSTANTIATE_TEST_SUITE_P(
568
+ Cuvs,
569
+ TestCuvsGpuIndexIVFFlatCopyFrom,
570
+ testing::Values(faiss::METRIC_L2, faiss::METRIC_INNER_PRODUCT));
571
+ #endif
572
+
475
573
  TEST(TestGpuIndexIVFFlat, Float32_negative) {
476
574
  Options opt;
477
575
 
@@ -63,6 +63,17 @@ size_t getMaxSharedMemPerBlockCurrentDevice();
63
63
  /// a device (deviceId >= 0) or the host (-1).
64
64
  int getDeviceForAddress(const void* p);
65
65
 
66
+ /// cudaMemcpyAsync, except that on ROCm a copy of more than 64 KiB to or from
67
+ /// pageable host memory goes through pinned staging buffers. As with CUDA's
68
+ /// pageable copies, a host-to-device copy returns once the source can be
69
+ /// reused, and a device-to-host copy returns once the data is on the host.
70
+ void memcpyHostDeviceAsync(
71
+ void* dst,
72
+ const void* src,
73
+ size_t bytes,
74
+ cudaMemcpyKind kind,
75
+ cudaStream_t stream);
76
+
66
77
  /// Does the given device support full unified memory sharing host
67
78
  /// memory?
68
79
  bool getFullUnifiedMemSupport(int device);
@@ -145,7 +145,7 @@ void StackDeviceMemory::Stack::returnAlloc(
145
145
  }
146
146
 
147
147
  head_ = p;
148
- lastUsers_.push_back(Range(p, p + size, stream));
148
+ lastUsers_.emplace_back(p, p + size, stream);
149
149
  }
150
150
 
151
151
  std::string StackDeviceMemory::Stack::toString() const {
@@ -11,6 +11,7 @@
11
11
  #pragma once
12
12
 
13
13
  #include <faiss/Index.h>
14
+ #include <faiss/IndexBinary.h>
14
15
 
15
16
  namespace faiss {
16
17
  namespace gpu_metal {
@@ -31,5 +32,15 @@ faiss::Index* index_cpu_to_metal_gpu(
31
32
  /// Caller owns the returned index.
32
33
  faiss::Index* index_metal_gpu_to_cpu(const faiss::Index* index);
33
34
 
35
+ /// Clone IndexBinaryFlat to Metal. device must be 0; caller owns the result.
36
+ faiss::IndexBinary* index_binary_cpu_to_metal_gpu(
37
+ StandardMetalResources* res,
38
+ int device,
39
+ const faiss::IndexBinary* index);
40
+
41
+ /// Clone MetalIndexBinaryFlat to CPU. Caller owns the returned index.
42
+ faiss::IndexBinary* index_binary_metal_gpu_to_cpu(
43
+ const faiss::IndexBinary* index);
44
+
34
45
  } // namespace gpu_metal
35
46
  } // namespace faiss