faiss 0.2.4 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (178) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +23 -21
  5. data/ext/faiss/extconf.rb +11 -0
  6. data/ext/faiss/index.cpp +17 -4
  7. data/ext/faiss/index_binary.cpp +6 -6
  8. data/ext/faiss/product_quantizer.cpp +4 -4
  9. data/lib/faiss/version.rb +1 -1
  10. data/vendor/faiss/faiss/AutoTune.cpp +13 -0
  11. data/vendor/faiss/faiss/IVFlib.cpp +101 -2
  12. data/vendor/faiss/faiss/IVFlib.h +26 -2
  13. data/vendor/faiss/faiss/Index.cpp +36 -3
  14. data/vendor/faiss/faiss/Index.h +43 -6
  15. data/vendor/faiss/faiss/Index2Layer.cpp +6 -2
  16. data/vendor/faiss/faiss/Index2Layer.h +6 -1
  17. data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +219 -16
  18. data/vendor/faiss/faiss/IndexAdditiveQuantizer.h +63 -5
  19. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +299 -0
  20. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.h +199 -0
  21. data/vendor/faiss/faiss/IndexBinary.cpp +20 -4
  22. data/vendor/faiss/faiss/IndexBinary.h +18 -3
  23. data/vendor/faiss/faiss/IndexBinaryFlat.cpp +9 -2
  24. data/vendor/faiss/faiss/IndexBinaryFlat.h +4 -2
  25. data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +4 -1
  26. data/vendor/faiss/faiss/IndexBinaryFromFloat.h +2 -1
  27. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +5 -1
  28. data/vendor/faiss/faiss/IndexBinaryHNSW.h +2 -1
  29. data/vendor/faiss/faiss/IndexBinaryHash.cpp +17 -4
  30. data/vendor/faiss/faiss/IndexBinaryHash.h +8 -4
  31. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +28 -13
  32. data/vendor/faiss/faiss/IndexBinaryIVF.h +10 -7
  33. data/vendor/faiss/faiss/IndexFastScan.cpp +626 -0
  34. data/vendor/faiss/faiss/IndexFastScan.h +145 -0
  35. data/vendor/faiss/faiss/IndexFlat.cpp +34 -21
  36. data/vendor/faiss/faiss/IndexFlat.h +7 -4
  37. data/vendor/faiss/faiss/IndexFlatCodes.cpp +35 -1
  38. data/vendor/faiss/faiss/IndexFlatCodes.h +12 -0
  39. data/vendor/faiss/faiss/IndexHNSW.cpp +66 -138
  40. data/vendor/faiss/faiss/IndexHNSW.h +4 -2
  41. data/vendor/faiss/faiss/IndexIDMap.cpp +247 -0
  42. data/vendor/faiss/faiss/IndexIDMap.h +107 -0
  43. data/vendor/faiss/faiss/IndexIVF.cpp +121 -33
  44. data/vendor/faiss/faiss/IndexIVF.h +35 -16
  45. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +84 -7
  46. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.h +63 -1
  47. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +590 -0
  48. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.h +171 -0
  49. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +1290 -0
  50. data/vendor/faiss/faiss/IndexIVFFastScan.h +213 -0
  51. data/vendor/faiss/faiss/IndexIVFFlat.cpp +37 -17
  52. data/vendor/faiss/faiss/IndexIVFFlat.h +4 -2
  53. data/vendor/faiss/faiss/IndexIVFPQ.cpp +234 -50
  54. data/vendor/faiss/faiss/IndexIVFPQ.h +5 -1
  55. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +23 -852
  56. data/vendor/faiss/faiss/IndexIVFPQFastScan.h +7 -112
  57. data/vendor/faiss/faiss/IndexIVFPQR.cpp +3 -3
  58. data/vendor/faiss/faiss/IndexIVFPQR.h +1 -1
  59. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +3 -1
  60. data/vendor/faiss/faiss/IndexIVFSpectralHash.h +2 -1
  61. data/vendor/faiss/faiss/IndexLSH.cpp +4 -2
  62. data/vendor/faiss/faiss/IndexLSH.h +2 -1
  63. data/vendor/faiss/faiss/IndexLattice.cpp +7 -1
  64. data/vendor/faiss/faiss/IndexLattice.h +3 -1
  65. data/vendor/faiss/faiss/IndexNNDescent.cpp +4 -3
  66. data/vendor/faiss/faiss/IndexNNDescent.h +2 -1
  67. data/vendor/faiss/faiss/IndexNSG.cpp +37 -3
  68. data/vendor/faiss/faiss/IndexNSG.h +25 -1
  69. data/vendor/faiss/faiss/IndexPQ.cpp +106 -69
  70. data/vendor/faiss/faiss/IndexPQ.h +19 -5
  71. data/vendor/faiss/faiss/IndexPQFastScan.cpp +15 -450
  72. data/vendor/faiss/faiss/IndexPQFastScan.h +15 -78
  73. data/vendor/faiss/faiss/IndexPreTransform.cpp +47 -8
  74. data/vendor/faiss/faiss/IndexPreTransform.h +15 -3
  75. data/vendor/faiss/faiss/IndexRefine.cpp +8 -4
  76. data/vendor/faiss/faiss/IndexRefine.h +4 -2
  77. data/vendor/faiss/faiss/IndexReplicas.cpp +4 -2
  78. data/vendor/faiss/faiss/IndexReplicas.h +2 -1
  79. data/vendor/faiss/faiss/IndexRowwiseMinMax.cpp +438 -0
  80. data/vendor/faiss/faiss/IndexRowwiseMinMax.h +92 -0
  81. data/vendor/faiss/faiss/IndexScalarQuantizer.cpp +26 -15
  82. data/vendor/faiss/faiss/IndexScalarQuantizer.h +6 -7
  83. data/vendor/faiss/faiss/IndexShards.cpp +4 -1
  84. data/vendor/faiss/faiss/IndexShards.h +2 -1
  85. data/vendor/faiss/faiss/MetaIndexes.cpp +5 -178
  86. data/vendor/faiss/faiss/MetaIndexes.h +3 -81
  87. data/vendor/faiss/faiss/VectorTransform.cpp +43 -0
  88. data/vendor/faiss/faiss/VectorTransform.h +22 -4
  89. data/vendor/faiss/faiss/clone_index.cpp +23 -1
  90. data/vendor/faiss/faiss/clone_index.h +3 -0
  91. data/vendor/faiss/faiss/cppcontrib/SaDecodeKernels.h +300 -0
  92. data/vendor/faiss/faiss/cppcontrib/detail/CoarseBitType.h +24 -0
  93. data/vendor/faiss/faiss/cppcontrib/detail/UintReader.h +195 -0
  94. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-avx2-inl.h +2058 -0
  95. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-inl.h +408 -0
  96. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-neon-inl.h +2147 -0
  97. data/vendor/faiss/faiss/cppcontrib/sa_decode/MinMax-inl.h +460 -0
  98. data/vendor/faiss/faiss/cppcontrib/sa_decode/MinMaxFP16-inl.h +465 -0
  99. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-avx2-inl.h +1618 -0
  100. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-inl.h +251 -0
  101. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-neon-inl.h +1452 -0
  102. data/vendor/faiss/faiss/gpu/GpuAutoTune.cpp +1 -0
  103. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +0 -4
  104. data/vendor/faiss/faiss/gpu/GpuIndex.h +28 -4
  105. data/vendor/faiss/faiss/gpu/GpuIndexBinaryFlat.h +2 -1
  106. data/vendor/faiss/faiss/gpu/GpuIndexFlat.h +10 -8
  107. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +75 -14
  108. data/vendor/faiss/faiss/gpu/GpuIndexIVFFlat.h +19 -32
  109. data/vendor/faiss/faiss/gpu/GpuIndexIVFPQ.h +22 -31
  110. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +22 -28
  111. data/vendor/faiss/faiss/gpu/GpuResources.cpp +14 -0
  112. data/vendor/faiss/faiss/gpu/GpuResources.h +16 -3
  113. data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +3 -3
  114. data/vendor/faiss/faiss/gpu/impl/IndexUtils.h +32 -0
  115. data/vendor/faiss/faiss/gpu/test/TestGpuIndexBinaryFlat.cpp +1 -0
  116. data/vendor/faiss/faiss/gpu/test/TestGpuIndexFlat.cpp +311 -75
  117. data/vendor/faiss/faiss/gpu/test/TestUtils.cpp +10 -0
  118. data/vendor/faiss/faiss/gpu/test/TestUtils.h +3 -0
  119. data/vendor/faiss/faiss/gpu/test/demo_ivfpq_indexing_gpu.cpp +2 -2
  120. data/vendor/faiss/faiss/gpu/utils/DeviceUtils.h +5 -4
  121. data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +116 -47
  122. data/vendor/faiss/faiss/impl/AdditiveQuantizer.h +44 -13
  123. data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +0 -54
  124. data/vendor/faiss/faiss/impl/AuxIndexStructures.h +0 -76
  125. data/vendor/faiss/faiss/impl/DistanceComputer.h +64 -0
  126. data/vendor/faiss/faiss/impl/HNSW.cpp +123 -27
  127. data/vendor/faiss/faiss/impl/HNSW.h +19 -16
  128. data/vendor/faiss/faiss/impl/IDSelector.cpp +125 -0
  129. data/vendor/faiss/faiss/impl/IDSelector.h +135 -0
  130. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +6 -28
  131. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.h +6 -1
  132. data/vendor/faiss/faiss/impl/LookupTableScaler.h +77 -0
  133. data/vendor/faiss/faiss/impl/NNDescent.cpp +1 -0
  134. data/vendor/faiss/faiss/impl/NSG.cpp +1 -1
  135. data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.cpp +383 -0
  136. data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.h +154 -0
  137. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +225 -145
  138. data/vendor/faiss/faiss/impl/ProductQuantizer.h +29 -10
  139. data/vendor/faiss/faiss/impl/Quantizer.h +43 -0
  140. data/vendor/faiss/faiss/impl/ResidualQuantizer.cpp +192 -36
  141. data/vendor/faiss/faiss/impl/ResidualQuantizer.h +40 -20
  142. data/vendor/faiss/faiss/impl/ResultHandler.h +96 -0
  143. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +97 -173
  144. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +18 -18
  145. data/vendor/faiss/faiss/impl/index_read.cpp +240 -9
  146. data/vendor/faiss/faiss/impl/index_write.cpp +237 -5
  147. data/vendor/faiss/faiss/impl/kmeans1d.cpp +6 -4
  148. data/vendor/faiss/faiss/impl/pq4_fast_scan.cpp +56 -16
  149. data/vendor/faiss/faiss/impl/pq4_fast_scan.h +25 -8
  150. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_1.cpp +66 -25
  151. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_qbs.cpp +75 -27
  152. data/vendor/faiss/faiss/index_factory.cpp +196 -7
  153. data/vendor/faiss/faiss/index_io.h +5 -0
  154. data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -0
  155. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +4 -1
  156. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +2 -1
  157. data/vendor/faiss/faiss/python/python_callbacks.cpp +27 -0
  158. data/vendor/faiss/faiss/python/python_callbacks.h +15 -0
  159. data/vendor/faiss/faiss/utils/Heap.h +31 -15
  160. data/vendor/faiss/faiss/utils/distances.cpp +380 -56
  161. data/vendor/faiss/faiss/utils/distances.h +113 -15
  162. data/vendor/faiss/faiss/utils/distances_simd.cpp +726 -6
  163. data/vendor/faiss/faiss/utils/extra_distances.cpp +12 -7
  164. data/vendor/faiss/faiss/utils/extra_distances.h +3 -1
  165. data/vendor/faiss/faiss/utils/fp16-fp16c.h +21 -0
  166. data/vendor/faiss/faiss/utils/fp16-inl.h +101 -0
  167. data/vendor/faiss/faiss/utils/fp16.h +11 -0
  168. data/vendor/faiss/faiss/utils/hamming-inl.h +54 -0
  169. data/vendor/faiss/faiss/utils/hamming.cpp +0 -48
  170. data/vendor/faiss/faiss/utils/ordered_key_value.h +10 -0
  171. data/vendor/faiss/faiss/utils/quantize_lut.cpp +62 -0
  172. data/vendor/faiss/faiss/utils/quantize_lut.h +20 -0
  173. data/vendor/faiss/faiss/utils/random.cpp +53 -0
  174. data/vendor/faiss/faiss/utils/random.h +5 -0
  175. data/vendor/faiss/faiss/utils/simdlib_avx2.h +4 -0
  176. data/vendor/faiss/faiss/utils/simdlib_emulated.h +6 -1
  177. data/vendor/faiss/faiss/utils/simdlib_neon.h +7 -2
  178. metadata +37 -3
@@ -26,10 +26,12 @@
26
26
 
27
27
  #include <faiss/Index2Layer.h>
28
28
  #include <faiss/IndexAdditiveQuantizer.h>
29
+ #include <faiss/IndexAdditiveQuantizerFastScan.h>
29
30
  #include <faiss/IndexFlat.h>
30
31
  #include <faiss/IndexHNSW.h>
31
32
  #include <faiss/IndexIVF.h>
32
33
  #include <faiss/IndexIVFAdditiveQuantizer.h>
34
+ #include <faiss/IndexIVFAdditiveQuantizerFastScan.h>
33
35
  #include <faiss/IndexIVFFlat.h>
34
36
  #include <faiss/IndexIVFPQ.h>
35
37
  #include <faiss/IndexIVFPQFastScan.h>
@@ -37,11 +39,13 @@
37
39
  #include <faiss/IndexIVFSpectralHash.h>
38
40
  #include <faiss/IndexLSH.h>
39
41
  #include <faiss/IndexLattice.h>
42
+ #include <faiss/IndexNNDescent.h>
40
43
  #include <faiss/IndexNSG.h>
41
44
  #include <faiss/IndexPQ.h>
42
45
  #include <faiss/IndexPQFastScan.h>
43
46
  #include <faiss/IndexPreTransform.h>
44
47
  #include <faiss/IndexRefine.h>
48
+ #include <faiss/IndexRowwiseMinMax.h>
45
49
  #include <faiss/IndexScalarQuantizer.h>
46
50
  #include <faiss/MetaIndexes.h>
47
51
  #include <faiss/VectorTransform.h>
@@ -271,9 +275,17 @@ static void read_AdditiveQuantizer(AdditiveQuantizer* aq, IOReader* f) {
271
275
  READ1(aq->norm_min);
272
276
  READ1(aq->norm_max);
273
277
  if (aq->search_type == AdditiveQuantizer::ST_norm_cqint8 ||
274
- aq->search_type == AdditiveQuantizer::ST_norm_cqint4) {
278
+ aq->search_type == AdditiveQuantizer::ST_norm_cqint4 ||
279
+ aq->search_type == AdditiveQuantizer::ST_norm_lsq2x4 ||
280
+ aq->search_type == AdditiveQuantizer::ST_norm_rq2x4) {
275
281
  READXBVECTOR(aq->qnorm.codes);
276
282
  }
283
+
284
+ if (aq->search_type == AdditiveQuantizer::ST_norm_lsq2x4 ||
285
+ aq->search_type == AdditiveQuantizer::ST_norm_rq2x4) {
286
+ READVECTOR(aq->norm_tabs);
287
+ }
288
+
277
289
  aq->set_derived_values();
278
290
  }
279
291
 
@@ -301,6 +313,37 @@ static void read_LocalSearchQuantizer(LocalSearchQuantizer* lsq, IOReader* f) {
301
313
  READ1(lsq->update_codebooks_with_double);
302
314
  }
303
315
 
316
+ static void read_ProductAdditiveQuantizer(
317
+ ProductAdditiveQuantizer* paq,
318
+ IOReader* f) {
319
+ read_AdditiveQuantizer(paq, f);
320
+ READ1(paq->nsplits);
321
+ }
322
+
323
+ static void read_ProductResidualQuantizer(
324
+ ProductResidualQuantizer* prq,
325
+ IOReader* f) {
326
+ read_ProductAdditiveQuantizer(prq, f);
327
+
328
+ for (size_t i = 0; i < prq->nsplits; i++) {
329
+ auto rq = new ResidualQuantizer();
330
+ read_ResidualQuantizer(rq, f);
331
+ prq->quantizers.push_back(rq);
332
+ }
333
+ }
334
+
335
+ static void read_ProductLocalSearchQuantizer(
336
+ ProductLocalSearchQuantizer* plsq,
337
+ IOReader* f) {
338
+ read_ProductAdditiveQuantizer(plsq, f);
339
+
340
+ for (size_t i = 0; i < plsq->nsplits; i++) {
341
+ auto lsq = new LocalSearchQuantizer();
342
+ read_LocalSearchQuantizer(lsq, f);
343
+ plsq->quantizers.push_back(lsq);
344
+ }
345
+ }
346
+
304
347
  static void read_ScalarQuantizer(ScalarQuantizer* ivsc, IOReader* f) {
305
348
  READ1(ivsc->qtype);
306
349
  READ1(ivsc->rangestat);
@@ -361,6 +404,21 @@ static void read_NSG(NSG* nsg, IOReader* f) {
361
404
  }
362
405
  }
363
406
 
407
+ static void read_NNDescent(NNDescent* nnd, IOReader* f) {
408
+ READ1(nnd->ntotal);
409
+ READ1(nnd->d);
410
+ READ1(nnd->K);
411
+ READ1(nnd->S);
412
+ READ1(nnd->R);
413
+ READ1(nnd->L);
414
+ READ1(nnd->iter);
415
+ READ1(nnd->search_L);
416
+ READ1(nnd->random_seed);
417
+ READ1(nnd->has_built);
418
+
419
+ READVECTOR(nnd->final_graph);
420
+ }
421
+
364
422
  ProductQuantizer* read_ProductQuantizer(const char* fname) {
365
423
  FileIOReader reader(fname);
366
424
  return read_ProductQuantizer(&reader);
@@ -444,10 +502,14 @@ static IndexIVFPQ* read_ivfpq(IOReader* f, uint32_t h, int io_flags) {
444
502
  }
445
503
 
446
504
  if (ivpq->is_trained) {
447
- // precomputed table not stored. It is cheaper to recompute it
505
+ // precomputed table not stored. It is cheaper to recompute it.
506
+ // precompute_table() may be disabled with a flag.
448
507
  ivpq->use_precomputed_table = 0;
449
- if (ivpq->by_residual)
450
- ivpq->precompute_table();
508
+ if (ivpq->by_residual) {
509
+ if ((io_flags & IO_FLAG_SKIP_PRECOMPUTE_TABLE) == 0) {
510
+ ivpq->precompute_table();
511
+ }
512
+ }
451
513
  if (ivfpqr) {
452
514
  read_ProductQuantizer(&ivfpqr->refine_pq, f);
453
515
  READVECTOR(ivfpqr->refine_codes);
@@ -549,6 +611,20 @@ Index* read_index(IOReader* f, int io_flags) {
549
611
  READ1(idxr->code_size);
550
612
  READVECTOR(idxr->codes);
551
613
  idx = idxr;
614
+ } else if (h == fourcc("IxPR")) {
615
+ auto idxpr = new IndexProductResidualQuantizer();
616
+ read_index_header(idxpr, f);
617
+ read_ProductResidualQuantizer(&idxpr->prq, f);
618
+ READ1(idxpr->code_size);
619
+ READVECTOR(idxpr->codes);
620
+ idx = idxpr;
621
+ } else if (h == fourcc("IxPL")) {
622
+ auto idxpl = new IndexProductLocalSearchQuantizer();
623
+ read_index_header(idxpl, f);
624
+ read_ProductLocalSearchQuantizer(&idxpl->plsq, f);
625
+ READ1(idxpl->code_size);
626
+ READVECTOR(idxpl->codes);
627
+ idx = idxpl;
552
628
  } else if (h == fourcc("ImRQ")) {
553
629
  ResidualCoarseQuantizer* idxr = new ResidualCoarseQuantizer();
554
630
  read_index_header(idxr, f);
@@ -556,6 +632,103 @@ Index* read_index(IOReader* f, int io_flags) {
556
632
  READ1(idxr->beam_factor);
557
633
  idxr->set_beam_factor(idxr->beam_factor);
558
634
  idx = idxr;
635
+ } else if (
636
+ h == fourcc("ILfs") || h == fourcc("IRfs") || h == fourcc("IPRf") ||
637
+ h == fourcc("IPLf")) {
638
+ bool is_LSQ = h == fourcc("ILfs");
639
+ bool is_RQ = h == fourcc("IRfs");
640
+ bool is_PLSQ = h == fourcc("IPLf");
641
+
642
+ IndexAdditiveQuantizerFastScan* idxaqfs;
643
+ if (is_LSQ) {
644
+ idxaqfs = new IndexLocalSearchQuantizerFastScan();
645
+ } else if (is_RQ) {
646
+ idxaqfs = new IndexResidualQuantizerFastScan();
647
+ } else if (is_PLSQ) {
648
+ idxaqfs = new IndexProductLocalSearchQuantizerFastScan();
649
+ } else {
650
+ idxaqfs = new IndexProductResidualQuantizerFastScan();
651
+ }
652
+ read_index_header(idxaqfs, f);
653
+
654
+ if (is_LSQ) {
655
+ read_LocalSearchQuantizer((LocalSearchQuantizer*)idxaqfs->aq, f);
656
+ } else if (is_RQ) {
657
+ read_ResidualQuantizer((ResidualQuantizer*)idxaqfs->aq, f);
658
+ } else if (is_PLSQ) {
659
+ read_ProductLocalSearchQuantizer(
660
+ (ProductLocalSearchQuantizer*)idxaqfs->aq, f);
661
+ } else {
662
+ read_ProductResidualQuantizer(
663
+ (ProductResidualQuantizer*)idxaqfs->aq, f);
664
+ }
665
+
666
+ READ1(idxaqfs->implem);
667
+ READ1(idxaqfs->bbs);
668
+ READ1(idxaqfs->qbs);
669
+
670
+ READ1(idxaqfs->M);
671
+ READ1(idxaqfs->nbits);
672
+ READ1(idxaqfs->ksub);
673
+ READ1(idxaqfs->code_size);
674
+ READ1(idxaqfs->ntotal2);
675
+ READ1(idxaqfs->M2);
676
+
677
+ READ1(idxaqfs->rescale_norm);
678
+ READ1(idxaqfs->norm_scale);
679
+ READ1(idxaqfs->max_train_points);
680
+
681
+ READVECTOR(idxaqfs->codes);
682
+ idx = idxaqfs;
683
+ } else if (
684
+ h == fourcc("IVLf") || h == fourcc("IVRf") || h == fourcc("NPLf") ||
685
+ h == fourcc("NPRf")) {
686
+ bool is_LSQ = h == fourcc("IVLf");
687
+ bool is_RQ = h == fourcc("IVRf");
688
+ bool is_PLSQ = h == fourcc("NPLf");
689
+
690
+ IndexIVFAdditiveQuantizerFastScan* ivaqfs;
691
+ if (is_LSQ) {
692
+ ivaqfs = new IndexIVFLocalSearchQuantizerFastScan();
693
+ } else if (is_RQ) {
694
+ ivaqfs = new IndexIVFResidualQuantizerFastScan();
695
+ } else if (is_PLSQ) {
696
+ ivaqfs = new IndexIVFProductLocalSearchQuantizerFastScan();
697
+ } else {
698
+ ivaqfs = new IndexIVFProductResidualQuantizerFastScan();
699
+ }
700
+ read_ivf_header(ivaqfs, f);
701
+
702
+ if (is_LSQ) {
703
+ read_LocalSearchQuantizer((LocalSearchQuantizer*)ivaqfs->aq, f);
704
+ } else if (is_RQ) {
705
+ read_ResidualQuantizer((ResidualQuantizer*)ivaqfs->aq, f);
706
+ } else if (is_PLSQ) {
707
+ read_ProductLocalSearchQuantizer(
708
+ (ProductLocalSearchQuantizer*)ivaqfs->aq, f);
709
+ } else {
710
+ read_ProductResidualQuantizer(
711
+ (ProductResidualQuantizer*)ivaqfs->aq, f);
712
+ }
713
+
714
+ READ1(ivaqfs->by_residual);
715
+ READ1(ivaqfs->implem);
716
+ READ1(ivaqfs->bbs);
717
+ READ1(ivaqfs->qbs);
718
+
719
+ READ1(ivaqfs->M);
720
+ READ1(ivaqfs->nbits);
721
+ READ1(ivaqfs->ksub);
722
+ READ1(ivaqfs->code_size);
723
+ READ1(ivaqfs->qbs2);
724
+ READ1(ivaqfs->M2);
725
+
726
+ READ1(ivaqfs->rescale_norm);
727
+ READ1(ivaqfs->norm_scale);
728
+ READ1(ivaqfs->max_train_points);
729
+
730
+ read_InvertedLists(ivaqfs, f, io_flags);
731
+ idx = ivaqfs;
559
732
  } else if (h == fourcc("IvFl") || h == fourcc("IvFL")) { // legacy
560
733
  IndexIVFFlat* ivfl = new IndexIVFFlat();
561
734
  std::vector<std::vector<Index::idx_t>> ids;
@@ -635,20 +808,34 @@ Index* read_index(IOReader* f, int io_flags) {
635
808
  }
636
809
  read_InvertedLists(ivsc, f, io_flags);
637
810
  idx = ivsc;
638
- } else if (h == fourcc("IwLS") || h == fourcc("IwRQ")) {
811
+ } else if (
812
+ h == fourcc("IwLS") || h == fourcc("IwRQ") || h == fourcc("IwPL") ||
813
+ h == fourcc("IwPR")) {
639
814
  bool is_LSQ = h == fourcc("IwLS");
815
+ bool is_RQ = h == fourcc("IwRQ");
816
+ bool is_PLSQ = h == fourcc("IwPL");
640
817
  IndexIVFAdditiveQuantizer* iva;
641
818
  if (is_LSQ) {
642
819
  iva = new IndexIVFLocalSearchQuantizer();
643
- } else {
820
+ } else if (is_RQ) {
644
821
  iva = new IndexIVFResidualQuantizer();
822
+ } else if (is_PLSQ) {
823
+ iva = new IndexIVFProductLocalSearchQuantizer();
824
+ } else {
825
+ iva = new IndexIVFProductResidualQuantizer();
645
826
  }
646
827
  read_ivf_header(iva, f);
647
828
  READ1(iva->code_size);
648
829
  if (is_LSQ) {
649
830
  read_LocalSearchQuantizer((LocalSearchQuantizer*)iva->aq, f);
650
- } else {
831
+ } else if (is_RQ) {
651
832
  read_ResidualQuantizer((ResidualQuantizer*)iva->aq, f);
833
+ } else if (is_PLSQ) {
834
+ read_ProductLocalSearchQuantizer(
835
+ (ProductLocalSearchQuantizer*)iva->aq, f);
836
+ } else {
837
+ read_ProductResidualQuantizer(
838
+ (ProductResidualQuantizer*)iva->aq, f);
652
839
  }
653
840
  READ1(iva->by_residual);
654
841
  READ1(iva->use_precomputed_table);
@@ -751,8 +938,15 @@ Index* read_index(IOReader* f, int io_flags) {
751
938
  dynamic_cast<IndexPQ*>(idxhnsw->storage)->pq.compute_sdc_table();
752
939
  }
753
940
  idx = idxhnsw;
754
- } else if (h == fourcc("INSf")) {
755
- IndexNSG* idxnsg = new IndexNSGFlat();
941
+ } else if (
942
+ h == fourcc("INSf") || h == fourcc("INSp") || h == fourcc("INSs")) {
943
+ IndexNSG* idxnsg;
944
+ if (h == fourcc("INSf"))
945
+ idxnsg = new IndexNSGFlat();
946
+ if (h == fourcc("INSp"))
947
+ idxnsg = new IndexNSGPQ();
948
+ if (h == fourcc("INSs"))
949
+ idxnsg = new IndexNSGSQ();
756
950
  read_index_header(idxnsg, f);
757
951
  READ1(idxnsg->GK);
758
952
  READ1(idxnsg->build_type);
@@ -764,6 +958,13 @@ Index* read_index(IOReader* f, int io_flags) {
764
958
  idxnsg->storage = read_index(f, io_flags);
765
959
  idxnsg->own_fields = true;
766
960
  idx = idxnsg;
961
+ } else if (h == fourcc("INNf")) {
962
+ IndexNNDescent* idxnnd = new IndexNNDescentFlat();
963
+ read_index_header(idxnnd, f);
964
+ read_NNDescent(&idxnnd->nndescent, f);
965
+ idxnnd->storage = read_index(f, io_flags);
966
+ idxnnd->own_fields = true;
967
+ idx = idxnnd;
767
968
  } else if (h == fourcc("IPfs")) {
768
969
  IndexPQFastScan* idxpqfs = new IndexPQFastScan();
769
970
  read_index_header(idxpqfs, f);
@@ -774,6 +975,13 @@ Index* read_index(IOReader* f, int io_flags) {
774
975
  READ1(idxpqfs->ntotal2);
775
976
  READ1(idxpqfs->M2);
776
977
  READVECTOR(idxpqfs->codes);
978
+
979
+ const auto& pq = idxpqfs->pq;
980
+ idxpqfs->M = pq.M;
981
+ idxpqfs->nbits = pq.nbits;
982
+ idxpqfs->ksub = (1 << pq.nbits);
983
+ idxpqfs->code_size = pq.code_size;
984
+
777
985
  idx = idxpqfs;
778
986
 
779
987
  } else if (h == fourcc("IwPf")) {
@@ -788,7 +996,30 @@ Index* read_index(IOReader* f, int io_flags) {
788
996
  read_ProductQuantizer(&ivpq->pq, f);
789
997
  read_InvertedLists(ivpq, f, io_flags);
790
998
  ivpq->precompute_table();
999
+
1000
+ const auto& pq = ivpq->pq;
1001
+ ivpq->M = pq.M;
1002
+ ivpq->nbits = pq.nbits;
1003
+ ivpq->ksub = (1 << pq.nbits);
1004
+ ivpq->code_size = pq.code_size;
1005
+
791
1006
  idx = ivpq;
1007
+ } else if (h == fourcc("IRMf")) {
1008
+ IndexRowwiseMinMax* imm = new IndexRowwiseMinMax();
1009
+ read_index_header(imm, f);
1010
+
1011
+ imm->index = read_index(f, io_flags);
1012
+ imm->own_fields = true;
1013
+
1014
+ idx = imm;
1015
+ } else if (h == fourcc("IRMh")) {
1016
+ IndexRowwiseMinMaxFP16* imm = new IndexRowwiseMinMaxFP16();
1017
+ read_index_header(imm, f);
1018
+
1019
+ imm->index = read_index(f, io_flags);
1020
+ imm->own_fields = true;
1021
+
1022
+ idx = imm;
792
1023
  } else {
793
1024
  FAISS_THROW_FMT(
794
1025
  "Index type 0x%08x (\"%s\") not recognized",
@@ -27,10 +27,12 @@
27
27
 
28
28
  #include <faiss/Index2Layer.h>
29
29
  #include <faiss/IndexAdditiveQuantizer.h>
30
+ #include <faiss/IndexAdditiveQuantizerFastScan.h>
30
31
  #include <faiss/IndexFlat.h>
31
32
  #include <faiss/IndexHNSW.h>
32
33
  #include <faiss/IndexIVF.h>
33
34
  #include <faiss/IndexIVFAdditiveQuantizer.h>
35
+ #include <faiss/IndexIVFAdditiveQuantizerFastScan.h>
34
36
  #include <faiss/IndexIVFFlat.h>
35
37
  #include <faiss/IndexIVFPQ.h>
36
38
  #include <faiss/IndexIVFPQFastScan.h>
@@ -38,11 +40,13 @@
38
40
  #include <faiss/IndexIVFSpectralHash.h>
39
41
  #include <faiss/IndexLSH.h>
40
42
  #include <faiss/IndexLattice.h>
43
+ #include <faiss/IndexNNDescent.h>
41
44
  #include <faiss/IndexNSG.h>
42
45
  #include <faiss/IndexPQ.h>
43
46
  #include <faiss/IndexPQFastScan.h>
44
47
  #include <faiss/IndexPreTransform.h>
45
48
  #include <faiss/IndexRefine.h>
49
+ #include <faiss/IndexRowwiseMinMax.h>
46
50
  #include <faiss/IndexScalarQuantizer.h>
47
51
  #include <faiss/MetaIndexes.h>
48
52
  #include <faiss/VectorTransform.h>
@@ -170,9 +174,16 @@ static void write_AdditiveQuantizer(const AdditiveQuantizer* aq, IOWriter* f) {
170
174
  WRITE1(aq->norm_min);
171
175
  WRITE1(aq->norm_max);
172
176
  if (aq->search_type == AdditiveQuantizer::ST_norm_cqint8 ||
173
- aq->search_type == AdditiveQuantizer::ST_norm_cqint4) {
177
+ aq->search_type == AdditiveQuantizer::ST_norm_cqint4 ||
178
+ aq->search_type == AdditiveQuantizer::ST_norm_lsq2x4 ||
179
+ aq->search_type == AdditiveQuantizer::ST_norm_rq2x4) {
174
180
  WRITEXBVECTOR(aq->qnorm.codes);
175
181
  }
182
+
183
+ if (aq->search_type == AdditiveQuantizer::ST_norm_lsq2x4 ||
184
+ aq->search_type == AdditiveQuantizer::ST_norm_rq2x4) {
185
+ WRITEVECTOR(aq->norm_tabs);
186
+ }
176
187
  }
177
188
 
178
189
  static void write_ResidualQuantizer(const ResidualQuantizer* rq, IOWriter* f) {
@@ -198,6 +209,33 @@ static void write_LocalSearchQuantizer(
198
209
  WRITE1(lsq->update_codebooks_with_double);
199
210
  }
200
211
 
212
+ static void write_ProductAdditiveQuantizer(
213
+ const ProductAdditiveQuantizer* paq,
214
+ IOWriter* f) {
215
+ write_AdditiveQuantizer(paq, f);
216
+ WRITE1(paq->nsplits);
217
+ }
218
+
219
+ static void write_ProductResidualQuantizer(
220
+ const ProductResidualQuantizer* prq,
221
+ IOWriter* f) {
222
+ write_ProductAdditiveQuantizer(prq, f);
223
+ for (const auto aq : prq->quantizers) {
224
+ auto rq = dynamic_cast<const ResidualQuantizer*>(aq);
225
+ write_ResidualQuantizer(rq, f);
226
+ }
227
+ }
228
+
229
+ static void write_ProductLocalSearchQuantizer(
230
+ const ProductLocalSearchQuantizer* plsq,
231
+ IOWriter* f) {
232
+ write_ProductAdditiveQuantizer(plsq, f);
233
+ for (const auto aq : plsq->quantizers) {
234
+ auto lsq = dynamic_cast<const LocalSearchQuantizer*>(aq);
235
+ write_LocalSearchQuantizer(lsq, f);
236
+ }
237
+ }
238
+
201
239
  static void write_ScalarQuantizer(const ScalarQuantizer* ivsc, IOWriter* f) {
202
240
  WRITE1(ivsc->qtype);
203
241
  WRITE1(ivsc->rangestat);
@@ -314,6 +352,21 @@ static void write_NSG(const NSG* nsg, IOWriter* f) {
314
352
  }
315
353
  }
316
354
 
355
+ static void write_NNDescent(const NNDescent* nnd, IOWriter* f) {
356
+ WRITE1(nnd->ntotal);
357
+ WRITE1(nnd->d);
358
+ WRITE1(nnd->K);
359
+ WRITE1(nnd->S);
360
+ WRITE1(nnd->R);
361
+ WRITE1(nnd->L);
362
+ WRITE1(nnd->iter);
363
+ WRITE1(nnd->search_L);
364
+ WRITE1(nnd->random_seed);
365
+ WRITE1(nnd->has_built);
366
+
367
+ WRITEVECTOR(nnd->final_graph);
368
+ }
369
+
317
370
  static void write_direct_map(const DirectMap* dm, IOWriter* f) {
318
371
  char maintain_direct_map =
319
372
  (char)dm->type; // for backwards compatibility with bool
@@ -385,6 +438,137 @@ void write_index(const Index* idx, IOWriter* f) {
385
438
  write_LocalSearchQuantizer(&idxr->lsq, f);
386
439
  WRITE1(idxr->code_size);
387
440
  WRITEVECTOR(idxr->codes);
441
+ } else if (
442
+ const IndexProductResidualQuantizer* idxpr =
443
+ dynamic_cast<const IndexProductResidualQuantizer*>(idx)) {
444
+ uint32_t h = fourcc("IxPR");
445
+ WRITE1(h);
446
+ write_index_header(idx, f);
447
+ write_ProductResidualQuantizer(&idxpr->prq, f);
448
+ WRITE1(idxpr->code_size);
449
+ WRITEVECTOR(idxpr->codes);
450
+ } else if (
451
+ const IndexProductLocalSearchQuantizer* idxpl =
452
+ dynamic_cast<const IndexProductLocalSearchQuantizer*>(
453
+ idx)) {
454
+ uint32_t h = fourcc("IxPL");
455
+ WRITE1(h);
456
+ write_index_header(idx, f);
457
+ write_ProductLocalSearchQuantizer(&idxpl->plsq, f);
458
+ WRITE1(idxpl->code_size);
459
+ WRITEVECTOR(idxpl->codes);
460
+ } else if (
461
+ auto* idxaqfs =
462
+ dynamic_cast<const IndexAdditiveQuantizerFastScan*>(idx)) {
463
+ auto idxlsqfs =
464
+ dynamic_cast<const IndexLocalSearchQuantizerFastScan*>(idx);
465
+ auto idxrqfs = dynamic_cast<const IndexResidualQuantizerFastScan*>(idx);
466
+ auto idxplsqfs =
467
+ dynamic_cast<const IndexProductLocalSearchQuantizerFastScan*>(
468
+ idx);
469
+ auto idxprqfs =
470
+ dynamic_cast<const IndexProductResidualQuantizerFastScan*>(idx);
471
+ FAISS_THROW_IF_NOT(idxlsqfs || idxrqfs || idxplsqfs || idxprqfs);
472
+
473
+ if (idxlsqfs) {
474
+ uint32_t h = fourcc("ILfs");
475
+ WRITE1(h);
476
+ } else if (idxrqfs) {
477
+ uint32_t h = fourcc("IRfs");
478
+ WRITE1(h);
479
+ } else if (idxplsqfs) {
480
+ uint32_t h = fourcc("IPLf");
481
+ WRITE1(h);
482
+ } else if (idxprqfs) {
483
+ uint32_t h = fourcc("IPRf");
484
+ WRITE1(h);
485
+ }
486
+
487
+ write_index_header(idxaqfs, f);
488
+
489
+ if (idxlsqfs) {
490
+ write_LocalSearchQuantizer(&idxlsqfs->lsq, f);
491
+ } else if (idxrqfs) {
492
+ write_ResidualQuantizer(&idxrqfs->rq, f);
493
+ } else if (idxplsqfs) {
494
+ write_ProductLocalSearchQuantizer(&idxplsqfs->plsq, f);
495
+ } else if (idxprqfs) {
496
+ write_ProductResidualQuantizer(&idxprqfs->prq, f);
497
+ }
498
+ WRITE1(idxaqfs->implem);
499
+ WRITE1(idxaqfs->bbs);
500
+ WRITE1(idxaqfs->qbs);
501
+
502
+ WRITE1(idxaqfs->M);
503
+ WRITE1(idxaqfs->nbits);
504
+ WRITE1(idxaqfs->ksub);
505
+ WRITE1(idxaqfs->code_size);
506
+ WRITE1(idxaqfs->ntotal2);
507
+ WRITE1(idxaqfs->M2);
508
+
509
+ WRITE1(idxaqfs->rescale_norm);
510
+ WRITE1(idxaqfs->norm_scale);
511
+ WRITE1(idxaqfs->max_train_points);
512
+
513
+ WRITEVECTOR(idxaqfs->codes);
514
+ } else if (
515
+ auto* ivaqfs =
516
+ dynamic_cast<const IndexIVFAdditiveQuantizerFastScan*>(
517
+ idx)) {
518
+ auto ivlsqfs =
519
+ dynamic_cast<const IndexIVFLocalSearchQuantizerFastScan*>(idx);
520
+ auto ivrqfs =
521
+ dynamic_cast<const IndexIVFResidualQuantizerFastScan*>(idx);
522
+ auto ivplsqfs = dynamic_cast<
523
+ const IndexIVFProductLocalSearchQuantizerFastScan*>(idx);
524
+ auto ivprqfs =
525
+ dynamic_cast<const IndexIVFProductResidualQuantizerFastScan*>(
526
+ idx);
527
+ FAISS_THROW_IF_NOT(ivlsqfs || ivrqfs || ivplsqfs || ivprqfs);
528
+
529
+ if (ivlsqfs) {
530
+ uint32_t h = fourcc("IVLf");
531
+ WRITE1(h);
532
+ } else if (ivrqfs) {
533
+ uint32_t h = fourcc("IVRf");
534
+ WRITE1(h);
535
+ } else if (ivplsqfs) {
536
+ uint32_t h = fourcc("NPLf"); // N means IV ...
537
+ WRITE1(h);
538
+ } else {
539
+ uint32_t h = fourcc("NPRf");
540
+ WRITE1(h);
541
+ }
542
+
543
+ write_ivf_header(ivaqfs, f);
544
+
545
+ if (ivlsqfs) {
546
+ write_LocalSearchQuantizer(&ivlsqfs->lsq, f);
547
+ } else if (ivrqfs) {
548
+ write_ResidualQuantizer(&ivrqfs->rq, f);
549
+ } else if (ivplsqfs) {
550
+ write_ProductLocalSearchQuantizer(&ivplsqfs->plsq, f);
551
+ } else {
552
+ write_ProductResidualQuantizer(&ivprqfs->prq, f);
553
+ }
554
+
555
+ WRITE1(ivaqfs->by_residual);
556
+ WRITE1(ivaqfs->implem);
557
+ WRITE1(ivaqfs->bbs);
558
+ WRITE1(ivaqfs->qbs);
559
+
560
+ WRITE1(ivaqfs->M);
561
+ WRITE1(ivaqfs->nbits);
562
+ WRITE1(ivaqfs->ksub);
563
+ WRITE1(ivaqfs->code_size);
564
+ WRITE1(ivaqfs->qbs2);
565
+ WRITE1(ivaqfs->M2);
566
+
567
+ WRITE1(ivaqfs->rescale_norm);
568
+ WRITE1(ivaqfs->norm_scale);
569
+ WRITE1(ivaqfs->max_train_points);
570
+
571
+ write_InvertedLists(ivaqfs->invlists, f);
388
572
  } else if (
389
573
  const ResidualCoarseQuantizer* idxr =
390
574
  dynamic_cast<const ResidualCoarseQuantizer*>(idx)) {
@@ -459,14 +643,33 @@ void write_index(const Index* idx, IOWriter* f) {
459
643
  write_InvertedLists(ivsc->invlists, f);
460
644
  } else if (auto iva = dynamic_cast<const IndexIVFAdditiveQuantizer*>(idx)) {
461
645
  bool is_LSQ = dynamic_cast<const IndexIVFLocalSearchQuantizer*>(iva);
462
- uint32_t h = fourcc(is_LSQ ? "IwLS" : "IwRQ");
646
+ bool is_RQ = dynamic_cast<const IndexIVFResidualQuantizer*>(iva);
647
+ bool is_PLSQ =
648
+ dynamic_cast<const IndexIVFProductLocalSearchQuantizer*>(iva);
649
+ uint32_t h;
650
+ if (is_LSQ) {
651
+ h = fourcc("IwLS");
652
+ } else if (is_RQ) {
653
+ h = fourcc("IwRQ");
654
+ } else if (is_PLSQ) {
655
+ h = fourcc("IwPL");
656
+ } else {
657
+ h = fourcc("IwPR");
658
+ }
659
+
463
660
  WRITE1(h);
464
661
  write_ivf_header(iva, f);
465
662
  WRITE1(iva->code_size);
466
663
  if (is_LSQ) {
467
664
  write_LocalSearchQuantizer((LocalSearchQuantizer*)iva->aq, f);
468
- } else {
665
+ } else if (is_RQ) {
469
666
  write_ResidualQuantizer((ResidualQuantizer*)iva->aq, f);
667
+ } else if (is_PLSQ) {
668
+ write_ProductLocalSearchQuantizer(
669
+ (ProductLocalSearchQuantizer*)iva->aq, f);
670
+ } else {
671
+ write_ProductResidualQuantizer(
672
+ (ProductResidualQuantizer*)iva->aq, f);
470
673
  }
471
674
  WRITE1(iva->by_residual);
472
675
  WRITE1(iva->use_precomputed_table);
@@ -546,8 +749,10 @@ void write_index(const Index* idx, IOWriter* f) {
546
749
  write_HNSW(&idxhnsw->hnsw, f);
547
750
  write_index(idxhnsw->storage, f);
548
751
  } else if (const IndexNSG* idxnsg = dynamic_cast<const IndexNSG*>(idx)) {
549
- uint32_t h =
550
- dynamic_cast<const IndexNSGFlat*>(idx) ? fourcc("INSf") : 0;
752
+ uint32_t h = dynamic_cast<const IndexNSGFlat*>(idx) ? fourcc("INSf")
753
+ : dynamic_cast<const IndexNSGPQ*>(idx) ? fourcc("INSp")
754
+ : dynamic_cast<const IndexNSGSQ*>(idx) ? fourcc("INSs")
755
+ : 0;
551
756
  FAISS_THROW_IF_NOT(h != 0);
552
757
  WRITE1(h);
553
758
  write_index_header(idxnsg, f);
@@ -559,6 +764,17 @@ void write_index(const Index* idx, IOWriter* f) {
559
764
  WRITE1(idxnsg->nndescent_iter);
560
765
  write_NSG(&idxnsg->nsg, f);
561
766
  write_index(idxnsg->storage, f);
767
+ } else if (
768
+ const IndexNNDescent* idxnnd =
769
+ dynamic_cast<const IndexNNDescent*>(idx)) {
770
+ auto idxnndflat = dynamic_cast<const IndexNNDescentFlat*>(idx);
771
+ FAISS_THROW_IF_NOT(idxnndflat != nullptr);
772
+ uint32_t h = fourcc("INNf");
773
+ FAISS_THROW_IF_NOT(h != 0);
774
+ WRITE1(h);
775
+ write_index_header(idxnnd, f);
776
+ write_NNDescent(&idxnnd->nndescent, f);
777
+ write_index(idxnnd->storage, f);
562
778
  } else if (
563
779
  const IndexPQFastScan* idxpqfs =
564
780
  dynamic_cast<const IndexPQFastScan*>(idx)) {
@@ -586,6 +802,22 @@ void write_index(const Index* idx, IOWriter* f) {
586
802
  WRITE1(ivpq->qbs2);
587
803
  write_ProductQuantizer(&ivpq->pq, f);
588
804
  write_InvertedLists(ivpq->invlists, f);
805
+ } else if (
806
+ const IndexRowwiseMinMax* imm =
807
+ dynamic_cast<const IndexRowwiseMinMax*>(idx)) {
808
+ // IndexRowwiseMinmaxFloat
809
+ uint32_t h = fourcc("IRMf");
810
+ WRITE1(h);
811
+ write_index_header(imm, f);
812
+ write_index(imm->index, f);
813
+ } else if (
814
+ const IndexRowwiseMinMaxFP16* imm =
815
+ dynamic_cast<const IndexRowwiseMinMaxFP16*>(idx)) {
816
+ // IndexRowwiseMinmaxHalf
817
+ uint32_t h = fourcc("IRMh");
818
+ WRITE1(h);
819
+ write_index_header(imm, f);
820
+ write_index(imm->index, f);
589
821
  } else {
590
822
  FAISS_THROW_MSG("don't know how to serialize this type of index");
591
823
  }