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
@@ -0,0 +1,129 @@
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
+ #pragma once
9
+
10
+ #include <vector>
11
+
12
+ #include <faiss/IndexFastScan.h>
13
+ #include <faiss/IndexFlatCodes.h>
14
+ #include <faiss/IndexScalarQuantizer.h>
15
+ #include <faiss/impl/ScalarQuantizer.h>
16
+
17
+ namespace faiss {
18
+
19
+ /** Fast scan version of IndexScalarQuantizer.
20
+ *
21
+ * Supported quantizer types:
22
+ * - QT_4bit, QT_4bit_uniform: native 4-bit codes mapped onto the
23
+ * PQ4 FastScan SIMD (vpshufb / equivalent).
24
+ *
25
+ * - QT_6bit, QT_8bit, QT_8bit_uniform, QT_8bit_direct,
26
+ * QT_8bit_direct_signed: re-quantised to 4-bit for the scan, reranked
27
+ * against the originals in orig_codes.
28
+ *
29
+ * - All other types (QT_fp16, QT_bf16): use IndexScalarQuantizer directly.
30
+ */
31
+ struct IndexSQFastScan : IndexFastScan {
32
+ ScalarQuantizer sq;
33
+
34
+ /// Overselection ratio for reranking.
35
+ float rerank_factor = 2;
36
+
37
+ /// Low nibbles of the 8-bit codes, two dimensions per byte, indexed by
38
+ /// id. The high nibbles live in the packed scan codes. Empty for the
39
+ /// native 4-bit types, which need no rerank.
40
+ std::vector<uint8_t> lo_codes;
41
+
42
+ /** Constructor.
43
+ *
44
+ * @param d dimensionality of input vectors
45
+ * @param qtype any native 4-bit or reranked type (see above)
46
+ * @param metric distance metric (METRIC_L2 or METRIC_INNER_PRODUCT)
47
+ * @param bbs block size for SIMD processing (multiple of 32)
48
+ */
49
+ IndexSQFastScan(
50
+ int d,
51
+ ScalarQuantizer::QuantizerType qtype,
52
+ MetricType metric = METRIC_L2,
53
+ int bbs = 32);
54
+
55
+ IndexSQFastScan();
56
+
57
+ /// Build from an existing IndexScalarQuantizer
58
+ explicit IndexSQFastScan(const IndexScalarQuantizer& orig, int bbs = 32);
59
+
60
+ void train(idx_t n, const float* x) override;
61
+
62
+ void add(idx_t n, const float* x) override;
63
+
64
+ void reset() override;
65
+
66
+ void search(
67
+ idx_t n,
68
+ const float* x,
69
+ idx_t k,
70
+ float* distances,
71
+ idx_t* labels,
72
+ const SearchParameters* params = nullptr) const override;
73
+
74
+ void compute_codes(uint8_t* codes, idx_t n, const float* x) const override;
75
+
76
+ void check_compatible_for_merge(const Index& otherIndex) const override;
77
+
78
+ void compute_float_LUT(
79
+ float* lut,
80
+ idx_t n,
81
+ const float* x,
82
+ const FastScanDistancePostProcessing& context) const override;
83
+
84
+ void sa_decode(idx_t n, const uint8_t* bytes, float* x) const override;
85
+
86
+ void sa_encode(idx_t n, const float* x, uint8_t* bytes) const override;
87
+
88
+ void reconstruct(idx_t key, float* recons) const override;
89
+
90
+ void reconstruct_n(idx_t i0, idx_t ni, float* recons) const override;
91
+
92
+ void add_sa_codes(idx_t n, const uint8_t* codes, const idx_t* xids)
93
+ override;
94
+
95
+ void permute_entries(const idx_t* perm);
96
+
97
+ FlatCodesDistanceComputer* get_FlatCodesDistanceComputer() const;
98
+
99
+ DistanceComputer* get_distance_computer() const override;
100
+
101
+ void range_search(
102
+ idx_t n,
103
+ const float* x,
104
+ float radius,
105
+ RangeSearchResult* result,
106
+ const SearchParameters* params = nullptr) const override;
107
+
108
+ size_t remove_ids(const IDSelector& sel) override;
109
+
110
+ void merge_from(Index& otherIndex, idx_t add_id = 0) override;
111
+
112
+ void search1(
113
+ const float* x,
114
+ ResultHandler& handler,
115
+ SearchParameters* params = nullptr) const override;
116
+
117
+ size_t sa_code_size() const override;
118
+
119
+ void fill_sa_code(
120
+ const CodePacker& packer,
121
+ idx_t id,
122
+ uint8_t* scratch,
123
+ int* values,
124
+ uint8_t* code_out) const;
125
+
126
+ size_t fast_scan_code_size() const override;
127
+ };
128
+
129
+ } // namespace faiss
@@ -193,6 +193,16 @@ void IndexShardsTemplate<IndexT>::add_with_ids(
193
193
  syncWithSubIndexes();
194
194
  }
195
195
 
196
+ template <typename IndexT>
197
+ size_t IndexShardsTemplate<IndexT>::remove_ids(const IDSelector& sel) {
198
+ FAISS_THROW_IF_MSG(
199
+ successive_ids, "remove_ids needs successive_ids = false");
200
+ const idx_t before = this->ntotal;
201
+ this->runOnIndex([&sel](int, IndexT* index) { index->remove_ids(sel); });
202
+ syncWithSubIndexes();
203
+ return before - this->ntotal;
204
+ }
205
+
196
206
  template <typename IndexT>
197
207
  void IndexShardsTemplate<IndexT>::search(
198
208
  idx_t n,
@@ -91,6 +91,11 @@ struct IndexShardsTemplate : public ThreadedIndex<IndexT> {
91
91
 
92
92
  void train(idx_t n, const component_t* x) override;
93
93
 
94
+ /// Removes the ids from every shard, and returns the sum of the counts.
95
+ /// Needs successive_ids = false: with successive ids, the ids of a shard
96
+ /// depend on the sizes of the shards before it.
97
+ size_t remove_ids(const IDSelector& sel) override;
98
+
94
99
  bool successive_ids;
95
100
 
96
101
  /// Synchronize the top-level index (IndexShards) with data in the
@@ -22,6 +22,7 @@
22
22
  #include <faiss/impl/ClusteringHelpers.h>
23
23
  #include <faiss/impl/FaissAssert.h>
24
24
  #include <faiss/impl/PdxLayout.h>
25
+ #include <faiss/impl/platform_macros.h>
25
26
  #include <faiss/impl/simd_dispatch.h>
26
27
  #include <faiss/utils/distances.h>
27
28
  #include <faiss/utils/random.h>
@@ -266,9 +267,9 @@ float adapt_d_prime(
266
267
  }
267
268
 
268
269
  /// Pre-loop setup: subsample, rotate, Forgy init, build ADSampling table,
269
- /// size the label scratch. Returned `sampled_x_owner` keeps the subsampled
270
- /// buffer alive when subsampling occurred (otherwise empty).
271
- std::unique_ptr<uint8_t[]> setup_train_state(
270
+ /// and size the label scratch. The subsampled input only needs to remain alive
271
+ /// through the rotation and is released before the iteration loop starts.
272
+ void setup_train_state(
272
273
  TrainState& state,
273
274
  std::vector<int64_t>& labels64,
274
275
  std::vector<float>& hassign,
@@ -276,10 +277,13 @@ std::unique_ptr<uint8_t[]> setup_train_state(
276
277
  int d,
277
278
  int k,
278
279
  idx_t n,
279
- const float* x) {
280
- const size_t line_size = sizeof(float) * static_cast<size_t>(d);
280
+ const void* x,
281
+ NumericType numeric_type) {
282
+ const bool fp16 = numeric_type == NumericType::Float16;
283
+ const size_t line_size =
284
+ (fp16 ? sizeof(uint16_t) : sizeof(float)) * static_cast<size_t>(d);
281
285
  idx_t nx = n;
282
- const uint8_t* x_bytes = reinterpret_cast<const uint8_t*>(x);
286
+ const uint8_t* x_bytes = static_cast<const uint8_t*>(x);
283
287
  std::unique_ptr<uint8_t[]> sampled_x_owner;
284
288
  if (static_cast<size_t>(nx) >
285
289
  static_cast<size_t>(k) * cp.max_points_per_centroid) {
@@ -298,7 +302,6 @@ std::unique_ptr<uint8_t[]> setup_train_state(
298
302
  sampled_x_owner.reset(x_new);
299
303
  x_bytes = x_new;
300
304
  }
301
- const float* x_sampled = reinterpret_cast<const float*>(x_bytes);
302
305
 
303
306
  FAISS_THROW_IF_NOT_MSG(
304
307
  nx <= static_cast<idx_t>(std::numeric_limits<int>::max()),
@@ -315,7 +318,28 @@ std::unique_ptr<uint8_t[]> setup_train_state(
315
318
  }
316
319
 
317
320
  state.X_tilde.resize(static_cast<size_t>(state.n) * d);
318
- state.R->apply_noalloc(state.n, x_sampled, state.X_tilde.data());
321
+ if (!fp16) {
322
+ state.R->apply_noalloc(
323
+ state.n,
324
+ reinterpret_cast<const float*>(x_bytes),
325
+ state.X_tilde.data());
326
+ } else {
327
+ const size_t block_size =
328
+ std::min(static_cast<size_t>(state.n), cp.decode_block_size);
329
+ std::vector<float> decoded(block_size * d);
330
+ const uint16_t* x16 = reinterpret_cast<const uint16_t*>(x_bytes);
331
+ for (size_t i0 = 0; i0 < static_cast<size_t>(state.n);
332
+ i0 += block_size) {
333
+ const size_t i1 =
334
+ std::min(static_cast<size_t>(state.n), i0 + block_size);
335
+ fp16_to_fp32((i1 - i0) * d, x16 + i0 * d, decoded.data());
336
+ state.R->apply_noalloc(
337
+ static_cast<idx_t>(i1 - i0),
338
+ decoded.data(),
339
+ state.X_tilde.data() + i0 * d);
340
+ }
341
+ }
342
+ sampled_x_owner.reset();
319
343
 
320
344
  // Forgy init: pick k random rows from the rotated pool as initial
321
345
  // centroids. These remain in rotated space; un-rotation happens
@@ -351,8 +375,6 @@ std::unique_ptr<uint8_t[]> setup_train_state(
351
375
  hassign.assign(k, 0.0f);
352
376
 
353
377
  labels64.resize(state.n);
354
-
355
- return sampled_x_owner;
356
378
  }
357
379
 
358
380
  /// Un-rotate centroids into output buffer. R orthogonal, so
@@ -411,15 +433,36 @@ SuperKMeans::SuperKMeans(int d, int k, const SuperKMeansParameters& cp_in)
411
433
  }
412
434
 
413
435
  void SuperKMeans::train(idx_t n, const float* x) {
436
+ train_ex(n, x, NumericType::Float32);
437
+ }
438
+
439
+ void SuperKMeans::train_ex(idx_t n, const void* x, NumericType numeric_type) {
440
+ FAISS_THROW_IF_NOT_MSG(
441
+ numeric_type == NumericType::Float32 ||
442
+ numeric_type == NumericType::Float16,
443
+ "SuperKMeans::train_ex: unsupported numeric type");
414
444
  FAISS_THROW_IF_NOT_MSG(n > 0, "SuperKMeans: n must be positive");
415
445
  FAISS_THROW_IF_MSG(x == nullptr, "SuperKMeans: x must not be null");
416
446
  FAISS_THROW_IF_NOT_MSG(
417
447
  n >= static_cast<idx_t>(k), "SuperKMeans: n must be >= k");
448
+ const bool fp16 = numeric_type == NumericType::Float16;
449
+ FAISS_THROW_IF_NOT_MSG(
450
+ !fp16 || cp.decode_block_size > 0,
451
+ "SuperKMeans: decode_block_size must be positive");
418
452
  if (cp.check_input_data_for_NaNs) {
419
- for (size_t i = 0; i < static_cast<size_t>(n) * d; i++) {
453
+ const size_t num_values = static_cast<size_t>(n) * d;
454
+ if (fp16) {
420
455
  FAISS_THROW_IF_NOT_MSG(
421
- std::isfinite(x[i]),
456
+ detail::fp16_all_finite(
457
+ num_values, static_cast<const uint16_t*>(x)),
422
458
  "SuperKMeans: input contains NaN's or Inf's");
459
+ } else {
460
+ const float* x32 = static_cast<const float*>(x);
461
+ for (size_t i = 0; i < num_values; i++) {
462
+ FAISS_THROW_IF_NOT_MSG(
463
+ std::isfinite(x32[i]),
464
+ "SuperKMeans: input contains NaN's or Inf's");
465
+ }
423
466
  }
424
467
  }
425
468
  if (cp.verbose && n < static_cast<idx_t>(k) * cp.min_points_per_centroid) {
@@ -435,8 +478,7 @@ void SuperKMeans::train(idx_t n, const float* x) {
435
478
  std::vector<int64_t> labels64;
436
479
  SuperKMeansAssignScratch assign_scratch;
437
480
  std::vector<float> hassign;
438
- [[maybe_unused]] auto sampled_x_owner =
439
- setup_train_state(state, labels64, hassign, cp, d, k, n, x);
481
+ setup_train_state(state, labels64, hassign, cp, d, k, n, x, numeric_type);
440
482
 
441
483
  iteration_stats.clear();
442
484
  iteration_stats.reserve(cp.niter);
@@ -625,7 +667,7 @@ void super_kmeans_assign_iteration(
625
667
  [[maybe_unused]] const int omp_chunk_local = cp.omp_chunk;
626
668
  int64_t tile_total = 0;
627
669
  int64_t tile_pruned = 0;
628
- #pragma omp parallel for schedule(dynamic, omp_chunk_local) \
670
+ #pragma omp parallel for schedule(FAISS_OMP_DYNAMIC, omp_chunk_local) \
629
671
  reduction(+ : tile_total) reduction(+ : tile_pruned)
630
672
  for (int i = 0; i < bx; ++i) {
631
673
  const float xnp_i = x_norms_partial[xi + i];
@@ -89,11 +89,16 @@ struct SuperKMeans {
89
89
 
90
90
  SuperKMeans(int d, int k, const SuperKMeansParameters& cp = {});
91
91
 
92
- /// Train on `n` row-major vectors of dimension `d`. Honors the applicable
93
- /// ClusteringParameters fields (niter, seed, verbose,
94
- /// max_points_per_centroid, use_faster_subsampling,
95
- /// check_input_data_for_NaNs).
92
+ /// Train on `n` row-major fp32 vectors of dimension `d`.
96
93
  void train(idx_t n, const float* x);
94
+
95
+ /** Train on vectors of the given numeric type.
96
+ *
97
+ * Float32 is the same as train(). Float16 takes packed IEEE binary16
98
+ * vectors and widens bounded blocks while rotating them into the fp32
99
+ * training workspace. Centroids and all iteration state remain fp32.
100
+ */
101
+ void train_ex(idx_t n, const void* x, NumericType numeric_type);
97
102
  };
98
103
 
99
104
  /// Reusable scratch for super_kmeans_assign_iteration; pass one instance across
@@ -17,6 +17,7 @@
17
17
 
18
18
  #include <faiss/IndexPQ.h>
19
19
  #include <faiss/impl/FaissAssert.h>
20
+ #include <faiss/impl/platform_macros.h>
20
21
  #include <faiss/utils/distances.h>
21
22
  #include <faiss/utils/random.h>
22
23
  #include <faiss/utils/utils.h>
@@ -481,7 +482,7 @@ void HadamardRotation::apply_noalloc(idx_t n, const float* x, float* xt) const {
481
482
  // Three rounds scale by p^(3/2). Normalize once at the end.
482
483
  float total_scale = 1.0f / (p * std::sqrt(static_cast<float>(p)));
483
484
 
484
- #pragma omp parallel for schedule(dynamic)
485
+ #pragma omp parallel for schedule(FAISS_OMP_DYNAMIC)
485
486
  for (idx_t i = 0; i < n; i++) {
486
487
  const float* xi = x + i * d;
487
488
  float* xo = xt + i * p;
@@ -526,7 +527,7 @@ void HadamardRotation::reverse_transform(idx_t n, const float* xt, float* x)
526
527
  // total_scale = 1/(p*sqrt(p)), so the inverse applies the same factor.
527
528
  const float inverse_scale = 1.0f / (p * std::sqrt(static_cast<float>(p)));
528
529
 
529
- #pragma omp parallel for schedule(dynamic)
530
+ #pragma omp parallel for schedule(FAISS_OMP_DYNAMIC)
530
531
  for (idx_t i = 0; i < n; i++) {
531
532
  const float* xi = xt + i * p;
532
533
  float* xo = x + i * p;
@@ -9,6 +9,8 @@
9
9
 
10
10
  #include <faiss/clone_index.h>
11
11
 
12
+ #include <memory>
13
+
12
14
  #include <faiss/impl/FaissAssert.h>
13
15
 
14
16
  #include <faiss/Index2Layer.h>
@@ -37,6 +39,7 @@
37
39
  #include <faiss/IndexNSG.h>
38
40
  #include <faiss/IndexPQ.h>
39
41
  #include <faiss/IndexPQFastScan.h>
42
+ #include <faiss/IndexPiPNN.h>
40
43
  #include <faiss/IndexPreTransform.h>
41
44
  #include <faiss/IndexRaBitQ.h>
42
45
  #include <faiss/IndexRefine.h>
@@ -170,6 +173,17 @@ IndexNSG* clone_IndexNSG(const IndexNSG* insg) {
170
173
  }
171
174
  }
172
175
 
176
+ static IndexPiPNN* clone_IndexPiPNN(const IndexPiPNN* ipipnn) {
177
+ TRYCLONE(IndexPiPNNFlat, ipipnn)
178
+ TRYCLONE(IndexPiPNNSQ, ipipnn) {
179
+ FAISS_THROW_IF_NOT_FMT(
180
+ typeid(*ipipnn) == typeid(IndexPiPNN),
181
+ "clone not supported for this type of IndexPiPNN: %s",
182
+ typeid(*ipipnn).name());
183
+ return new IndexPiPNN(*ipipnn);
184
+ }
185
+ }
186
+
173
187
  IndexRowwiseMinMaxBase* clone_IndexRowwiseMinMax(
174
188
  const IndexRowwiseMinMaxBase* irmmb) {
175
189
  TRYCLONE(IndexRowwiseMinMaxFP16, irmmb)
@@ -356,6 +370,16 @@ Index* Cloner::clone_Index(const Index* index) {
356
370
  res->own_fields = true;
357
371
  res->storage = clone_Index(insg->storage);
358
372
  return res;
373
+ } else if (
374
+ const IndexPiPNN* ipipnn = dynamic_cast<const IndexPiPNN*>(index)) {
375
+ // make sure we don't get a GPU index here
376
+ std::unique_ptr<Index> storage(
377
+ ipipnn->storage ? Cloner::clone_Index(ipipnn->storage)
378
+ : nullptr);
379
+ IndexPiPNN* res = clone_IndexPiPNN(ipipnn);
380
+ res->storage = storage.release();
381
+ res->own_fields = true;
382
+ return res;
359
383
  } else if (
360
384
  const IndexNNDescent* innd =
361
385
  dynamic_cast<const IndexNNDescent*>(index)) {
@@ -0,0 +1,112 @@
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
+ #pragma once
9
+
10
+ #include <faiss/Index.h>
11
+
12
+ #include <memory>
13
+
14
+ namespace faiss {
15
+ namespace gpu {
16
+ class GpuResourcesProvider;
17
+
18
+ /** Caller-controlled dense vector storage for cuVS CAGRA.
19
+ *
20
+ * Dimensions and row strides are in elements, with contiguous columns. Binary
21
+ * vectors use UInt8, and their dimension is the number of bytes, not bits.
22
+ * Views never own or copy their allocation. An owning Dataset controls the
23
+ * allocation's lifetime; CAGRA always borrows it. Keep the backing allocation
24
+ * alive and unchanged until all indexes using it and queued GPU work finish.
25
+ * Moving an owning Dataset preserves its allocation and existing borrowed
26
+ * views.
27
+ */
28
+ class Dataset {
29
+ public:
30
+ enum class Layout { Standard, Padded };
31
+
32
+ ~Dataset();
33
+ Dataset(Dataset&&) noexcept;
34
+ Dataset& operator=(Dataset&&) noexcept;
35
+ Dataset(const Dataset&) = delete;
36
+ Dataset& operator=(const Dataset&) = delete;
37
+
38
+ /// Borrow host storage. rowStride must be at least dim.
39
+ static Dataset viewHost(
40
+ const void* data,
41
+ idx_t numRows,
42
+ int dim,
43
+ NumericType numericType,
44
+ idx_t rowStride);
45
+
46
+ /// Borrow storage accessible on device. A Standard view can also be
47
+ /// CAGRA-compatible when its physical stride and alignment satisfy padding.
48
+ /// When used by CAGRA, elements between dim and rowStride must be zero.
49
+ static Dataset viewDevice(
50
+ const void* data,
51
+ idx_t numRows,
52
+ int dim,
53
+ NumericType numericType,
54
+ idx_t rowStride,
55
+ int device);
56
+
57
+ /// Borrow CAGRA-compatible device storage without copying. The base address
58
+ /// must be 16-byte aligned and rowStride must equal dim rounded up to a
59
+ /// 16-byte row width. The caller must zero elements between dim and
60
+ /// rowStride, including for compatible Standard views used by CAGRA.
61
+ static Dataset viewDevicePadded(
62
+ const void* data,
63
+ idx_t numRows,
64
+ int dim,
65
+ NumericType numericType,
66
+ idx_t rowStride,
67
+ int device);
68
+
69
+ /// Create padded device storage using cuVS make_device_padded_dataset.
70
+ /// Device/managed input whose stride already matches the required padding
71
+ /// is rejected; use a view for that storage. Copies logical columns and
72
+ /// zeroes padding asynchronously on the resource's stream. Source data must
73
+ /// be ready on that stream and stay alive and unchanged until copying
74
+ /// finishes. Order subsequent use on that stream. Retains the resources
75
+ /// needed to release the allocation.
76
+ static Dataset makeDevicePadded(
77
+ GpuResourcesProvider* resources,
78
+ const Dataset& source,
79
+ int device);
80
+
81
+ const void* getData() const;
82
+ idx_t getNumRows() const;
83
+ int getDim() const;
84
+ idx_t getRowStride() const;
85
+ NumericType getNumericType() const;
86
+ int getDevice() const; // -1 for host storage
87
+ Layout getLayout() const;
88
+ bool isDevice() const;
89
+ bool ownsData() const;
90
+
91
+ /// Reports device residency, base alignment, and exact required row stride.
92
+ /// Does not inspect padding values; zero padding is a caller contract.
93
+ bool isCagraCompatible() const;
94
+
95
+ /// Create a non-owning view of the same storage by copying its metadata.
96
+ /// Does not retain ownership of the backing allocation.
97
+ Dataset view() const;
98
+
99
+ /// Copy logical columns into packed host storage. destination must have
100
+ /// numRows * dim * sizeof(element) bytes. Completes all device work using
101
+ /// the source device before copying and returns with the host data ready.
102
+ void copyToHost(void* destination) const;
103
+
104
+ private:
105
+ struct Impl;
106
+ explicit Dataset(std::unique_ptr<Impl> impl);
107
+ const Impl& getImpl() const;
108
+ std::unique_ptr<Impl> impl_;
109
+ };
110
+
111
+ } // namespace gpu
112
+ } // namespace faiss
@@ -14,7 +14,7 @@
14
14
 
15
15
  #include <faiss/IndexBinaryFlat.h>
16
16
  #include <faiss/IndexFlat.h>
17
- #if defined(USE_NVIDIA_CUVS) && !defined(FAISS_CUVS_NO_CAGRA)
17
+ #if defined USE_NVIDIA_CUVS
18
18
  #include <faiss/IndexBinaryHNSW.h>
19
19
  #include <faiss/IndexHNSW.h>
20
20
  #endif
@@ -28,7 +28,7 @@
28
28
  #include <faiss/MetaIndexes.h>
29
29
  #include <faiss/gpu/GpuIndex.h>
30
30
  #include <faiss/gpu/GpuIndexBinaryFlat.h>
31
- #if defined(USE_NVIDIA_CUVS) && !defined(FAISS_CUVS_NO_CAGRA)
31
+ #if defined USE_NVIDIA_CUVS
32
32
  #include <faiss/gpu/GpuIndexBinaryCagra.h>
33
33
  #include <faiss/gpu/GpuIndexCagra.h>
34
34
  #endif
@@ -92,7 +92,7 @@ Index* ToCPUCloner::clone_Index(const Index* index) {
92
92
  // (inverse op of ToGpuClonerMultiple)
93
93
 
94
94
  }
95
- #if defined(USE_NVIDIA_CUVS) && !defined(FAISS_CUVS_NO_CAGRA)
95
+ #if defined USE_NVIDIA_CUVS
96
96
  else if (auto icg = dynamic_cast<const GpuIndexCagra*>(index)) {
97
97
  IndexHNSWCagra* res = new IndexHNSWCagra();
98
98
  if (icg->get_numeric_type() != faiss::NumericType::Float32) {
@@ -171,6 +171,7 @@ Index* ToGpuCloner::clone_Index(const Index* index) {
171
171
  config.flatConfig.useFloat16 = useFloat16CoarseQuantizer;
172
172
  config.use_cuvs = use_cuvs;
173
173
  config.allowCpuCoarseQuantizer = allowCpuCoarseQuantizer;
174
+ config.deterministic_tie_break = deterministic_tie_break;
174
175
 
175
176
  GpuIndexIVFFlat* res = new GpuIndexIVFFlat(
176
177
  provider, ifl->d, ifl->nlist, ifl->metric_type, config);
@@ -189,6 +190,7 @@ Index* ToGpuCloner::clone_Index(const Index* index) {
189
190
  config.flatConfig.useFloat16 = useFloat16CoarseQuantizer;
190
191
  config.use_cuvs = use_cuvs;
191
192
  config.allowCpuCoarseQuantizer = allowCpuCoarseQuantizer;
193
+ config.deterministic_tie_break = deterministic_tie_break;
192
194
 
193
195
  GpuIndexIVFScalarQuantizer* res = new GpuIndexIVFScalarQuantizer(
194
196
  provider,
@@ -224,6 +226,7 @@ Index* ToGpuCloner::clone_Index(const Index* index) {
224
226
  config.use_cuvs = use_cuvs;
225
227
  config.interleavedLayout = use_cuvs;
226
228
  config.allowCpuCoarseQuantizer = allowCpuCoarseQuantizer;
229
+ config.deterministic_tie_break = deterministic_tie_break;
227
230
 
228
231
  GpuIndexIVFPQ* res = new GpuIndexIVFPQ(provider, ipq, config);
229
232
 
@@ -233,14 +236,14 @@ Index* ToGpuCloner::clone_Index(const Index* index) {
233
236
 
234
237
  return res;
235
238
  }
236
- #if defined(USE_NVIDIA_CUVS) && !defined(FAISS_CUVS_NO_CAGRA)
239
+ #if defined USE_NVIDIA_CUVS
237
240
  else if (auto icg = dynamic_cast<const faiss::IndexHNSWCagra*>(index)) {
238
241
  GpuIndexCagraConfig config;
239
242
  config.device = device;
240
- GpuIndexCagra* res =
241
- new GpuIndexCagra(provider, icg->d, icg->metric_type, config);
242
- res->copyFrom_ex(icg, icg->get_numeric_type());
243
- return res;
243
+ auto res = std::make_unique<GpuIndexCagra>(
244
+ provider, icg->d, icg->metric_type, config);
245
+ res->copyFrom(icg);
246
+ return res.release();
244
247
  }
245
248
  #endif
246
249
  else {
@@ -533,7 +536,7 @@ faiss::IndexBinary* index_binary_gpu_to_cpu(
533
536
  ii->copyTo(ret);
534
537
  return ret;
535
538
  }
536
- #if defined(USE_NVIDIA_CUVS) && !defined(FAISS_CUVS_NO_CAGRA)
539
+ #if defined USE_NVIDIA_CUVS
537
540
  else if (auto ii = dynamic_cast<const GpuIndexBinaryCagra*>(gpu_index)) {
538
541
  IndexBinaryHNSWCagra* ret = new IndexBinaryHNSWCagra();
539
542
  ii->copyTo(ret);
@@ -555,15 +558,15 @@ faiss::IndexBinary* index_binary_cpu_to_gpu(
555
558
  config.device = device;
556
559
  return new GpuIndexBinaryFlat(provider, ii, config);
557
560
  }
558
- #if defined(USE_NVIDIA_CUVS) && !defined(FAISS_CUVS_NO_CAGRA)
561
+ #if defined USE_NVIDIA_CUVS
559
562
  else if (
560
563
  auto ii = dynamic_cast<const faiss::IndexBinaryHNSWCagra*>(index)) {
561
564
  GpuIndexCagraConfig config;
562
565
  config.device = device;
563
- GpuIndexBinaryCagra* res =
564
- new GpuIndexBinaryCagra(provider, ii->d, config);
566
+ auto res =
567
+ std::make_unique<GpuIndexBinaryCagra>(provider, ii->d, config);
565
568
  res->copyFrom(ii);
566
- return res;
569
+ return res.release();
567
570
  }
568
571
  #endif
569
572
  else {
@@ -70,6 +70,8 @@ struct ToGpuClonerMultiple : faiss::Cloner, GpuMultipleClonerOptions {
70
70
  faiss::Index* index_gpu_to_cpu(const faiss::Index* gpu_index);
71
71
 
72
72
  /// converts any CPU index that can be converted to GPU
73
+ /// CAGRA clones contain only the graph. Call updateDataset with caller-owned,
74
+ /// compatible device storage before searching.
73
75
  faiss::Index* index_cpu_to_gpu(
74
76
  GpuResourcesProvider* provider,
75
77
  int device,
@@ -105,6 +107,8 @@ faiss::IndexBinary* index_binary_gpu_to_cpu(
105
107
  const faiss::IndexBinary* gpu_index);
106
108
 
107
109
  /// converts any CPU index that can be converted to GPU
110
+ /// CAGRA clones contain only the graph. Call updateDataset with caller-owned,
111
+ /// compatible device storage before searching.
108
112
  faiss::IndexBinary* index_binary_cpu_to_gpu(
109
113
  GpuResourcesProvider* provider,
110
114
  int device,
@@ -42,6 +42,9 @@ struct GpuClonerOptions {
42
42
  /// Use the cuVS implementation. Opt-in: see GpuIndexConfig::use_cuvs.
43
43
  bool use_cuvs = false;
44
44
 
45
+ /// IVF indexes only: see GpuIndexIVFConfig::deterministic_tie_break.
46
+ bool deterministic_tie_break = false;
47
+
45
48
  /// This flag controls the CPU fallback logic for coarse quantizer
46
49
  /// component of the index. When set to false (default), the cloner will
47
50
  /// throw an exception for indices not implemented on GPU. When set to
@@ -213,6 +213,9 @@ class GpuIndex : public faiss::Index {
213
213
  idx_t* labels,
214
214
  const SearchParameters* params) const = 0;
215
215
 
216
+ /// Search with queries of the given numeric type; all data is guaranteed
217
+ /// to be resident on our device. The default handles Float32 and widens
218
+ /// Float16 queries to float32 on the device before calling searchImpl_
216
219
  virtual void searchImpl_ex_(
217
220
  idx_t n,
218
221
  const void* x,
@@ -220,19 +223,7 @@ class GpuIndex : public faiss::Index {
220
223
  int k,
221
224
  float* distances,
222
225
  idx_t* labels,
223
- const SearchParameters* params) const {
224
- if (numeric_type == NumericType::Float32) {
225
- searchImpl_(
226
- n,
227
- static_cast<const float*>(x),
228
- k,
229
- distances,
230
- labels,
231
- params);
232
- } else {
233
- FAISS_THROW_MSG("GpuIndex::searchImpl_: unsupported numeric type");
234
- }
235
- }
226
+ const SearchParameters* params) const;
236
227
 
237
228
  private:
238
229
  /// Calls addImpl_ for a single page of GPU-resident data