faiss 0.6.2 → 0.6.3

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 (144) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/lib/faiss/version.rb +1 -1
  4. data/vendor/faiss/faiss/AutoTune.cpp +3 -1
  5. data/vendor/faiss/faiss/Clustering.cpp +9 -1
  6. data/vendor/faiss/faiss/IVFlib.cpp +14 -3
  7. data/vendor/faiss/faiss/Index.h +2 -2
  8. data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +9 -10
  9. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +2 -3
  10. data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +1 -2
  11. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +4 -5
  12. data/vendor/faiss/faiss/IndexBinaryHash.cpp +5 -9
  13. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +2 -4
  14. data/vendor/faiss/faiss/IndexEDEN.cpp +273 -0
  15. data/vendor/faiss/faiss/IndexEDEN.h +57 -0
  16. data/vendor/faiss/faiss/IndexFastScan.cpp +15 -4
  17. data/vendor/faiss/faiss/IndexFlat.cpp +13 -50
  18. data/vendor/faiss/faiss/IndexHNSW.cpp +10 -11
  19. data/vendor/faiss/faiss/IndexIDMap.cpp +16 -3
  20. data/vendor/faiss/faiss/IndexIDMap.h +2 -0
  21. data/vendor/faiss/faiss/IndexIVF.cpp +17 -6
  22. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +1 -1
  23. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +3 -4
  24. data/vendor/faiss/faiss/IndexIVFEDEN.cpp +302 -0
  25. data/vendor/faiss/faiss/IndexIVFEDEN.h +70 -0
  26. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +5 -6
  27. data/vendor/faiss/faiss/IndexIVFFlat.cpp +3 -4
  28. data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +1 -1
  29. data/vendor/faiss/faiss/IndexIVFPQ.cpp +40 -22
  30. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +0 -1
  31. data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +19 -49
  32. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +180 -76
  33. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -4
  34. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +8 -6
  35. data/vendor/faiss/faiss/IndexLSH.cpp +2 -3
  36. data/vendor/faiss/faiss/IndexLattice.cpp +5 -0
  37. data/vendor/faiss/faiss/IndexNNDescent.cpp +9 -2
  38. data/vendor/faiss/faiss/IndexNSG.cpp +7 -2
  39. data/vendor/faiss/faiss/IndexPQ.cpp +6 -8
  40. data/vendor/faiss/faiss/IndexPreTransform.cpp +15 -0
  41. data/vendor/faiss/faiss/IndexRaBitQ.cpp +2 -2
  42. data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +1 -2
  43. data/vendor/faiss/faiss/IndexRaBitQFastScan.h +5 -1
  44. data/vendor/faiss/faiss/IndexRefine.cpp +30 -1
  45. data/vendor/faiss/faiss/IndexReplicas.cpp +1 -2
  46. data/vendor/faiss/faiss/IndexShards.cpp +2 -2
  47. data/vendor/faiss/faiss/IndexShardsIVF.cpp +2 -2
  48. data/vendor/faiss/faiss/MetaIndexes.cpp +2 -4
  49. data/vendor/faiss/faiss/SuperKMeans.cpp +256 -240
  50. data/vendor/faiss/faiss/SuperKMeans.h +30 -0
  51. data/vendor/faiss/faiss/VectorTransform.cpp +33 -2
  52. data/vendor/faiss/faiss/clone_index.cpp +5 -0
  53. data/vendor/faiss/faiss/factory_tools.cpp +47 -4
  54. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +11 -11
  55. data/vendor/faiss/faiss/gpu/GpuIndex.h +34 -11
  56. data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +47 -0
  57. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +17 -0
  58. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +16 -0
  59. data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +1 -1
  60. data/vendor/faiss/faiss/gpu/perf/PerfIVFPQAdd.cpp +2 -2
  61. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFScalarQuantizer.cpp +180 -0
  62. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFFlat.h +1 -5
  63. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +88 -0
  64. data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFPQ.h +134 -0
  65. data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +2 -2
  66. data/vendor/faiss/faiss/impl/DistanceComputer.h +34 -0
  67. data/vendor/faiss/faiss/impl/EDENQuantizer.h +119 -0
  68. data/vendor/faiss/faiss/impl/HNSW.cpp +109 -152
  69. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +2 -2
  70. data/vendor/faiss/faiss/impl/NSG.cpp +3 -1
  71. data/vendor/faiss/faiss/impl/Panorama.h +9 -7
  72. data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +152 -84
  73. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +34 -22
  74. data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +44 -36
  75. data/vendor/faiss/faiss/impl/RaBitQUtils.h +35 -0
  76. data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +168 -67
  77. data/vendor/faiss/faiss/impl/RaBitQuantizer.h +19 -0
  78. data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +2 -11
  79. data/vendor/faiss/faiss/impl/ResultHandler.h +25 -31
  80. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +258 -57
  81. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +20 -0
  82. data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +2 -2
  83. data/vendor/faiss/faiss/impl/VisitedTable.cpp +22 -2
  84. data/vendor/faiss/faiss/impl/VisitedTable.h +20 -0
  85. data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryIVF_impl.h +1 -1
  86. data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +4 -4
  87. data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +35 -2
  88. data/vendor/faiss/faiss/impl/hnsw/LockVector.cpp +1 -1
  89. data/vendor/faiss/faiss/impl/index_read.cpp +376 -36
  90. data/vendor/faiss/faiss/impl/index_write.cpp +55 -4
  91. data/vendor/faiss/faiss/impl/lattice_Zn.cpp +8 -9
  92. data/vendor/faiss/faiss/impl/platform_macros.h +3 -1
  93. data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +284 -0
  94. data/vendor/faiss/faiss/impl/polysemous_training/dispatch.h +115 -0
  95. data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQ_QueryTables.cpp +0 -1
  96. data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +26 -15
  97. data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +4 -4
  98. data/vendor/faiss/faiss/impl/result_handler/ResultHandler.cpp +195 -0
  99. data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +133 -0
  100. data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +281 -0
  101. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +72 -0
  102. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +228 -0
  103. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer.cpp +882 -0
  104. data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +9 -8
  105. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +85 -23
  106. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +30 -30
  107. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +4 -5
  108. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +101 -34
  109. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +136 -0
  110. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +16 -16
  111. data/vendor/faiss/faiss/impl/simd_dispatch.h +30 -9
  112. data/vendor/faiss/faiss/index_factory.cpp +32 -6
  113. data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
  114. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +2 -2
  115. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +19 -4
  116. data/vendor/faiss/faiss/python/python_callbacks.cpp +3 -1
  117. data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +60 -0
  118. data/vendor/faiss/faiss/svs/IndexSVSFlat.cpp +26 -1
  119. data/vendor/faiss/faiss/svs/IndexSVSFlat.h +13 -0
  120. data/vendor/faiss/faiss/svs/IndexSVSIVF.cpp +1 -1
  121. data/vendor/faiss/faiss/svs/IndexSVSIVFLeanVec.cpp +1 -1
  122. data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +31 -1
  123. data/vendor/faiss/faiss/svs/IndexSVSVamana.h +15 -2
  124. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +1 -2
  125. data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +1 -1
  126. data/vendor/faiss/faiss/utils/distances.cpp +14 -2
  127. data/vendor/faiss/faiss/utils/distances_simd.cpp +4 -3
  128. data/vendor/faiss/faiss/utils/extra_distances.cpp +4 -14
  129. data/vendor/faiss/faiss/utils/extra_distances.h +1 -2
  130. data/vendor/faiss/faiss/utils/hamming.cpp +1 -1
  131. data/vendor/faiss/faiss/utils/quantize_lut.cpp +29 -8
  132. data/vendor/faiss/faiss/utils/rabitq_simd.h +202 -0
  133. data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +0 -1
  134. data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +263 -15
  135. data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +160 -18
  136. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +245 -0
  137. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +273 -0
  138. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512_spr.cpp +92 -0
  139. data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +11 -0
  140. data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +143 -6
  141. data/vendor/faiss/faiss/utils/simd_levels.cpp +44 -0
  142. data/vendor/faiss/faiss/utils/simd_levels.h +14 -0
  143. data/vendor/faiss/faiss/utils/utils.cpp +9 -27
  144. metadata +16 -1
@@ -11,8 +11,10 @@
11
11
  #include <faiss/gpu/StandardGpuResources.h>
12
12
  #include <faiss/gpu/test/TestUtils.h>
13
13
  #include <faiss/gpu/utils/DeviceUtils.h>
14
+ #include <faiss/impl/IDSelector.h>
14
15
  #include <gtest/gtest.h>
15
16
  #include <cmath>
17
+ #include <limits> // IWYU pragma: keep
16
18
  #include <sstream>
17
19
  #include <vector>
18
20
 
@@ -74,6 +76,7 @@ void runCopyToTest(faiss::ScalarQuantizer::QuantizerType qtype) {
74
76
 
75
77
  auto config = GpuIndexIVFScalarQuantizerConfig();
76
78
  config.device = opt.device;
79
+ config.use_cuvs = false;
77
80
 
78
81
  GpuIndexIVFScalarQuantizer gpuIndex(
79
82
  &res, opt.dim, opt.numCentroids, qtype, METRIC_L2, true, config);
@@ -163,6 +166,7 @@ void runCopyFromTest(faiss::ScalarQuantizer::QuantizerType qtype) {
163
166
 
164
167
  auto config = GpuIndexIVFScalarQuantizerConfig();
165
168
  config.device = opt.device;
169
+ config.use_cuvs = false;
166
170
 
167
171
  GpuIndexIVFScalarQuantizer gpuIndex(
168
172
  &res,
@@ -223,6 +227,182 @@ TEST(TestGpuIndexIVFScalarQuantizer, CopyFrom_4bit_uniform) {
223
227
  runCopyFromTest(faiss::ScalarQuantizer::QuantizerType::QT_4bit_uniform);
224
228
  }
225
229
 
230
+ #if defined USE_NVIDIA_CUVS
231
+ void runCuvsSQ8Test(faiss::MetricType metricType) {
232
+ using namespace faiss;
233
+ using namespace faiss::gpu;
234
+
235
+ Options opt;
236
+ opt.indicesOpt = INDICES_64_BIT;
237
+
238
+ std::vector<float> trainVecs = randVecs(opt.numTrain, opt.dim);
239
+ std::vector<float> addVecs = randVecs(opt.numAdd, opt.dim);
240
+ std::vector<float> queryVecs = randVecs(opt.numQuery, opt.dim);
241
+
242
+ StandardGpuResources res;
243
+ res.noTempMemory();
244
+
245
+ auto config = GpuIndexIVFScalarQuantizerConfig();
246
+ config.device = opt.device;
247
+ config.indicesOptions = INDICES_64_BIT;
248
+ config.use_cuvs = true;
249
+ if (!should_use_cuvs(config)) {
250
+ GTEST_SKIP() << "cuVS is not enabled for this GPU";
251
+ }
252
+
253
+ GpuIndexIVFScalarQuantizer gpuIndex(
254
+ &res,
255
+ opt.dim,
256
+ opt.numCentroids,
257
+ ScalarQuantizer::QT_8bit,
258
+ metricType,
259
+ true,
260
+ config);
261
+ gpuIndex.train(opt.numTrain, trainVecs.data());
262
+ gpuIndex.add(opt.numAdd, addVecs.data());
263
+ gpuIndex.nprobe = opt.nprobe;
264
+
265
+ std::vector<float> distances(opt.numQuery * opt.k);
266
+ std::vector<idx_t> labels(opt.numQuery * opt.k);
267
+ gpuIndex.search(
268
+ opt.numQuery,
269
+ queryVecs.data(),
270
+ opt.k,
271
+ distances.data(),
272
+ labels.data());
273
+ EXPECT_EQ(gpuIndex.ntotal, opt.numAdd);
274
+ EXPECT_NE(labels[0], idx_t(-1));
275
+
276
+ IndexFlatL2 quantizerL2(opt.dim);
277
+ IndexFlatIP quantizerIP(opt.dim);
278
+ Index* quantizer = metricType == METRIC_L2 ? (Index*)&quantizerL2
279
+ : (Index*)&quantizerIP;
280
+
281
+ IndexIVFScalarQuantizer cpuCopy(
282
+ quantizer,
283
+ opt.dim,
284
+ opt.numCentroids,
285
+ ScalarQuantizer::QT_8bit,
286
+ metricType,
287
+ true);
288
+ gpuIndex.copyTo(&cpuCopy);
289
+ cpuCopy.nprobe = opt.nprobe;
290
+
291
+ EXPECT_EQ(cpuCopy.ntotal, gpuIndex.ntotal);
292
+ EXPECT_EQ(cpuCopy.d, gpuIndex.d);
293
+ EXPECT_EQ(cpuCopy.nlist, gpuIndex.getNumLists());
294
+ EXPECT_EQ(cpuCopy.sq.qtype, ScalarQuantizer::QT_8bit);
295
+ EXPECT_EQ(cpuCopy.sq.trained.size(), 2 * opt.dim);
296
+ EXPECT_TRUE(cpuCopy.by_residual);
297
+
298
+ compareIndices(
299
+ cpuCopy,
300
+ gpuIndex,
301
+ opt.numQuery,
302
+ opt.dim,
303
+ opt.k,
304
+ opt.toString(),
305
+ 0.08f,
306
+ 0.2f,
307
+ 0.05f);
308
+
309
+ GpuIndexIVFScalarQuantizer copiedGpuIndex(
310
+ &res, 1, 1, ScalarQuantizer::QT_4bit, METRIC_L2, false, config);
311
+ copiedGpuIndex.copyFrom(&cpuCopy);
312
+ copiedGpuIndex.nprobe = opt.nprobe;
313
+ EXPECT_EQ(copiedGpuIndex.ntotal, cpuCopy.ntotal);
314
+ testIVFEquality(cpuCopy, copiedGpuIndex);
315
+
316
+ compareIndices(
317
+ cpuCopy,
318
+ copiedGpuIndex,
319
+ opt.numQuery,
320
+ opt.dim,
321
+ opt.k,
322
+ opt.toString(),
323
+ 0.08f,
324
+ 0.2f,
325
+ 0.05f);
326
+
327
+ SearchParametersIVF searchParams;
328
+ searchParams.nprobe = opt.nprobe;
329
+ TestIDSelectorStruct selectorStruct(opt.numAdd);
330
+ for (auto& [selectorName, selector] : selectorStruct.selector_map) {
331
+ searchParams.sel = selector.get();
332
+ testIDSelectorSearch(
333
+ &gpuIndex,
334
+ &searchParams,
335
+ queryVecs,
336
+ opt.numQuery,
337
+ opt.k,
338
+ selectorName);
339
+ }
340
+
341
+ GpuIndexIVFScalarQuantizer shiftedGpuIndex(
342
+ &res,
343
+ opt.dim,
344
+ opt.numCentroids,
345
+ ScalarQuantizer::QT_8bit,
346
+ metricType,
347
+ true,
348
+ config);
349
+ shiftedGpuIndex.train(opt.numTrain, trainVecs.data());
350
+ std::vector<idx_t> shiftedIds(opt.numAdd);
351
+ idx_t shiftedIdBase = opt.numAdd * 4 + 123;
352
+ for (int i = 0; i < opt.numAdd; ++i) {
353
+ shiftedIds[i] = shiftedIdBase + i;
354
+ }
355
+ shiftedGpuIndex.add_with_ids(opt.numAdd, addVecs.data(), shiftedIds.data());
356
+ shiftedGpuIndex.nprobe = opt.nprobe;
357
+
358
+ SearchParametersIVF shiftedSearchParams;
359
+ shiftedSearchParams.nprobe = opt.nprobe;
360
+ IDSelectorRange shiftedSelector(shiftedIdBase, shiftedIdBase + opt.numAdd);
361
+ shiftedSearchParams.sel = &shiftedSelector;
362
+ std::vector<float> shiftedDistances(opt.numQuery * opt.k);
363
+ std::vector<idx_t> shiftedLabels(opt.numQuery * opt.k, -1);
364
+ shiftedGpuIndex.search(
365
+ opt.numQuery,
366
+ queryVecs.data(),
367
+ opt.k,
368
+ shiftedDistances.data(),
369
+ shiftedLabels.data(),
370
+ &shiftedSearchParams);
371
+
372
+ bool foundShiftedLabel = false;
373
+ for (idx_t label : shiftedLabels) {
374
+ if (label >= 0) {
375
+ foundShiftedLabel = true;
376
+ EXPECT_TRUE(shiftedSelector.is_member(label));
377
+ }
378
+ }
379
+ EXPECT_TRUE(foundShiftedLabel);
380
+
381
+ auto nanQueries = queryVecs;
382
+ nanQueries[opt.dim + 3] = std::numeric_limits<float>::quiet_NaN();
383
+ gpuIndex.search(
384
+ 2, nanQueries.data(), opt.k, distances.data(), labels.data());
385
+ for (int j = 0; j < opt.k; ++j) {
386
+ EXPECT_EQ(labels[opt.k + j], idx_t(-1));
387
+ EXPECT_EQ(distances[opt.k + j], std::numeric_limits<float>::max());
388
+ }
389
+
390
+ gpuIndex.reset();
391
+ EXPECT_EQ(gpuIndex.ntotal, 0);
392
+ for (int i = 0; i < opt.numCentroids; ++i) {
393
+ EXPECT_EQ(gpuIndex.getListLength(i), 0);
394
+ }
395
+ }
396
+
397
+ TEST(TestCuvsGpuIndexIVFScalarQuantizer, SQ8_L2) {
398
+ runCuvsSQ8Test(faiss::METRIC_L2);
399
+ }
400
+
401
+ TEST(TestCuvsGpuIndexIVFScalarQuantizer, SQ8_IP) {
402
+ runCuvsSQ8Test(faiss::METRIC_INNER_PRODUCT);
403
+ }
404
+ #endif
405
+
226
406
  int main(int argc, char** argv) {
227
407
  testing::InitGoogleTest(&argc, argv);
228
408
 
@@ -21,12 +21,8 @@
21
21
 
22
22
  namespace faiss {
23
23
  namespace gpu_metal {
24
- class MetalIVFFlatImpl;
25
- } // namespace gpu_metal
26
- } // namespace faiss
27
24
 
28
- namespace faiss {
29
- namespace gpu_metal {
25
+ class MetalIVFFlatImpl;
30
26
 
31
27
  /// IVFFlat index wrapper for Metal backend.
32
28
  /// Currently delegates to an internal CPU IndexIVFFlat; later phases
@@ -0,0 +1,88 @@
1
+ // @lint-ignore-every LICENSELINT
2
+ /**
3
+ * Copyright (c) Meta Platforms, Inc. and its affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ *
8
+ * Metal IVF-PQ index: 8-bit product quantization with precomputed
9
+ * per-query lookup tables and GPU IVF list scanning.
10
+ */
11
+
12
+ #pragma once
13
+
14
+ #import <Metal/Metal.h>
15
+
16
+ #include <faiss/IndexIVFPQ.h>
17
+ #include <faiss/gpu_metal/MetalIndex.h>
18
+
19
+ #include <memory>
20
+
21
+ namespace faiss {
22
+ namespace gpu_metal {
23
+
24
+ class MetalIVFPQImpl;
25
+
26
+ class MetalIndexIVFPQ : public MetalIndex {
27
+ public:
28
+ MetalIndexIVFPQ(
29
+ std::shared_ptr<MetalResources> resources,
30
+ int dims,
31
+ idx_t nlist,
32
+ int M,
33
+ int nbitsPerIdx,
34
+ faiss::MetricType metric,
35
+ float metricArg = 0.0f,
36
+ MetalIndexConfig config = MetalIndexConfig());
37
+
38
+ MetalIndexIVFPQ(
39
+ std::shared_ptr<MetalResources> resources,
40
+ const faiss::IndexIVFPQ* cpuIndex,
41
+ MetalIndexConfig config = MetalIndexConfig());
42
+
43
+ ~MetalIndexIVFPQ() override;
44
+
45
+ void train(idx_t n, const float* x) override;
46
+ void add(idx_t n, const float* x) override;
47
+ void add_with_ids(idx_t n, const float* x, const idx_t* xids) override;
48
+ void reset() override;
49
+
50
+ void search(
51
+ idx_t n,
52
+ const float* x,
53
+ idx_t k,
54
+ float* distances,
55
+ idx_t* labels,
56
+ const SearchParameters* params = nullptr) const override;
57
+
58
+ void copyFrom(const faiss::IndexIVFPQ* index);
59
+ void copyTo(faiss::IndexIVFPQ* index) const;
60
+
61
+ void updateQuantizer();
62
+ std::vector<idx_t> getListIndices(idx_t listId) const;
63
+ void reclaimMemory();
64
+
65
+ /// Pre-allocate GPU storage for the given total number of vectors.
66
+ void reserveMemory(idx_t numVecs);
67
+
68
+ idx_t nlist() const;
69
+ size_t nprobe() const;
70
+ int getNumSubQuantizers() const;
71
+ void setUsePrecomputedTables(bool enable);
72
+ bool getUsePrecomputedTables() const;
73
+
74
+ private:
75
+ std::unique_ptr<faiss::IndexIVFPQ> cpuIndex_;
76
+ std::unique_ptr<MetalIVFPQImpl> gpuIvf_;
77
+
78
+ void verifyPQSettings_() const;
79
+
80
+ void encodeResidualAndAppend_(
81
+ idx_t n,
82
+ const float* x,
83
+ const idx_t* list_nos,
84
+ const idx_t* xids);
85
+ };
86
+
87
+ } // namespace gpu_metal
88
+ } // namespace faiss
@@ -0,0 +1,134 @@
1
+ // @lint-ignore-every LICENSELINT
2
+ /**
3
+ * Copyright (c) Meta Platforms, Inc. and its affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ *
8
+ * Metal IVF PQ implementation: GPU-resident IVF list storage for
9
+ * 8-bit product-quantized codes. Each vector is M bytes (one byte
10
+ * per subquantizer, ksub=256).
11
+ */
12
+
13
+ #pragma once
14
+
15
+ #import <Metal/Metal.h>
16
+
17
+ #include <cstddef>
18
+ #include <cstdint>
19
+ #include <memory>
20
+ #include <vector>
21
+
22
+ #include <faiss/Index.h>
23
+ #include <faiss/MetricType.h>
24
+ #include <faiss/gpu_metal/MetalResources.h>
25
+
26
+ namespace faiss {
27
+ namespace gpu_metal {
28
+
29
+ class MetalIVFPQImpl {
30
+ public:
31
+ MetalIVFPQImpl(
32
+ std::shared_ptr<MetalResources> resources,
33
+ int dim,
34
+ idx_t nlist,
35
+ int numSubQuantizers,
36
+ int bitsPerCode,
37
+ faiss::MetricType metric,
38
+ float metricArg);
39
+
40
+ ~MetalIVFPQImpl();
41
+
42
+ void reset();
43
+ void reserveMemory(idx_t totalVecs);
44
+
45
+ /// Append PQ-encoded vectors. codes: n * codeSize bytes.
46
+ void appendCodes(
47
+ idx_t n,
48
+ const uint8_t* codes,
49
+ const idx_t* list_nos,
50
+ const idx_t* xids);
51
+
52
+ /// Upload PQ centroids: M * ksub * dsub floats, row-major.
53
+ /// Layout: pqCentroids[m][c][dsub_dim]
54
+ void setPQCentroids(const float* centroids);
55
+
56
+ int dim() const {
57
+ return dim_;
58
+ }
59
+ idx_t nlist() const {
60
+ return nlist_;
61
+ }
62
+ int numSubQuantizers() const {
63
+ return M_;
64
+ }
65
+ int bitsPerCode() const {
66
+ return bitsPerCode_;
67
+ }
68
+ int ksub() const {
69
+ return ksub_;
70
+ }
71
+ int dsub() const {
72
+ return dsub_;
73
+ }
74
+ size_t codeSize() const {
75
+ return codeSize_;
76
+ }
77
+
78
+ const std::vector<size_t>& listLength() const {
79
+ return listLength_;
80
+ }
81
+ const std::vector<size_t>& listOffset() const {
82
+ return listOffset_;
83
+ }
84
+
85
+ id<MTLBuffer> codesBuffer() const {
86
+ return codesBuffer_;
87
+ }
88
+ id<MTLBuffer> idsBuffer() const {
89
+ return idsBuffer_;
90
+ }
91
+ id<MTLBuffer> listOffsetGpuBuffer() const {
92
+ return listOffsetBuf_;
93
+ }
94
+ id<MTLBuffer> listLengthGpuBuffer() const {
95
+ return listLengthBuf_;
96
+ }
97
+ id<MTLBuffer> pqCentroidsBuffer() const {
98
+ return pqCentroidsBuf_;
99
+ }
100
+ size_t totalVecs() const {
101
+ return totalVecs_;
102
+ }
103
+
104
+ private:
105
+ void uploadToGpu();
106
+
107
+ std::shared_ptr<MetalResources> resources_;
108
+
109
+ int dim_;
110
+ idx_t nlist_;
111
+ int M_;
112
+ int bitsPerCode_;
113
+ int ksub_;
114
+ int dsub_;
115
+ size_t codeSize_;
116
+ faiss::MetricType metric_type_;
117
+ float metric_arg_;
118
+
119
+ std::vector<size_t> listLength_;
120
+ std::vector<size_t> listOffset_;
121
+
122
+ std::vector<uint8_t> hostCodes_;
123
+ std::vector<idx_t> hostIds_;
124
+ size_t totalVecs_;
125
+
126
+ id<MTLBuffer> codesBuffer_;
127
+ id<MTLBuffer> idsBuffer_;
128
+ id<MTLBuffer> listOffsetBuf_;
129
+ id<MTLBuffer> listLengthBuf_;
130
+ id<MTLBuffer> pqCentroidsBuf_;
131
+ };
132
+
133
+ } // namespace gpu_metal
134
+ } // namespace faiss
@@ -157,8 +157,8 @@ void ClusteringInitialization::init_centroids(
157
157
  n,
158
158
  k);
159
159
  FAISS_THROW_IF_NOT(d > 0);
160
- FAISS_THROW_IF_NOT(x != nullptr);
161
- FAISS_THROW_IF_NOT(centroids != nullptr);
160
+ FAISS_THROW_IF_NOT(x);
161
+ FAISS_THROW_IF_NOT(centroids);
162
162
  FAISS_THROW_IF_NOT(
163
163
  n_existing_centroids == 0 || existing_centroids != nullptr);
164
164
 
@@ -130,6 +130,26 @@ struct FlatCodesDistanceComputer : DistanceComputer {
130
130
  return distance_to_code(codes + i * code_size);
131
131
  }
132
132
 
133
+ void distances_batch_4(
134
+ const idx_t idx0,
135
+ const idx_t idx1,
136
+ const idx_t idx2,
137
+ const idx_t idx3,
138
+ float& dis0,
139
+ float& dis1,
140
+ float& dis2,
141
+ float& dis3) override {
142
+ distance_to_code_batch_4(
143
+ codes + idx0 * code_size,
144
+ codes + idx1 * code_size,
145
+ codes + idx2 * code_size,
146
+ codes + idx3 * code_size,
147
+ dis0,
148
+ dis1,
149
+ dis2,
150
+ dis3);
151
+ }
152
+
133
153
  /// Computes a partial dot product over a slice of the query vector.
134
154
  /// The slice is defined by the following parameters:
135
155
  /// — `offset`: the starting index of the first component to include
@@ -167,6 +187,20 @@ struct FlatCodesDistanceComputer : DistanceComputer {
167
187
 
168
188
  /// compute distance of current query to an encoded vector
169
189
  virtual float distance_to_code(const uint8_t* code) = 0;
190
+ virtual void distance_to_code_batch_4(
191
+ const uint8_t* c1,
192
+ const uint8_t* c2,
193
+ const uint8_t* c3,
194
+ const uint8_t* c4,
195
+ float& d1,
196
+ float& d2,
197
+ float& d3,
198
+ float& d4) {
199
+ d1 = distance_to_code(c1);
200
+ d2 = distance_to_code(c2);
201
+ d3 = distance_to_code(c3);
202
+ d4 = distance_to_code(c4);
203
+ }
170
204
 
171
205
  /// Compute partial dot products of current query to 4 stored vectors.
172
206
  /// See `partial_dot_product` for more details.
@@ -0,0 +1,119 @@
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 <cstddef>
11
+ #include <cstdint>
12
+
13
+ #include <faiss/MetricType.h>
14
+ #include <faiss/impl/DistanceComputer.h>
15
+ #include <faiss/impl/ScalarQuantizer.h>
16
+ #include <faiss/impl/platform_macros.h>
17
+
18
+ namespace faiss {
19
+
20
+ enum EDENScaleType {
21
+ // Original EDEN unbiased scale.
22
+ EDENScaleType_UNBIASED = 1,
23
+ // Biased DRIVE scale (NeurIPS 2021, arXiv:2105.08339), generalized to
24
+ // multi-bit EDEN; see also https://arxiv.org/abs/2604.18555.
25
+ EDENScaleType_BIASED = 2,
26
+ };
27
+
28
+ FAISS_PACK_STRUCTS_BEGIN
29
+ struct FAISS_PACKED EDENCodeFactors {
30
+ // L2 term used by the distance computer. For the unbiased scale this is
31
+ // ||r||^2. For the biased scale this is S^2 * ||q_code||^2, the
32
+ // reconstructed-code norm.
33
+ float l2_norm_term = 0;
34
+ // Per-vector reconstruction scale.
35
+ float scale = 0;
36
+ };
37
+ FAISS_PACK_STRUCTS_END
38
+
39
+ struct EDENFlatCodesDistanceComputer : FlatCodesDistanceComputer {
40
+ using FlatCodesDistanceComputer::FlatCodesDistanceComputer;
41
+
42
+ virtual void consecutive_distances_batch_8(idx_t first, float* distances) {
43
+ distances_batch_4(
44
+ first,
45
+ first + 1,
46
+ first + 2,
47
+ first + 3,
48
+ distances[0],
49
+ distances[1],
50
+ distances[2],
51
+ distances[3]);
52
+ distances_batch_4(
53
+ first + 4,
54
+ first + 5,
55
+ first + 6,
56
+ first + 7,
57
+ distances[4],
58
+ distances[5],
59
+ distances[6],
60
+ distances[7]);
61
+ }
62
+
63
+ virtual void consecutive_distances_batch_16(idx_t first, float* distances) {
64
+ consecutive_distances_batch_8(first, distances);
65
+ consecutive_distances_batch_8(first + 8, distances + 8);
66
+ }
67
+ };
68
+
69
+ // EDEN Lloyd-Max quantizer from the EDEN ICML 2022 paper:
70
+ // https://proceedings.mlr.press/v162/vargaftik22a.html.
71
+ //
72
+ // EDEN operates on the vectors supplied to it. Optional preprocessing such as
73
+ // a random rotation can be applied externally with IndexPreTransform. The
74
+ // scalar assignment itself is a ScalarQuantizer::QT_*_eden qtype. EDEN adds
75
+ // per-vector scale factors after the packed scalar code and computes them
76
+ // against an externally supplied centroid; nullptr means a zero centroid. The
77
+ // default stored scale is EDEN's original unbiased scale. The biased scale
78
+ // follows DRIVE's MSE-minimizing scale for the chosen Lloyd-Max codeword; see
79
+ // also
80
+ // https://arxiv.org/abs/2604.18555.
81
+
82
+ namespace eden_utils {
83
+
84
+ ScalarQuantizer::QuantizerType quantizer_type_for_bits(size_t nb_bits);
85
+
86
+ bool is_eden_quantizer_type(ScalarQuantizer::QuantizerType qtype);
87
+
88
+ size_t nb_bits_for_qtype(ScalarQuantizer::QuantizerType qtype);
89
+
90
+ size_t packed_code_size(size_t d, size_t nb_bits);
91
+
92
+ size_t code_size(size_t d, size_t nb_bits);
93
+
94
+ uint8_t extract_code(const uint8_t* codes, size_t index, size_t nb_bits);
95
+
96
+ void compute_codes(
97
+ const ScalarQuantizer& sq,
98
+ MetricType metric_type,
99
+ EDENScaleType scale_type,
100
+ const float* x,
101
+ uint8_t* codes,
102
+ size_t n,
103
+ const float* centroid = nullptr);
104
+
105
+ void decode(
106
+ const ScalarQuantizer& sq,
107
+ const uint8_t* codes,
108
+ float* x,
109
+ size_t n,
110
+ const float* centroid = nullptr);
111
+
112
+ EDENFlatCodesDistanceComputer* get_distance_computer(
113
+ const ScalarQuantizer& sq,
114
+ MetricType metric_type,
115
+ const float* centroid = nullptr);
116
+
117
+ } // namespace eden_utils
118
+
119
+ } // namespace faiss