faiss 0.6.1 → 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 (186) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -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 +10 -12
  12. data/vendor/faiss/faiss/IndexBinaryHash.cpp +5 -9
  13. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +5 -7
  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 +177 -148
  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 +19 -8
  22. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +3 -3
  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 +6 -5
  28. data/vendor/faiss/faiss/IndexIVFFlatPanorama.cpp +3 -3
  29. data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +1 -1
  30. data/vendor/faiss/faiss/IndexIVFPQ.cpp +42 -25
  31. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +0 -1
  32. data/vendor/faiss/faiss/IndexIVFPQR.cpp +2 -3
  33. data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +23 -62
  34. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +180 -76
  35. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -4
  36. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +8 -6
  37. data/vendor/faiss/faiss/IndexLSH.cpp +2 -3
  38. data/vendor/faiss/faiss/IndexLattice.cpp +5 -0
  39. data/vendor/faiss/faiss/IndexNNDescent.cpp +10 -3
  40. data/vendor/faiss/faiss/IndexNSG.cpp +8 -4
  41. data/vendor/faiss/faiss/IndexPQ.cpp +6 -8
  42. data/vendor/faiss/faiss/IndexPreTransform.cpp +15 -0
  43. data/vendor/faiss/faiss/IndexRaBitQ.cpp +2 -2
  44. data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +1 -2
  45. data/vendor/faiss/faiss/IndexRaBitQFastScan.h +5 -1
  46. data/vendor/faiss/faiss/IndexRefine.cpp +30 -1
  47. data/vendor/faiss/faiss/IndexReplicas.cpp +1 -2
  48. data/vendor/faiss/faiss/IndexScalarQuantizer.cpp +68 -6
  49. data/vendor/faiss/faiss/IndexScalarQuantizer.h +10 -0
  50. data/vendor/faiss/faiss/IndexShards.cpp +2 -2
  51. data/vendor/faiss/faiss/IndexShardsIVF.cpp +2 -2
  52. data/vendor/faiss/faiss/MetaIndexes.cpp +2 -4
  53. data/vendor/faiss/faiss/SuperKMeans.cpp +256 -240
  54. data/vendor/faiss/faiss/SuperKMeans.h +30 -0
  55. data/vendor/faiss/faiss/VectorTransform.cpp +33 -2
  56. data/vendor/faiss/faiss/clone_index.cpp +5 -0
  57. data/vendor/faiss/faiss/cppcontrib/SaDecodeKernels.h +1 -1
  58. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-neon-inl.h +902 -12
  59. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-neon-inl.h +702 -10
  60. data/vendor/faiss/faiss/factory_tools.cpp +51 -4
  61. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +11 -11
  62. data/vendor/faiss/faiss/gpu/GpuIndex.h +34 -11
  63. data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +47 -0
  64. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +17 -0
  65. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +16 -0
  66. data/vendor/faiss/faiss/gpu/GpuResources.h +3 -2
  67. data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +11 -12
  68. data/vendor/faiss/faiss/gpu/StandardGpuResources.h +3 -3
  69. data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +1 -1
  70. data/vendor/faiss/faiss/gpu/perf/PerfIVFPQAdd.cpp +2 -2
  71. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFScalarQuantizer.cpp +180 -0
  72. data/vendor/faiss/faiss/gpu_metal/MetalDistance.h +87 -0
  73. data/vendor/faiss/faiss/gpu_metal/MetalIndex.h +7 -0
  74. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFFlat.h +177 -0
  75. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +88 -0
  76. data/vendor/faiss/faiss/gpu_metal/MetalKernels.h +48 -3
  77. data/vendor/faiss/faiss/gpu_metal/MetalPythonBridge.h +45 -0
  78. data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFFlat.h +193 -0
  79. data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFPQ.h +134 -0
  80. data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +2 -2
  81. data/vendor/faiss/faiss/impl/DistanceComputer.h +34 -0
  82. data/vendor/faiss/faiss/impl/EDENQuantizer.h +119 -0
  83. data/vendor/faiss/faiss/impl/HNSW.cpp +658 -344
  84. data/vendor/faiss/faiss/impl/HNSW.h +51 -13
  85. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +2 -2
  86. data/vendor/faiss/faiss/impl/NSG.cpp +18 -12
  87. data/vendor/faiss/faiss/impl/Panorama.h +20 -7
  88. data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +152 -84
  89. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +59 -24
  90. data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +45 -37
  91. data/vendor/faiss/faiss/impl/RaBitQUtils.h +35 -0
  92. data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +175 -68
  93. data/vendor/faiss/faiss/impl/RaBitQuantizer.h +19 -0
  94. data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +2 -11
  95. data/vendor/faiss/faiss/impl/ResultHandler.h +26 -31
  96. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +522 -58
  97. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +70 -0
  98. data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +2 -2
  99. data/vendor/faiss/faiss/impl/VisitedTable.cpp +33 -13
  100. data/vendor/faiss/faiss/impl/VisitedTable.h +88 -33
  101. data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryIVF_impl.h +1 -1
  102. data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +4 -4
  103. data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +38 -3
  104. data/vendor/faiss/faiss/impl/hnsw/LockVector.cpp +1 -1
  105. data/vendor/faiss/faiss/impl/hnsw/MinimaxHeap.cpp +35 -43
  106. data/vendor/faiss/faiss/impl/hnsw/MinimaxHeap.h +64 -15
  107. data/vendor/faiss/faiss/impl/hnsw/avx2.cpp +86 -40
  108. data/vendor/faiss/faiss/impl/hnsw/avx512.cpp +81 -50
  109. data/vendor/faiss/faiss/impl/index_read.cpp +476 -75
  110. data/vendor/faiss/faiss/impl/index_write.cpp +56 -4
  111. data/vendor/faiss/faiss/impl/io_macros.h +25 -0
  112. data/vendor/faiss/faiss/impl/lattice_Zn.cpp +8 -9
  113. data/vendor/faiss/faiss/impl/platform_macros.h +15 -9
  114. data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +284 -0
  115. data/vendor/faiss/faiss/impl/polysemous_training/dispatch.h +115 -0
  116. data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQ_QueryTables.cpp +0 -1
  117. data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +26 -15
  118. data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +6 -4
  119. data/vendor/faiss/faiss/impl/pq_code_distance/avx512.cpp +2 -0
  120. data/vendor/faiss/faiss/impl/pq_code_distance/neon.cpp +2 -0
  121. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +20 -0
  122. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-inl.h +36 -0
  123. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-sve.cpp +5 -0
  124. data/vendor/faiss/faiss/impl/pq_code_distance/pq_scan_impl.h +105 -0
  125. data/vendor/faiss/faiss/impl/pq_code_distance/rvv.cpp +2 -0
  126. data/vendor/faiss/faiss/impl/result_handler/ResultHandler.cpp +195 -0
  127. data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +133 -0
  128. data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +281 -0
  129. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +72 -0
  130. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +228 -0
  131. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer.cpp +882 -0
  132. data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +6 -0
  133. data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +336 -26
  134. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +331 -32
  135. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +553 -0
  136. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +558 -0
  137. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +284 -45
  138. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +502 -3
  139. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +157 -32
  140. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-rvv.cpp +26 -0
  141. data/vendor/faiss/faiss/impl/simd_dispatch.h +86 -8
  142. data/vendor/faiss/faiss/index_factory.cpp +37 -7
  143. data/vendor/faiss/faiss/index_io.h +16 -0
  144. data/vendor/faiss/faiss/invlists/DirectMap.cpp +5 -2
  145. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +15 -15
  146. data/vendor/faiss/faiss/invlists/InvertedLists.h +2 -2
  147. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +19 -4
  148. data/vendor/faiss/faiss/python/python_callbacks.cpp +3 -1
  149. data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +60 -0
  150. data/vendor/faiss/faiss/svs/IndexSVSFlat.cpp +26 -1
  151. data/vendor/faiss/faiss/svs/IndexSVSFlat.h +13 -0
  152. data/vendor/faiss/faiss/svs/IndexSVSIVF.cpp +1 -1
  153. data/vendor/faiss/faiss/svs/IndexSVSIVFLeanVec.cpp +1 -1
  154. data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +150 -23
  155. data/vendor/faiss/faiss/svs/IndexSVSVamana.h +30 -7
  156. data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.cpp +3 -2
  157. data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.h +2 -1
  158. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +65 -25
  159. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.h +3 -2
  160. data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +1 -1
  161. data/vendor/faiss/faiss/utils/bf16.h +34 -0
  162. data/vendor/faiss/faiss/utils/distances.cpp +14 -2
  163. data/vendor/faiss/faiss/utils/distances_simd.cpp +4 -4
  164. data/vendor/faiss/faiss/utils/extra_distances.cpp +4 -14
  165. data/vendor/faiss/faiss/utils/extra_distances.h +1 -2
  166. data/vendor/faiss/faiss/utils/hamming.cpp +9 -9
  167. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx2.cpp +2 -1
  168. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_spr.cpp +15 -0
  169. data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512.h +6 -30
  170. data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512_spr.h +171 -0
  171. data/vendor/faiss/faiss/utils/partitioning.cpp +0 -2
  172. data/vendor/faiss/faiss/utils/quantize_lut.cpp +29 -8
  173. data/vendor/faiss/faiss/utils/rabitq_simd.h +202 -0
  174. data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +0 -1
  175. data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +263 -15
  176. data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +160 -18
  177. data/vendor/faiss/faiss/utils/simd_impl/partitioning_simdlib256.h +14 -68
  178. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +245 -0
  179. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +273 -0
  180. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512_spr.cpp +435 -0
  181. data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +11 -0
  182. data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +143 -6
  183. data/vendor/faiss/faiss/utils/simd_levels.cpp +56 -2
  184. data/vendor/faiss/faiss/utils/simd_levels.h +14 -0
  185. data/vendor/faiss/faiss/utils/utils.cpp +9 -27
  186. metadata +27 -2
@@ -25,11 +25,13 @@
25
25
  #include <faiss/Index2Layer.h>
26
26
  #include <faiss/IndexAdditiveQuantizer.h>
27
27
  #include <faiss/IndexAdditiveQuantizerFastScan.h>
28
+ #include <faiss/IndexEDEN.h>
28
29
  #include <faiss/IndexFlat.h>
29
30
  #include <faiss/IndexHNSW.h>
30
31
  #include <faiss/IndexIVF.h>
31
32
  #include <faiss/IndexIVFAdditiveQuantizer.h>
32
33
  #include <faiss/IndexIVFAdditiveQuantizerFastScan.h>
34
+ #include <faiss/IndexIVFEDEN.h>
33
35
  #include <faiss/IndexIVFFlat.h>
34
36
  #include <faiss/IndexIVFFlatPanorama.h>
35
37
  #include <faiss/IndexIVFIndependentQuantizer.h>
@@ -63,6 +65,7 @@
63
65
  #include <faiss/IndexScalarQuantizer.h>
64
66
  #include <faiss/MetaIndexes.h>
65
67
  #include <faiss/VectorTransform.h>
68
+ #include <faiss/impl/EDENQuantizer.h>
66
69
 
67
70
  #include <faiss/IndexBinaryFlat.h>
68
71
  #include <faiss/IndexBinaryFromFloat.h>
@@ -439,6 +442,20 @@ static void write_RaBitQuantizer(
439
442
  }
440
443
  }
441
444
 
445
+ static void write_EDENScalarQuantizer(
446
+ const ScalarQuantizer* sq,
447
+ MetricType metric_type,
448
+ EDENScaleType scale_type,
449
+ size_t full_code_size,
450
+ IOWriter* f) {
451
+ WRITE1(sq->d);
452
+ WRITE1(full_code_size);
453
+ WRITE1(metric_type);
454
+ WRITE1(sq->bits);
455
+ int scale_type_int = static_cast<int>(scale_type);
456
+ WRITE1(scale_type_int);
457
+ }
458
+
442
459
  static void write_direct_map(const DirectMap* dm, IOWriter* f) {
443
460
  char maintain_direct_map =
444
461
  (char)dm->type; // for backwards compatibility with bool
@@ -871,8 +888,12 @@ void write_index(const Index* idx, IOWriter* f, int io_flags) {
871
888
  : dynamic_cast<const IndexHNSWSQ*>(idx) ? fourcc("IHNs")
872
889
  : dynamic_cast<const IndexHNSW2Level*>(idx) ? fourcc("IHN2")
873
890
  : dynamic_cast<const IndexHNSWCagra*>(idx) ? fourcc("IHc2")
891
+ : typeid(*idx) == typeid(IndexHNSW) ? fourcc("IH00")
874
892
  : 0;
875
- FAISS_THROW_IF_NOT(h != 0);
893
+ FAISS_THROW_IF_NOT_FMT(
894
+ h != 0,
895
+ "don't know how to serialize this IndexHNSW subtype: %s",
896
+ typeid(*idx).name());
876
897
  WRITE1(h);
877
898
  write_index_header(idxhnsw, f);
878
899
  if (h == fourcc("IHfP")) {
@@ -900,7 +921,8 @@ void write_index(const Index* idx, IOWriter* f, int io_flags) {
900
921
  : dynamic_cast<const IndexNSGPQ*>(idx) ? fourcc("INSp")
901
922
  : dynamic_cast<const IndexNSGSQ*>(idx) ? fourcc("INSs")
902
923
  : 0;
903
- FAISS_THROW_IF_NOT(h != 0);
924
+ FAISS_THROW_IF_MSG(
925
+ h == 0, "don't know how to serialize this IndexNSG subtype");
904
926
  WRITE1(h);
905
927
  write_index_header(idxnsg, f);
906
928
  WRITE1(idxnsg->GK);
@@ -915,9 +937,11 @@ void write_index(const Index* idx, IOWriter* f, int io_flags) {
915
937
  const IndexNNDescent* idxnnd =
916
938
  dynamic_cast<const IndexNNDescent*>(idx)) {
917
939
  auto idxnndflat = dynamic_cast<const IndexNNDescentFlat*>(idx);
918
- FAISS_THROW_IF_NOT(idxnndflat != nullptr);
940
+ FAISS_THROW_IF_NOT(idxnndflat);
919
941
  uint32_t h = fourcc("INNf");
920
- FAISS_THROW_IF_NOT(h != 0);
942
+ FAISS_THROW_IF_MSG(
943
+ h == 0,
944
+ "don't know how to serialize this IndexNNDescent subtype");
921
945
  WRITE1(h);
922
946
  write_index_header(idxnnd, f);
923
947
  write_NNDescent(&idxnnd->nndescent, f);
@@ -965,6 +989,33 @@ void write_index(const Index* idx, IOWriter* f, int io_flags) {
965
989
  WRITE1(h);
966
990
  write_index_header(imm_2, f);
967
991
  write_index(imm_2->index, f);
992
+ } else if (const IndexEDEN* idxe = dynamic_cast<const IndexEDEN*>(idx)) {
993
+ uint32_t h = fourcc("IxEe");
994
+ WRITE1(h);
995
+ write_index_header(idx, f);
996
+ write_EDENScalarQuantizer(
997
+ &idxe->sq,
998
+ idxe->metric_type,
999
+ idxe->scale_type,
1000
+ idxe->code_size,
1001
+ f);
1002
+ WRITEVECTOR(idxe->codes);
1003
+ WRITEVECTOR(idxe->center);
1004
+ } else if (
1005
+ const IndexIVFEDEN* iveden =
1006
+ dynamic_cast<const IndexIVFEDEN*>(idx)) {
1007
+ uint32_t h = fourcc("IwEe");
1008
+ WRITE1(h);
1009
+ write_ivf_header(iveden, f);
1010
+ write_EDENScalarQuantizer(
1011
+ &iveden->sq,
1012
+ iveden->metric_type,
1013
+ iveden->scale_type,
1014
+ iveden->code_size,
1015
+ f);
1016
+ WRITE1(iveden->code_size);
1017
+ WRITE1(iveden->by_residual);
1018
+ write_InvertedLists(iveden->invlists, f);
968
1019
  } else if (
969
1020
  const IndexRaBitQFastScan* idxqfs =
970
1021
  dynamic_cast<const IndexRaBitQFastScan*>(idx)) {
@@ -1044,6 +1095,7 @@ void write_index(const Index* idx, IOWriter* f, int io_flags) {
1044
1095
  WRITE1(svs->prune_to);
1045
1096
  WRITE1(svs->use_full_search_history);
1046
1097
  WRITE1(svs->storage_kind);
1098
+ WRITE1(svs->is_static);
1047
1099
 
1048
1100
  if (lean != nullptr) {
1049
1101
  WRITE1(lean->leanvec_d);
@@ -35,6 +35,31 @@ size_t get_deserialization_vector_byte_limit();
35
35
 
36
36
  #define READ1(x) READANDCHECK(&(x), 1)
37
37
 
38
+ // Reads a single byte into a bool, rejecting any byte that is not the
39
+ // canonical encoding for the platform's bool representation. Reading a
40
+ // non-canonical byte directly into a bool is undefined behavior and
41
+ // trips UBSan's invalid-bool-load check. To stay ABI-portable, we
42
+ // assign via the language-defined conversion (b != 0) and then compare
43
+ // the resulting bool's storage byte back against the byte we read - the
44
+ // roundtrip succeeds iff the input byte was already canonical on this
45
+ // platform. FAISS only ever writes the canonical encoding via
46
+ // WRITE1(bool), so well-formed indices roundtrip cleanly; corrupt or
47
+ // attacker-controlled input that places a non-canonical byte at a bool
48
+ // offset is rejected as a FaissException.
49
+ #define READ1_BOOL(x) \
50
+ { \
51
+ static_assert( \
52
+ sizeof(x) == 1, "READ1_BOOL: destination must be 1 byte"); \
53
+ uint8_t b; \
54
+ READANDCHECK(&b, 1); \
55
+ (x) = (b != 0); \
56
+ FAISS_THROW_IF_NOT_FMT( \
57
+ *reinterpret_cast<const uint8_t*>(&(x)) == b, \
58
+ "invalid bool encoding 0x%02x for %s", \
59
+ b, \
60
+ #x); \
61
+ }
62
+
38
63
  #define READ1_DUMMY(x_type) \
39
64
  { \
40
65
  x_type x = {}; \
@@ -557,12 +557,11 @@ ZnSphereCodecRec::ZnSphereCodecRec(int dim_in, int r2_in)
557
557
 
558
558
  decode_cache.resize((r2 + 1));
559
559
 
560
- // The decode cache stores total_cache_entries * dimsub floats.
561
- // Cap at 2^27 total floats (~512 MB), aligned with the nv_cum
562
- // memory cap above which also uses 2^27 entries. The entry count
563
- // grows as the number of lattice points in dimension
564
- // 2^cache_level, which is O(r2^(dim/2)) -- much faster than the
565
- // O(r2^2) growth of nv_cum.
560
+ // The decode cache stores total_cache_entries * dimsub floats and is
561
+ // built with one decode() call per entry. The entry count grows as the
562
+ // number of lattice points in dimension 2^cache_level, which is
563
+ // O(r2^(dim/2)) -- much faster than the O(r2^2) growth of nv_cum, so it
564
+ // is bounded per-r2sub in the loop below.
566
565
  size_t total_cache_entries = 0;
567
566
  int dimsub = (1 << cache_level);
568
567
 
@@ -571,9 +570,9 @@ ZnSphereCodecRec::ZnSphereCodecRec(int dim_in, int r2_in)
571
570
  uint64_t nvi = get_nv(ld, r2sub);
572
571
  total_cache_entries += nvi;
573
572
  FAISS_THROW_IF_NOT_MSG(
574
- total_cache_entries <= (size_t(1) << 27) / dimsub,
575
- "ZnSphereCodecRec: r2 too large, decode cache "
576
- "would require excessive memory");
573
+ total_cache_entries <= (size_t(1) << 27) / (size_t)dim,
574
+ "ZnSphereCodecRec: r2/dim too large, decode cache "
575
+ "would require excessive memory and computation");
577
576
  std::vector<float>& cache = decode_cache[r2sub];
578
577
  cache.resize(nvi * dimsub);
579
578
  std::vector<float> c(dim);
@@ -25,7 +25,9 @@
25
25
 
26
26
  #define strtok_r strtok_s
27
27
 
28
- #ifdef _MSC_VER
28
+ // clang-cl defines _MSC_VER but provides __PRETTY_FUNCTION__ itself, in
29
+ // clang's format. Redefining it there breaks code that parses it.
30
+ #if defined(_MSC_VER) && !defined(__clang__)
29
31
  #define __PRETTY_FUNCTION__ __FUNCSIG__
30
32
  #endif // _MSC_VER
31
33
 
@@ -110,12 +112,6 @@ inline int __builtin_clzll(uint64_t x) {
110
112
  #define FAISS_PACK_STRUCTS_BEGIN __pragma(pack(push, 1))
111
113
  #define FAISS_PACK_STRUCTS_END __pragma(pack(pop))
112
114
 
113
- #ifdef SWIG
114
- #define FAISS_MAYBE_UNUSED
115
- #else
116
- #define FAISS_MAYBE_UNUSED [[maybe_unused]]
117
- #endif
118
-
119
115
  #else
120
116
  /*******************************************************
121
117
  * Linux and OSX
@@ -130,12 +126,10 @@ inline int __builtin_clzll(uint64_t x) {
130
126
  #define ALIGNED(x)
131
127
  #define FAISS_PACKED
132
128
  #define FAISS_RESTRICT
133
- #define FAISS_MAYBE_UNUSED
134
129
  #else
135
130
  #define ALIGNED(x) __attribute__((aligned(x)))
136
131
  #define FAISS_PACKED __attribute__((packed))
137
132
  #define FAISS_RESTRICT __restrict
138
- #define FAISS_MAYBE_UNUSED [[maybe_unused]]
139
133
  #endif
140
134
 
141
135
  // On non-Windows, FAISS_PACKED handles packing, so these are no-ops
@@ -220,3 +214,15 @@ inline int __builtin_clzll(uint64_t x) {
220
214
  #define Swap4Bytes(val) \
221
215
  ((((val) >> 24) & 0x000000FF) | (((val) >> 8) & 0x0000FF00) | \
222
216
  (((val) << 8) & 0x00FF0000) | (((val) << 24) & 0xFF000000))
217
+
218
+ /*******************************************************
219
+ * A few things that SWIG has trouble parsing
220
+ *******************************************************/
221
+
222
+ #ifdef SWIG
223
+ #define FAISS_MAYBE_UNUSED
224
+ #define FAISS_FINAL
225
+ #else
226
+ #define FAISS_MAYBE_UNUSED [[maybe_unused]]
227
+ #define FAISS_FINAL final
228
+ #endif
@@ -0,0 +1,284 @@
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
+ // -*- c++ -*-
9
+
10
+ #ifdef COMPILE_SIMD_AVX512
11
+
12
+ #include <faiss/impl/PolysemousTraining.h>
13
+ #include <faiss/impl/polysemous_training/dispatch.h>
14
+ #include <faiss/utils/popcount.h>
15
+
16
+ #include <immintrin.h>
17
+ #include <cstdint>
18
+
19
+ namespace faiss {
20
+ namespace {
21
+
22
+ inline int hamming_dis(uint64_t a, uint64_t b) {
23
+ return popcount64(a ^ b);
24
+ }
25
+
26
+ inline double sqr(double x) {
27
+ return x * x;
28
+ }
29
+
30
+ inline __m512i popcnt_512(__m512i v) {
31
+ #ifdef __AVX512VPOPCNTDQ__
32
+ return _mm512_popcnt_epi64(v);
33
+ #else
34
+ const __m128i nibble_popcount =
35
+ _mm_setr_epi8(0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4);
36
+ const __m512i lookup = _mm512_broadcast_i32x4(nibble_popcount);
37
+
38
+ const __m512i low_mask = _mm512_set1_epi8(0x0f);
39
+ const __m512i lo = _mm512_and_si512(v, low_mask);
40
+ const __m512i hi = _mm512_and_si512(_mm512_srli_epi16(v, 4), low_mask);
41
+
42
+ const __m512i popcnt_lo = _mm512_shuffle_epi8(lookup, lo);
43
+ const __m512i popcnt_hi = _mm512_shuffle_epi8(lookup, hi);
44
+ const __m512i popcnt_bytes = _mm512_add_epi8(popcnt_lo, popcnt_hi);
45
+
46
+ return _mm512_sad_epu8(popcnt_bytes, _mm512_setzero_si512());
47
+ #endif
48
+ }
49
+
50
+ } // namespace
51
+
52
+ namespace polysemous_training {
53
+
54
+ template <>
55
+ double hamming_compute_cost<SIMDLevel::AVX512>(
56
+ int n,
57
+ const int* perm,
58
+ const double* target_dis,
59
+ const double* weights) {
60
+ double total_cost = 0.0;
61
+ for (int i = 0; i < n; i++) {
62
+ __m512d cost_vec = _mm512_setzero_pd();
63
+ const __m512i perm_i_vec = _mm512_set1_epi64(perm[i]);
64
+ const int bro = i * n;
65
+ int j = 0;
66
+ for (; j <= n - 8; j += 8) {
67
+ const __m512d wanted_vec = _mm512_loadu_pd(&target_dis[bro + j]);
68
+ const __m512d w_vec = _mm512_loadu_pd(&weights[bro + j]);
69
+ const __m256i pj32 = _mm256_loadu_si256((__m256i const*)&perm[j]);
70
+ const __m512i pj64 = _mm512_cvtepi32_epi64(pj32);
71
+ const __m512i xor_res = _mm512_xor_si512(perm_i_vec, pj64);
72
+ const __m512d actual_vec = _mm512_cvtepi64_pd(popcnt_512(xor_res));
73
+ const __m512d diff = _mm512_sub_pd(wanted_vec, actual_vec);
74
+ cost_vec =
75
+ _mm512_fmadd_pd(w_vec, _mm512_mul_pd(diff, diff), cost_vec);
76
+ }
77
+ total_cost += _mm512_reduce_add_pd(cost_vec);
78
+ for (; j < n; j++) {
79
+ double wanted = target_dis[bro + j];
80
+ double w = weights[bro + j];
81
+ double actual = hamming_dis(perm[i], perm[j]);
82
+ total_cost += w * sqr(wanted - actual);
83
+ }
84
+ }
85
+ return total_cost;
86
+ }
87
+
88
+ template <>
89
+ double hamming_cost_update<SIMDLevel::AVX512>(
90
+ int n,
91
+ const int* perm,
92
+ int iw,
93
+ int jw,
94
+ const double* target_dis,
95
+ const double* weights) {
96
+ double delta_cost_scalar = 0;
97
+ const __m512i v_idx_base = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7);
98
+ // Loop-invariant across the j-loop and both process_row calls.
99
+ const __m512i v_iw = _mm512_set1_epi64(iw);
100
+ const __m512i v_jw = _mm512_set1_epi64(jw);
101
+ const __m512i v_perm_iw = _mm512_set1_epi64(perm[iw]);
102
+ const __m512i v_perm_jw = _mm512_set1_epi64(perm[jw]);
103
+ __m512d delta_cost_vec = _mm512_setzero_pd();
104
+
105
+ auto process_row = [&](int row, int old_pi, int new_pi) {
106
+ const int bro = row * n;
107
+ const __m512i v_old = _mm512_set1_epi64(old_pi);
108
+ const __m512i v_new = _mm512_set1_epi64(new_pi);
109
+ int j = 0;
110
+ for (; j <= n - 8; j += 8) {
111
+ __m512d wv = _mm512_loadu_pd(&target_dis[bro + j]);
112
+ __m512d ww = _mm512_loadu_pd(&weights[bro + j]);
113
+ __m256i pj32 = _mm256_loadu_si256((__m256i const*)&perm[j]);
114
+ __m512i pjv = _mm512_cvtepi32_epi64(pj32);
115
+ __m512d av = _mm512_cvtepi64_pd(
116
+ popcnt_512(_mm512_xor_si512(v_old, pjv)));
117
+ __m512d to = _mm512_sub_pd(wv, av);
118
+ to = _mm512_mul_pd(to, to);
119
+ delta_cost_vec = _mm512_fnmadd_pd(ww, to, delta_cost_vec);
120
+
121
+ __m512i ji = _mm512_add_epi64(_mm512_set1_epi64(j), v_idx_base);
122
+ __mmask8 miw = _mm512_cmpeq_epi64_mask(ji, v_iw);
123
+ __mmask8 mjw = _mm512_cmpeq_epi64_mask(ji, v_jw);
124
+ __m512i pnj = _mm512_mask_blend_epi64(mjw, pjv, v_perm_iw);
125
+ pnj = _mm512_mask_blend_epi64(miw, pnj, v_perm_jw);
126
+ __m512d nav = _mm512_cvtepi64_pd(
127
+ popcnt_512(_mm512_xor_si512(v_new, pnj)));
128
+ __m512d tn = _mm512_sub_pd(wv, nav);
129
+ tn = _mm512_mul_pd(tn, tn);
130
+ delta_cost_vec = _mm512_fmadd_pd(ww, tn, delta_cost_vec);
131
+ }
132
+ for (; j < n; j++) {
133
+ double wanted = target_dis[bro + j];
134
+ double w = weights[bro + j];
135
+ double actual = hamming_dis(old_pi, perm[j]);
136
+ delta_cost_scalar -= w * sqr(wanted - actual);
137
+ double new_actual = hamming_dis(
138
+ new_pi,
139
+ perm[j == iw ? jw
140
+ : j == jw ? iw
141
+ : j]);
142
+ delta_cost_scalar += w * sqr(wanted - new_actual);
143
+ }
144
+ };
145
+ process_row(iw, perm[iw], perm[jw]);
146
+ process_row(jw, perm[jw], perm[iw]);
147
+
148
+ for (int i = 0; i < n; ++i) {
149
+ if (i == iw || i == jw)
150
+ continue;
151
+ int j = iw;
152
+ {
153
+ double wanted = target_dis[i * n + j];
154
+ double w = weights[i * n + j];
155
+ delta_cost_scalar -=
156
+ w * sqr(wanted - hamming_dis(perm[i], perm[j]));
157
+ delta_cost_scalar +=
158
+ w * sqr(wanted - hamming_dis(perm[i], perm[jw]));
159
+ }
160
+ j = jw;
161
+ {
162
+ double wanted = target_dis[i * n + j];
163
+ double w = weights[i * n + j];
164
+ delta_cost_scalar -=
165
+ w * sqr(wanted - hamming_dis(perm[i], perm[j]));
166
+ delta_cost_scalar +=
167
+ w * sqr(wanted - hamming_dis(perm[i], perm[iw]));
168
+ }
169
+ }
170
+ return _mm512_reduce_add_pd(delta_cost_vec) + delta_cost_scalar;
171
+ }
172
+
173
+ template <>
174
+ double distances_compute_cost<SIMDLevel::AVX512>(
175
+ const ReproduceDistancesObjective& obj,
176
+ const int* perm) {
177
+ const int n = obj.n;
178
+ double total_cost = 0.0;
179
+ for (int i = 0; i < n; ++i) {
180
+ const int pi = perm[i];
181
+ const int bro_t = i * n;
182
+ const int bro_s = pi * n;
183
+ __m512d sum = _mm512_setzero_pd();
184
+ int j = 0;
185
+ for (; j <= n - 8; j += 8) {
186
+ __m512d wv = _mm512_loadu_pd(&obj.target_dis[bro_t + j]);
187
+ __m512d ww = _mm512_loadu_pd(&obj.weights[bro_t + j]);
188
+ __m256i pj = _mm256_loadu_si256(
189
+ reinterpret_cast<const __m256i*>(&perm[j]));
190
+ __m256i idx = _mm256_add_epi32(_mm256_set1_epi32(bro_s), pj);
191
+ __m512d av = _mm512_i32gather_pd(idx, obj.source_dis.data(), 8);
192
+ __m512d d = _mm512_sub_pd(wv, av);
193
+ sum = _mm512_fmadd_pd(_mm512_mul_pd(d, d), ww, sum);
194
+ }
195
+ total_cost += _mm512_reduce_add_pd(sum);
196
+ for (; j < n; ++j) {
197
+ double wanted = obj.target_dis[bro_t + j];
198
+ double w = obj.weights[bro_t + j];
199
+ double actual = obj.get_source_dis(pi, perm[j]);
200
+ total_cost += w * sqr(wanted - actual);
201
+ }
202
+ }
203
+ return total_cost;
204
+ }
205
+
206
+ template <>
207
+ double distances_cost_update<SIMDLevel::AVX512>(
208
+ const ReproduceDistancesObjective& obj,
209
+ const int* perm,
210
+ int iw,
211
+ int jw) {
212
+ const int n = obj.n;
213
+ double delta_cost = 0.0;
214
+ const int p_iw = perm[iw], p_jw = perm[jw];
215
+ const __m256i v_joff = _mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0);
216
+ const __m256i vi = _mm256_set1_epi32(iw);
217
+ const __m256i vj = _mm256_set1_epi32(jw);
218
+ const __m256i vpi = _mm256_set1_epi32(p_iw);
219
+ const __m256i vpj = _mm256_set1_epi32(p_jw);
220
+ const __m256i vpin = _mm256_set1_epi32(p_iw * n);
221
+ const __m256i vpjn = _mm256_set1_epi32(p_jw * n);
222
+
223
+ auto process_row =
224
+ [&](int row, int old_p, int new_p, __m256i old_pn, __m256i new_pn) {
225
+ const int bro = row * n;
226
+ __m512d dv = _mm512_setzero_pd();
227
+ int j = 0;
228
+ for (; j <= n - 8; j += 8) {
229
+ __m512d wv = _mm512_loadu_pd(&obj.target_dis[bro + j]);
230
+ __m512d ww = _mm512_loadu_pd(&obj.weights[bro + j]);
231
+ __m256i pjv = _mm256_loadu_si256(
232
+ reinterpret_cast<const __m256i*>(&perm[j]));
233
+ __m256i ia = _mm256_add_epi32(old_pn, pjv);
234
+ __m512d av =
235
+ _mm512_i32gather_pd(ia, obj.source_dis.data(), 8);
236
+ __m512d da = _mm512_sub_pd(wv, av);
237
+ dv = _mm512_fnmadd_pd(ww, _mm512_mul_pd(da, da), dv);
238
+ __m256i vk = _mm256_add_epi32(_mm256_set1_epi32(j), v_joff);
239
+ __mmask8 mi = _mm256_cmpeq_epi32_mask(vk, vi);
240
+ __mmask8 mj = _mm256_cmpeq_epi32_mask(vk, vj);
241
+ __m256i pnj = _mm256_mask_blend_epi32(mi, pjv, vpj);
242
+ pnj = _mm256_mask_blend_epi32(mj, pnj, vpi);
243
+ __m256i in2 = _mm256_add_epi32(new_pn, pnj);
244
+ __m512d nav =
245
+ _mm512_i32gather_pd(in2, obj.source_dis.data(), 8);
246
+ __m512d dn = _mm512_sub_pd(wv, nav);
247
+ dv = _mm512_fmadd_pd(ww, _mm512_mul_pd(dn, dn), dv);
248
+ }
249
+ delta_cost += _mm512_reduce_add_pd(dv);
250
+ for (; j < n; ++j) {
251
+ double wanted = obj.target_dis[bro + j];
252
+ double w = obj.weights[bro + j];
253
+ double actual = obj.get_source_dis(old_p, perm[j]);
254
+ delta_cost -= w * sqr(wanted - actual);
255
+ int pnj = (j == iw) ? p_jw : ((j == jw) ? p_iw : perm[j]);
256
+ double na = obj.get_source_dis(new_p, pnj);
257
+ delta_cost += w * sqr(wanted - na);
258
+ }
259
+ };
260
+ process_row(iw, p_iw, p_jw, vpin, vpjn);
261
+ process_row(jw, p_jw, p_iw, vpjn, vpin);
262
+
263
+ for (int i = 0; i < n; ++i) {
264
+ if (i == iw || i == jw)
265
+ continue;
266
+ double wanted = obj.target_dis[i * n + iw], w = obj.weights[i * n + iw];
267
+ double actual = obj.get_source_dis(perm[i], p_iw);
268
+ delta_cost -= w * sqr(wanted - actual);
269
+ double na = obj.get_source_dis(perm[i], p_jw);
270
+ delta_cost += w * sqr(wanted - na);
271
+ wanted = obj.target_dis[i * n + jw];
272
+ w = obj.weights[i * n + jw];
273
+ actual = obj.get_source_dis(perm[i], p_jw);
274
+ delta_cost -= w * sqr(wanted - actual);
275
+ na = obj.get_source_dis(perm[i], p_iw);
276
+ delta_cost += w * sqr(wanted - na);
277
+ }
278
+ return delta_cost;
279
+ }
280
+
281
+ } // namespace polysemous_training
282
+ } // namespace faiss
283
+
284
+ #endif // COMPILE_SIMD_AVX512
@@ -0,0 +1,115 @@
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/utils/simd_levels.h>
11
+
12
+ namespace faiss {
13
+
14
+ struct ReproduceDistancesObjective;
15
+
16
+ namespace polysemous_training {
17
+
18
+ // Levels with a dedicated kernel: scalar (NONE) plus AVX-512. Any other runtime
19
+ // level (AVX2, NEON, ...) falls back to NONE via with_selected_simd_levels /
20
+ // get_simd_fallback, and AVX512_SPR reuses the AVX-512 kernel.
21
+ constexpr int SIMD_LEVELS =
22
+ (1 << int(SIMDLevel::NONE)) | (1 << int(SIMDLevel::AVX512));
23
+
24
+ /// compute_cost for ReproduceWithHammingObjective.
25
+ /// Parameters mirror the objective's fields to avoid exposing the
26
+ /// anonymous-namespace struct.
27
+ template <SIMDLevel SL>
28
+ double hamming_compute_cost(
29
+ int n,
30
+ const int* perm,
31
+ const double* target_dis,
32
+ const double* weights);
33
+
34
+ /// cost_update for ReproduceWithHammingObjective.
35
+ template <SIMDLevel SL>
36
+ double hamming_cost_update(
37
+ int n,
38
+ const int* perm,
39
+ int iw,
40
+ int jw,
41
+ const double* target_dis,
42
+ const double* weights);
43
+
44
+ /// compute_cost for ReproduceDistancesObjective.
45
+ template <SIMDLevel SL>
46
+ double distances_compute_cost(
47
+ const ReproduceDistancesObjective& obj,
48
+ const int* perm);
49
+
50
+ /// cost_update for ReproduceDistancesObjective.
51
+ template <SIMDLevel SL>
52
+ double distances_cost_update(
53
+ const ReproduceDistancesObjective& obj,
54
+ const int* perm,
55
+ int iw,
56
+ int jw);
57
+
58
+ // The scalar (NONE) specializations are defined in PolysemousTraining.cpp; the
59
+ // AVX-512 specializations are defined in polysemous_training/avx512.cpp. Both
60
+ // are declared here so callers instantiate the out-of-line definition rather
61
+ // than implicitly instantiating the (undefined) primary template.
62
+ template <>
63
+ double hamming_compute_cost<SIMDLevel::NONE>(
64
+ int n,
65
+ const int* perm,
66
+ const double* target_dis,
67
+ const double* weights);
68
+ template <>
69
+ double hamming_compute_cost<SIMDLevel::AVX512>(
70
+ int n,
71
+ const int* perm,
72
+ const double* target_dis,
73
+ const double* weights);
74
+
75
+ template <>
76
+ double hamming_cost_update<SIMDLevel::NONE>(
77
+ int n,
78
+ const int* perm,
79
+ int iw,
80
+ int jw,
81
+ const double* target_dis,
82
+ const double* weights);
83
+ template <>
84
+ double hamming_cost_update<SIMDLevel::AVX512>(
85
+ int n,
86
+ const int* perm,
87
+ int iw,
88
+ int jw,
89
+ const double* target_dis,
90
+ const double* weights);
91
+
92
+ template <>
93
+ double distances_compute_cost<SIMDLevel::NONE>(
94
+ const ReproduceDistancesObjective& obj,
95
+ const int* perm);
96
+ template <>
97
+ double distances_compute_cost<SIMDLevel::AVX512>(
98
+ const ReproduceDistancesObjective& obj,
99
+ const int* perm);
100
+
101
+ template <>
102
+ double distances_cost_update<SIMDLevel::NONE>(
103
+ const ReproduceDistancesObjective& obj,
104
+ const int* perm,
105
+ int iw,
106
+ int jw);
107
+ template <>
108
+ double distances_cost_update<SIMDLevel::AVX512>(
109
+ const ReproduceDistancesObjective& obj,
110
+ const int* perm,
111
+ int iw,
112
+ int jw);
113
+
114
+ } // namespace polysemous_training
115
+ } // namespace faiss
@@ -7,7 +7,6 @@
7
7
 
8
8
  #include <faiss/impl/pq_code_distance/IVFPQ_QueryTables.h>
9
9
 
10
- #include <faiss/Clustering.h>
11
10
  #include <faiss/utils/distances_dispatch.h>
12
11
 
13
12
  namespace faiss {