faiss 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (171) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +1 -1
  5. data/ext/faiss/extconf.rb +9 -2
  6. data/ext/faiss/index.cpp +1 -1
  7. data/ext/faiss/index_binary.cpp +2 -2
  8. data/ext/faiss/product_quantizer.cpp +1 -1
  9. data/lib/faiss/version.rb +1 -1
  10. data/vendor/faiss/faiss/AutoTune.cpp +7 -7
  11. data/vendor/faiss/faiss/AutoTune.h +0 -1
  12. data/vendor/faiss/faiss/Clustering.cpp +4 -18
  13. data/vendor/faiss/faiss/Clustering.h +31 -21
  14. data/vendor/faiss/faiss/IVFlib.cpp +22 -11
  15. data/vendor/faiss/faiss/Index.cpp +1 -1
  16. data/vendor/faiss/faiss/Index.h +20 -5
  17. data/vendor/faiss/faiss/Index2Layer.cpp +7 -7
  18. data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +176 -166
  19. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +15 -15
  20. data/vendor/faiss/faiss/IndexBinary.cpp +9 -4
  21. data/vendor/faiss/faiss/IndexBinary.h +8 -19
  22. data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +2 -1
  23. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +24 -31
  24. data/vendor/faiss/faiss/IndexBinaryHash.cpp +25 -50
  25. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +106 -187
  26. data/vendor/faiss/faiss/IndexFastScan.cpp +90 -159
  27. data/vendor/faiss/faiss/IndexFastScan.h +9 -8
  28. data/vendor/faiss/faiss/IndexFlat.cpp +195 -3
  29. data/vendor/faiss/faiss/IndexFlat.h +20 -1
  30. data/vendor/faiss/faiss/IndexFlatCodes.cpp +11 -0
  31. data/vendor/faiss/faiss/IndexFlatCodes.h +3 -1
  32. data/vendor/faiss/faiss/IndexHNSW.cpp +112 -316
  33. data/vendor/faiss/faiss/IndexHNSW.h +12 -48
  34. data/vendor/faiss/faiss/IndexIDMap.cpp +69 -28
  35. data/vendor/faiss/faiss/IndexIDMap.h +24 -2
  36. data/vendor/faiss/faiss/IndexIVF.cpp +159 -53
  37. data/vendor/faiss/faiss/IndexIVF.h +37 -5
  38. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +18 -26
  39. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.h +3 -2
  40. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +19 -46
  41. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.h +4 -3
  42. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +433 -405
  43. data/vendor/faiss/faiss/IndexIVFFastScan.h +56 -26
  44. data/vendor/faiss/faiss/IndexIVFFlat.cpp +15 -5
  45. data/vendor/faiss/faiss/IndexIVFFlat.h +3 -2
  46. data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +172 -0
  47. data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.h +56 -0
  48. data/vendor/faiss/faiss/IndexIVFPQ.cpp +78 -122
  49. data/vendor/faiss/faiss/IndexIVFPQ.h +6 -7
  50. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +18 -50
  51. data/vendor/faiss/faiss/IndexIVFPQFastScan.h +4 -3
  52. data/vendor/faiss/faiss/IndexIVFPQR.cpp +45 -29
  53. data/vendor/faiss/faiss/IndexIVFPQR.h +5 -2
  54. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +25 -27
  55. data/vendor/faiss/faiss/IndexIVFSpectralHash.h +6 -6
  56. data/vendor/faiss/faiss/IndexLSH.cpp +14 -16
  57. data/vendor/faiss/faiss/IndexNNDescent.cpp +3 -4
  58. data/vendor/faiss/faiss/IndexNSG.cpp +11 -27
  59. data/vendor/faiss/faiss/IndexNSG.h +10 -10
  60. data/vendor/faiss/faiss/IndexPQ.cpp +72 -88
  61. data/vendor/faiss/faiss/IndexPQ.h +1 -4
  62. data/vendor/faiss/faiss/IndexPQFastScan.cpp +1 -1
  63. data/vendor/faiss/faiss/IndexPreTransform.cpp +25 -31
  64. data/vendor/faiss/faiss/IndexRefine.cpp +49 -19
  65. data/vendor/faiss/faiss/IndexRefine.h +7 -0
  66. data/vendor/faiss/faiss/IndexReplicas.cpp +23 -26
  67. data/vendor/faiss/faiss/IndexScalarQuantizer.cpp +22 -16
  68. data/vendor/faiss/faiss/IndexScalarQuantizer.h +6 -4
  69. data/vendor/faiss/faiss/IndexShards.cpp +21 -29
  70. data/vendor/faiss/faiss/IndexShardsIVF.cpp +1 -2
  71. data/vendor/faiss/faiss/MatrixStats.cpp +17 -32
  72. data/vendor/faiss/faiss/MatrixStats.h +21 -9
  73. data/vendor/faiss/faiss/MetaIndexes.cpp +35 -35
  74. data/vendor/faiss/faiss/VectorTransform.cpp +13 -26
  75. data/vendor/faiss/faiss/VectorTransform.h +7 -7
  76. data/vendor/faiss/faiss/clone_index.cpp +15 -10
  77. data/vendor/faiss/faiss/clone_index.h +3 -0
  78. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +87 -4
  79. data/vendor/faiss/faiss/gpu/GpuCloner.h +22 -0
  80. data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +7 -0
  81. data/vendor/faiss/faiss/gpu/GpuDistance.h +46 -38
  82. data/vendor/faiss/faiss/gpu/GpuIndex.h +28 -4
  83. data/vendor/faiss/faiss/gpu/GpuIndexFlat.h +4 -4
  84. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +8 -9
  85. data/vendor/faiss/faiss/gpu/GpuIndexIVFFlat.h +18 -3
  86. data/vendor/faiss/faiss/gpu/GpuIndexIVFPQ.h +22 -11
  87. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +1 -3
  88. data/vendor/faiss/faiss/gpu/GpuResources.cpp +24 -3
  89. data/vendor/faiss/faiss/gpu/GpuResources.h +39 -11
  90. data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +117 -17
  91. data/vendor/faiss/faiss/gpu/StandardGpuResources.h +57 -3
  92. data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +1 -1
  93. data/vendor/faiss/faiss/gpu/test/TestGpuIndexBinaryFlat.cpp +25 -0
  94. data/vendor/faiss/faiss/gpu/test/TestGpuIndexFlat.cpp +129 -9
  95. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +267 -40
  96. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFPQ.cpp +299 -208
  97. data/vendor/faiss/faiss/gpu/test/TestGpuMemoryException.cpp +1 -0
  98. data/vendor/faiss/faiss/gpu/utils/RaftUtils.h +75 -0
  99. data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +3 -1
  100. data/vendor/faiss/faiss/impl/AdditiveQuantizer.h +5 -5
  101. data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +1 -1
  102. data/vendor/faiss/faiss/impl/AuxIndexStructures.h +1 -2
  103. data/vendor/faiss/faiss/impl/DistanceComputer.h +24 -1
  104. data/vendor/faiss/faiss/impl/FaissException.h +13 -34
  105. data/vendor/faiss/faiss/impl/HNSW.cpp +321 -70
  106. data/vendor/faiss/faiss/impl/HNSW.h +9 -8
  107. data/vendor/faiss/faiss/impl/IDSelector.h +4 -4
  108. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +3 -1
  109. data/vendor/faiss/faiss/impl/NNDescent.cpp +29 -19
  110. data/vendor/faiss/faiss/impl/NSG.h +1 -1
  111. data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +14 -12
  112. data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.h +1 -1
  113. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +24 -22
  114. data/vendor/faiss/faiss/impl/ProductQuantizer.h +1 -1
  115. data/vendor/faiss/faiss/impl/Quantizer.h +1 -1
  116. data/vendor/faiss/faiss/impl/ResidualQuantizer.cpp +27 -1015
  117. data/vendor/faiss/faiss/impl/ResidualQuantizer.h +5 -63
  118. data/vendor/faiss/faiss/impl/ResultHandler.h +232 -176
  119. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +444 -104
  120. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +0 -8
  121. data/vendor/faiss/faiss/impl/code_distance/code_distance-avx2.h +280 -42
  122. data/vendor/faiss/faiss/impl/code_distance/code_distance-generic.h +21 -14
  123. data/vendor/faiss/faiss/impl/code_distance/code_distance.h +22 -12
  124. data/vendor/faiss/faiss/impl/index_read.cpp +45 -19
  125. data/vendor/faiss/faiss/impl/index_write.cpp +60 -41
  126. data/vendor/faiss/faiss/impl/io.cpp +10 -10
  127. data/vendor/faiss/faiss/impl/lattice_Zn.cpp +1 -1
  128. data/vendor/faiss/faiss/impl/platform_macros.h +18 -1
  129. data/vendor/faiss/faiss/impl/pq4_fast_scan.cpp +3 -0
  130. data/vendor/faiss/faiss/impl/pq4_fast_scan.h +7 -6
  131. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_1.cpp +52 -38
  132. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_qbs.cpp +40 -49
  133. data/vendor/faiss/faiss/impl/residual_quantizer_encode_steps.cpp +960 -0
  134. data/vendor/faiss/faiss/impl/residual_quantizer_encode_steps.h +176 -0
  135. data/vendor/faiss/faiss/impl/simd_result_handlers.h +374 -202
  136. data/vendor/faiss/faiss/index_factory.cpp +10 -7
  137. data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
  138. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +27 -9
  139. data/vendor/faiss/faiss/invlists/InvertedLists.h +12 -3
  140. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +3 -3
  141. data/vendor/faiss/faiss/python/python_callbacks.cpp +1 -1
  142. data/vendor/faiss/faiss/utils/Heap.cpp +3 -1
  143. data/vendor/faiss/faiss/utils/WorkerThread.h +1 -0
  144. data/vendor/faiss/faiss/utils/distances.cpp +128 -74
  145. data/vendor/faiss/faiss/utils/distances.h +81 -4
  146. data/vendor/faiss/faiss/utils/distances_fused/avx512.cpp +5 -5
  147. data/vendor/faiss/faiss/utils/distances_fused/avx512.h +2 -2
  148. data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +2 -2
  149. data/vendor/faiss/faiss/utils/distances_fused/distances_fused.h +1 -1
  150. data/vendor/faiss/faiss/utils/distances_fused/simdlib_based.cpp +5 -5
  151. data/vendor/faiss/faiss/utils/distances_fused/simdlib_based.h +1 -1
  152. data/vendor/faiss/faiss/utils/distances_simd.cpp +428 -70
  153. data/vendor/faiss/faiss/utils/fp16-arm.h +29 -0
  154. data/vendor/faiss/faiss/utils/fp16.h +2 -0
  155. data/vendor/faiss/faiss/utils/hamming.cpp +162 -110
  156. data/vendor/faiss/faiss/utils/hamming.h +58 -0
  157. data/vendor/faiss/faiss/utils/hamming_distance/avx2-inl.h +16 -89
  158. data/vendor/faiss/faiss/utils/hamming_distance/common.h +1 -0
  159. data/vendor/faiss/faiss/utils/hamming_distance/generic-inl.h +15 -87
  160. data/vendor/faiss/faiss/utils/hamming_distance/hamdis-inl.h +57 -0
  161. data/vendor/faiss/faiss/utils/hamming_distance/neon-inl.h +14 -104
  162. data/vendor/faiss/faiss/utils/partitioning.cpp +3 -4
  163. data/vendor/faiss/faiss/utils/prefetch.h +77 -0
  164. data/vendor/faiss/faiss/utils/quantize_lut.cpp +0 -14
  165. data/vendor/faiss/faiss/utils/simdlib_avx2.h +0 -6
  166. data/vendor/faiss/faiss/utils/simdlib_neon.h +72 -77
  167. data/vendor/faiss/faiss/utils/sorting.cpp +140 -5
  168. data/vendor/faiss/faiss/utils/sorting.h +27 -0
  169. data/vendor/faiss/faiss/utils/utils.cpp +112 -6
  170. data/vendor/faiss/faiss/utils/utils.h +57 -20
  171. metadata +10 -3
@@ -35,10 +35,12 @@ IndexIVFPQR::IndexIVFPQR(
35
35
  refine_pq(d, M_refine, nbits_per_idx_refine),
36
36
  k_factor(4) {
37
37
  by_residual = true;
38
+ refine_pq.cp.max_points_per_centroid = 1000;
38
39
  }
39
40
 
40
41
  IndexIVFPQR::IndexIVFPQR() : k_factor(1) {
41
42
  by_residual = true;
43
+ refine_pq.cp.max_points_per_centroid = 1000;
42
44
  }
43
45
 
44
46
  void IndexIVFPQR::reset() {
@@ -46,24 +48,39 @@ void IndexIVFPQR::reset() {
46
48
  refine_codes.clear();
47
49
  }
48
50
 
49
- void IndexIVFPQR::train_residual(idx_t n, const float* x) {
50
- float* residual_2 = new float[n * d];
51
- ScopeDeleter<float> del(residual_2);
52
-
53
- train_residual_o(n, x, residual_2);
54
-
55
- if (verbose)
51
+ void IndexIVFPQR::train_encoder(idx_t n, const float* x, const idx_t* assign) {
52
+ IndexIVFPQ::train_encoder(n, x, assign);
53
+ if (verbose) {
56
54
  printf("training %zdx%zd 2nd level PQ quantizer on %" PRId64
57
55
  " %dD-vectors\n",
58
56
  refine_pq.M,
59
57
  refine_pq.ksub,
60
58
  n,
61
59
  d);
62
-
63
- refine_pq.cp.max_points_per_centroid = 1000;
60
+ }
64
61
  refine_pq.cp.verbose = verbose;
65
62
 
66
- refine_pq.train(n, residual_2);
63
+ // 2nd level residual
64
+ std::vector<float> residual_2(n * d);
65
+ std::vector<uint8_t> train_codes(pq.code_size * n);
66
+ pq.compute_codes(x, train_codes.data(), n);
67
+
68
+ for (idx_t i = 0; i < n; i++) {
69
+ const float* xx = x + i * d;
70
+ float* res = residual_2.data() + i * d;
71
+ pq.decode(train_codes.data() + i * pq.code_size, res);
72
+ for (int j = 0; j < d; j++) {
73
+ res[j] = xx[j] - res[j];
74
+ }
75
+ }
76
+
77
+ refine_pq.train(n, residual_2.data());
78
+ }
79
+
80
+ idx_t IndexIVFPQR::train_encoder_num_vectors() const {
81
+ return std::max(
82
+ pq.cp.max_points_per_centroid * pq.ksub,
83
+ refine_pq.cp.max_points_per_centroid * refine_pq.ksub);
67
84
  }
68
85
 
69
86
  void IndexIVFPQR::add_with_ids(idx_t n, const float* x, const idx_t* xids) {
@@ -74,18 +91,18 @@ void IndexIVFPQR::add_core(
74
91
  idx_t n,
75
92
  const float* x,
76
93
  const idx_t* xids,
77
- const idx_t* precomputed_idx) {
78
- float* residual_2 = new float[n * d];
79
- ScopeDeleter<float> del(residual_2);
94
+ const idx_t* precomputed_idx,
95
+ void* /*inverted_list_context*/) {
96
+ std::unique_ptr<float[]> residual_2(new float[n * d]);
80
97
 
81
98
  idx_t n0 = ntotal;
82
99
 
83
- add_core_o(n, x, xids, residual_2, precomputed_idx);
100
+ add_core_o(n, x, xids, residual_2.get(), precomputed_idx);
84
101
 
85
102
  refine_codes.resize(ntotal * refine_pq.code_size);
86
103
 
87
104
  refine_pq.compute_codes(
88
- residual_2, &refine_codes[n0 * refine_pq.code_size], n);
105
+ residual_2.get(), &refine_codes[n0 * refine_pq.code_size], n);
89
106
  }
90
107
  #define TIC t0 = get_cycles()
91
108
  #define TOC get_cycles() - t0
@@ -104,11 +121,10 @@ void IndexIVFPQR::search_preassigned(
104
121
  uint64_t t0;
105
122
  TIC;
106
123
  size_t k_coarse = long(k * k_factor);
107
- idx_t* coarse_labels = new idx_t[k_coarse * n];
108
- ScopeDeleter<idx_t> del1(coarse_labels);
109
- { // query with quantizer levels 1 and 2.
110
- float* coarse_distances = new float[k_coarse * n];
111
- ScopeDeleter<float> del(coarse_distances);
124
+ std::unique_ptr<idx_t[]> coarse_labels(new idx_t[k_coarse * n]);
125
+ {
126
+ // query with quantizer levels 1 and 2.
127
+ std::unique_ptr<float[]> coarse_distances(new float[k_coarse * n]);
112
128
 
113
129
  IndexIVFPQ::search_preassigned(
114
130
  n,
@@ -116,8 +132,8 @@ void IndexIVFPQR::search_preassigned(
116
132
  k_coarse,
117
133
  idx,
118
134
  L1_dis,
119
- coarse_distances,
120
- coarse_labels,
135
+ coarse_distances.get(),
136
+ coarse_labels.get(),
121
137
  true,
122
138
  params);
123
139
  }
@@ -131,13 +147,12 @@ void IndexIVFPQR::search_preassigned(
131
147
  #pragma omp parallel reduction(+ : n_refine)
132
148
  {
133
149
  // tmp buffers
134
- float* residual_1 = new float[2 * d];
135
- ScopeDeleter<float> del(residual_1);
136
- float* residual_2 = residual_1 + d;
150
+ std::unique_ptr<float[]> residual_1(new float[2 * d]);
151
+ float* residual_2 = residual_1.get() + d;
137
152
  #pragma omp for
138
153
  for (idx_t i = 0; i < n; i++) {
139
154
  const float* xq = x + i * d;
140
- const idx_t* shortlist = coarse_labels + k_coarse * i;
155
+ const idx_t* shortlist = coarse_labels.get() + k_coarse * i;
141
156
  float* heap_sim = distances + k * i;
142
157
  idx_t* heap_ids = labels + k * i;
143
158
  maxheap_heapify(k, heap_sim, heap_ids);
@@ -155,7 +170,7 @@ void IndexIVFPQR::search_preassigned(
155
170
  assert(ofs >= 0 && ofs < invlists->list_size(list_no));
156
171
 
157
172
  // 1st level residual
158
- quantizer->compute_residual(xq, residual_1, list_no);
173
+ quantizer->compute_residual(xq, residual_1.get(), list_no);
159
174
 
160
175
  // 2nd level residual
161
176
  const uint8_t* l2code = invlists->get_single_code(list_no, ofs);
@@ -168,9 +183,10 @@ void IndexIVFPQR::search_preassigned(
168
183
  idx_t id = invlists->get_single_id(list_no, ofs);
169
184
  assert(0 <= id && id < ntotal);
170
185
  refine_pq.decode(
171
- &refine_codes[id * refine_pq.code_size], residual_1);
186
+ &refine_codes[id * refine_pq.code_size],
187
+ residual_1.get());
172
188
 
173
- float dis = fvec_L2sqr(residual_1, residual_2, d);
189
+ float dis = fvec_L2sqr(residual_1.get(), residual_2, d);
174
190
 
175
191
  if (dis < heap_sim[0]) {
176
192
  idx_t id_or_pair = store_pairs ? sl : id;
@@ -37,7 +37,9 @@ struct IndexIVFPQR : IndexIVFPQ {
37
37
  size_t remove_ids(const IDSelector& sel) override;
38
38
 
39
39
  /// trains the two product quantizers
40
- void train_residual(idx_t n, const float* x) override;
40
+ void train_encoder(idx_t n, const float* x, const idx_t* assign) override;
41
+
42
+ idx_t train_encoder_num_vectors() const override;
41
43
 
42
44
  void add_with_ids(idx_t n, const float* x, const idx_t* xids) override;
43
45
 
@@ -46,7 +48,8 @@ struct IndexIVFPQR : IndexIVFPQ {
46
48
  idx_t n,
47
49
  const float* x,
48
50
  const idx_t* xids,
49
- const idx_t* precomputed_idx) override;
51
+ const idx_t* precomputed_idx,
52
+ void* inverted_list_context = nullptr) override;
50
53
 
51
54
  void reconstruct_from_offset(int64_t list_no, int64_t offset, float* recons)
52
55
  const override;
@@ -9,8 +9,8 @@
9
9
 
10
10
  #include <faiss/IndexIVFSpectralHash.h>
11
11
 
12
- #include <stdint.h>
13
12
  #include <algorithm>
13
+ #include <cstdint>
14
14
  #include <memory>
15
15
 
16
16
  #include <faiss/IndexLSH.h>
@@ -31,22 +31,17 @@ IndexIVFSpectralHash::IndexIVFSpectralHash(
31
31
  float period)
32
32
  : IndexIVF(quantizer, d, nlist, (nbit + 7) / 8, METRIC_L2),
33
33
  nbit(nbit),
34
- period(period),
35
- threshold_type(Thresh_global) {
34
+ period(period) {
36
35
  RandomRotationMatrix* rr = new RandomRotationMatrix(d, nbit);
37
36
  rr->init(1234);
38
37
  vt = rr;
39
- own_fields = true;
40
38
  is_trained = false;
39
+ by_residual = false;
41
40
  }
42
41
 
43
- IndexIVFSpectralHash::IndexIVFSpectralHash()
44
- : IndexIVF(),
45
- vt(nullptr),
46
- own_fields(false),
47
- nbit(0),
48
- period(0),
49
- threshold_type(Thresh_global) {}
42
+ IndexIVFSpectralHash::IndexIVFSpectralHash() : IndexIVF() {
43
+ by_residual = false;
44
+ }
50
45
 
51
46
  IndexIVFSpectralHash::~IndexIVFSpectralHash() {
52
47
  if (own_fields) {
@@ -67,10 +62,14 @@ float median(size_t n, float* x) {
67
62
 
68
63
  } // namespace
69
64
 
70
- void IndexIVFSpectralHash::train_residual(idx_t n, const float* x) {
65
+ void IndexIVFSpectralHash::train_encoder(
66
+ idx_t n,
67
+ const float* x,
68
+ const idx_t* assign) {
71
69
  if (!vt->is_trained) {
72
70
  vt->train(n, x);
73
71
  }
72
+ FAISS_THROW_IF_NOT(!by_residual);
74
73
 
75
74
  if (threshold_type == Thresh_global) {
76
75
  // nothing to do
@@ -158,7 +157,7 @@ void binarize_with_freq(
158
157
  }
159
158
  }
160
159
 
161
- }; // namespace
160
+ } // namespace
162
161
 
163
162
  void IndexIVFSpectralHash::encode_vectors(
164
163
  idx_t n,
@@ -167,6 +166,7 @@ void IndexIVFSpectralHash::encode_vectors(
167
166
  uint8_t* codes,
168
167
  bool include_listnos) const {
169
168
  FAISS_THROW_IF_NOT(is_trained);
169
+ FAISS_THROW_IF_NOT(!by_residual);
170
170
  float freq = 2.0 / period;
171
171
  size_t coarse_size = include_listnos ? coarse_code_size() : 0;
172
172
 
@@ -224,6 +224,7 @@ struct IVFScanner : InvertedListScanner {
224
224
  hc(qcode.data(), index->code_size) {
225
225
  this->store_pairs = store_pairs;
226
226
  this->code_size = index->code_size;
227
+ this->keep_max = is_similarity_metric(index->metric_type);
227
228
  }
228
229
 
229
230
  void set_query(const float* query) override {
@@ -288,26 +289,23 @@ struct IVFScanner : InvertedListScanner {
288
289
  }
289
290
  };
290
291
 
292
+ struct BuildScanner {
293
+ using T = InvertedListScanner*;
294
+
295
+ template <class HammingComputer>
296
+ static T f(const IndexIVFSpectralHash* index, bool store_pairs) {
297
+ return new IVFScanner<HammingComputer>(index, store_pairs);
298
+ }
299
+ };
300
+
291
301
  } // anonymous namespace
292
302
 
293
303
  InvertedListScanner* IndexIVFSpectralHash::get_InvertedListScanner(
294
304
  bool store_pairs,
295
305
  const IDSelector* sel) const {
296
306
  FAISS_THROW_IF_NOT(!sel);
297
- switch (code_size) {
298
- #define HANDLE_CODE_SIZE(cs) \
299
- case cs: \
300
- return new IVFScanner<HammingComputer##cs>(this, store_pairs)
301
- HANDLE_CODE_SIZE(4);
302
- HANDLE_CODE_SIZE(8);
303
- HANDLE_CODE_SIZE(16);
304
- HANDLE_CODE_SIZE(20);
305
- HANDLE_CODE_SIZE(32);
306
- HANDLE_CODE_SIZE(64);
307
- #undef HANDLE_CODE_SIZE
308
- default:
309
- return new IVFScanner<HammingComputerDefault>(this, store_pairs);
310
- }
307
+ BuildScanner bs;
308
+ return dispatch_HammingComputer(code_size, bs, this, store_pairs);
311
309
  }
312
310
 
313
311
  void IndexIVFSpectralHash::replace_vt(VectorTransform* vt_in, bool own) {
@@ -30,14 +30,14 @@ struct IndexPreTransform;
30
30
  */
31
31
  struct IndexIVFSpectralHash : IndexIVF {
32
32
  /// transformation from d to nbit dim
33
- VectorTransform* vt;
33
+ VectorTransform* vt = nullptr;
34
34
  /// own the vt
35
- bool own_fields;
35
+ bool own_fields = true;
36
36
 
37
37
  /// nb of bits of the binary signature
38
- int nbit;
38
+ int nbit = 0;
39
39
  /// interval size for 0s and 1s
40
- float period;
40
+ float period = 0;
41
41
 
42
42
  enum ThresholdType {
43
43
  Thresh_global, ///< global threshold at 0
@@ -45,7 +45,7 @@ struct IndexIVFSpectralHash : IndexIVF {
45
45
  Thresh_centroid_half, ///< central interval around centroid
46
46
  Thresh_median ///< median of training set
47
47
  };
48
- ThresholdType threshold_type;
48
+ ThresholdType threshold_type = Thresh_global;
49
49
 
50
50
  /// Trained threshold.
51
51
  /// size nlist * nbit or 0 if Thresh_global
@@ -60,7 +60,7 @@ struct IndexIVFSpectralHash : IndexIVF {
60
60
 
61
61
  IndexIVFSpectralHash();
62
62
 
63
- void train_residual(idx_t n, const float* x) override;
63
+ void train_encoder(idx_t n, const float* x, const idx_t* assign) override;
64
64
 
65
65
  void encode_vectors(
66
66
  idx_t n,
@@ -11,6 +11,7 @@
11
11
  #include <cstring>
12
12
 
13
13
  #include <algorithm>
14
+ #include <memory>
14
15
 
15
16
  #include <faiss/impl/FaissAssert.h>
16
17
  #include <faiss/utils/hamming.h>
@@ -56,7 +57,7 @@ const float* IndexLSH::apply_preprocess(idx_t n, const float* x) const {
56
57
  }
57
58
 
58
59
  if (train_thresholds) {
59
- if (xt == NULL) {
60
+ if (xt == nullptr) {
60
61
  xt = new float[nbits * n];
61
62
  memcpy(xt, x, sizeof(*x) * n * nbits);
62
63
  }
@@ -75,18 +76,17 @@ void IndexLSH::train(idx_t n, const float* x) {
75
76
  thresholds.resize(nbits);
76
77
  train_thresholds = false;
77
78
  const float* xt = apply_preprocess(n, x);
78
- ScopeDeleter<float> del(xt == x ? nullptr : xt);
79
+ std::unique_ptr<const float[]> del(xt == x ? nullptr : xt);
79
80
  train_thresholds = true;
80
81
 
81
- float* transposed_x = new float[n * nbits];
82
- ScopeDeleter<float> del2(transposed_x);
82
+ std::unique_ptr<float[]> transposed_x(new float[n * nbits]);
83
83
 
84
84
  for (idx_t i = 0; i < n; i++)
85
85
  for (idx_t j = 0; j < nbits; j++)
86
86
  transposed_x[j * n + i] = xt[i * nbits + j];
87
87
 
88
88
  for (idx_t i = 0; i < nbits; i++) {
89
- float* xi = transposed_x + i * n;
89
+ float* xi = transposed_x.get() + i * n;
90
90
  // std::nth_element
91
91
  std::sort(xi, xi + n);
92
92
  if (n % 2 == 1)
@@ -110,19 +110,17 @@ void IndexLSH::search(
110
110
  FAISS_THROW_IF_NOT(k > 0);
111
111
  FAISS_THROW_IF_NOT(is_trained);
112
112
  const float* xt = apply_preprocess(n, x);
113
- ScopeDeleter<float> del(xt == x ? nullptr : xt);
113
+ std::unique_ptr<const float[]> del(xt == x ? nullptr : xt);
114
114
 
115
- uint8_t* qcodes = new uint8_t[n * code_size];
116
- ScopeDeleter<uint8_t> del2(qcodes);
115
+ std::unique_ptr<uint8_t[]> qcodes(new uint8_t[n * code_size]);
117
116
 
118
- fvecs2bitvecs(xt, qcodes, nbits, n);
117
+ fvecs2bitvecs(xt, qcodes.get(), nbits, n);
119
118
 
120
- int* idistances = new int[n * k];
121
- ScopeDeleter<int> del3(idistances);
119
+ std::unique_ptr<int[]> idistances(new int[n * k]);
122
120
 
123
- int_maxheap_array_t res = {size_t(n), size_t(k), labels, idistances};
121
+ int_maxheap_array_t res = {size_t(n), size_t(k), labels, idistances.get()};
124
122
 
125
- hammings_knn_hc(&res, qcodes, codes.data(), ntotal, code_size, true);
123
+ hammings_knn_hc(&res, qcodes.get(), codes.data(), ntotal, code_size, true);
126
124
 
127
125
  // convert distances to floats
128
126
  for (int i = 0; i < k * n; i++)
@@ -146,16 +144,16 @@ void IndexLSH::transfer_thresholds(LinearTransform* vt) {
146
144
  void IndexLSH::sa_encode(idx_t n, const float* x, uint8_t* bytes) const {
147
145
  FAISS_THROW_IF_NOT(is_trained);
148
146
  const float* xt = apply_preprocess(n, x);
149
- ScopeDeleter<float> del(xt == x ? nullptr : xt);
147
+ std::unique_ptr<const float[]> del(xt == x ? nullptr : xt);
150
148
  fvecs2bitvecs(xt, bytes, nbits, n);
151
149
  }
152
150
 
153
151
  void IndexLSH::sa_decode(idx_t n, const uint8_t* bytes, float* x) const {
154
152
  float* xt = x;
155
- ScopeDeleter<float> del;
153
+ std::unique_ptr<float[]> del;
156
154
  if (rotate_data || nbits != d) {
157
155
  xt = new float[n * nbits];
158
- del.set(xt);
156
+ del.reset(xt);
159
157
  }
160
158
  bitvecs2fvecs(bytes, xt, nbits, n);
161
159
 
@@ -158,8 +158,8 @@ void IndexNNDescent::search(
158
158
  {
159
159
  VisitedTable vt(ntotal);
160
160
 
161
- DistanceComputer* dis = storage_distance_computer(storage);
162
- ScopeDeleter1<DistanceComputer> del(dis);
161
+ std::unique_ptr<DistanceComputer> dis(
162
+ storage_distance_computer(storage));
163
163
 
164
164
  #pragma omp for
165
165
  for (idx_t i = i0; i < i1; i++) {
@@ -197,8 +197,7 @@ void IndexNNDescent::add(idx_t n, const float* x) {
197
197
  storage->add(n, x);
198
198
  ntotal = storage->ntotal;
199
199
 
200
- DistanceComputer* dis = storage_distance_computer(storage);
201
- ScopeDeleter1<DistanceComputer> del(dis);
200
+ std::unique_ptr<DistanceComputer> dis(storage_distance_computer(storage));
202
201
  nndescent.build(*dis, ntotal, verbose);
203
202
  }
204
203
 
@@ -29,32 +29,16 @@ using namespace nsg;
29
29
  * IndexNSG implementation
30
30
  **************************************************************/
31
31
 
32
- IndexNSG::IndexNSG(int d, int R, MetricType metric)
33
- : Index(d, metric),
34
- nsg(R),
35
- own_fields(false),
36
- storage(nullptr),
37
- is_built(false),
38
- GK(64),
39
- build_type(0) {
40
- nndescent_S = 10;
41
- nndescent_R = 100;
32
+ IndexNSG::IndexNSG(int d, int R, MetricType metric) : Index(d, metric), nsg(R) {
42
33
  nndescent_L = GK + 50;
43
- nndescent_iter = 10;
44
34
  }
45
35
 
46
36
  IndexNSG::IndexNSG(Index* storage, int R)
47
37
  : Index(storage->d, storage->metric_type),
48
38
  nsg(R),
49
- own_fields(false),
50
39
  storage(storage),
51
- is_built(false),
52
- GK(64),
53
40
  build_type(1) {
54
- nndescent_S = 10;
55
- nndescent_R = 100;
56
41
  nndescent_L = GK + 50;
57
- nndescent_iter = 10;
58
42
  }
59
43
 
60
44
  IndexNSG::~IndexNSG() {
@@ -95,8 +79,8 @@ void IndexNSG::search(
95
79
  {
96
80
  VisitedTable vt(ntotal);
97
81
 
98
- DistanceComputer* dis = storage_distance_computer(storage);
99
- ScopeDeleter1<DistanceComputer> del(dis);
82
+ std::unique_ptr<DistanceComputer> dis(
83
+ storage_distance_computer(storage));
100
84
 
101
85
  #pragma omp for
102
86
  for (idx_t i = i0; i < i1; i++) {
@@ -120,7 +104,7 @@ void IndexNSG::search(
120
104
  }
121
105
  }
122
106
 
123
- void IndexNSG::build(idx_t n, const float* x, idx_t* knn_graph, int GK) {
107
+ void IndexNSG::build(idx_t n, const float* x, idx_t* knn_graph, int GK_2) {
124
108
  FAISS_THROW_IF_NOT_MSG(
125
109
  storage,
126
110
  "Please use IndexNSGFlat (or variants) instead of IndexNSG directly");
@@ -131,9 +115,9 @@ void IndexNSG::build(idx_t n, const float* x, idx_t* knn_graph, int GK) {
131
115
  ntotal = storage->ntotal;
132
116
 
133
117
  // check the knn graph
134
- check_knn_graph(knn_graph, n, GK);
118
+ check_knn_graph(knn_graph, n, GK_2);
135
119
 
136
- const nsg::Graph<idx_t> knng(knn_graph, n, GK);
120
+ const nsg::Graph<idx_t> knng(knn_graph, n, GK_2);
137
121
  nsg.build(storage, n, knng, verbose);
138
122
  is_built = true;
139
123
  }
@@ -302,10 +286,10 @@ IndexNSGFlat::IndexNSGFlat(int d, int R, MetricType metric)
302
286
  * IndexNSGPQ implementation
303
287
  **************************************************************/
304
288
 
305
- IndexNSGPQ::IndexNSGPQ() {}
289
+ IndexNSGPQ::IndexNSGPQ() = default;
306
290
 
307
- IndexNSGPQ::IndexNSGPQ(int d, int pq_m, int M)
308
- : IndexNSG(new IndexPQ(d, pq_m, 8), M) {
291
+ IndexNSGPQ::IndexNSGPQ(int d, int pq_m, int M, int pq_nbits)
292
+ : IndexNSG(new IndexPQ(d, pq_m, pq_nbits), M) {
309
293
  own_fields = true;
310
294
  is_trained = false;
311
295
  }
@@ -325,10 +309,10 @@ IndexNSGSQ::IndexNSGSQ(
325
309
  int M,
326
310
  MetricType metric)
327
311
  : IndexNSG(new IndexScalarQuantizer(d, qtype, metric), M) {
328
- is_trained = false;
312
+ is_trained = this->storage->is_trained;
329
313
  own_fields = true;
330
314
  }
331
315
 
332
- IndexNSGSQ::IndexNSGSQ() {}
316
+ IndexNSGSQ::IndexNSGSQ() = default;
333
317
 
334
318
  } // namespace faiss
@@ -28,25 +28,25 @@ struct IndexNSG : Index {
28
28
  NSG nsg;
29
29
 
30
30
  /// the sequential storage
31
- bool own_fields;
32
- Index* storage;
31
+ bool own_fields = false;
32
+ Index* storage = nullptr;
33
33
 
34
34
  /// the index is built or not
35
- bool is_built;
35
+ bool is_built = false;
36
36
 
37
37
  /// K of KNN graph for building
38
- int GK;
38
+ int GK = 64;
39
39
 
40
40
  /// indicate how to build a knn graph
41
41
  /// - 0: build NSG with brute force search
42
42
  /// - 1: build NSG with NNDescent
43
- char build_type;
43
+ char build_type = 0;
44
44
 
45
45
  /// parameters for nndescent
46
- int nndescent_S;
47
- int nndescent_R;
48
- int nndescent_L;
49
- int nndescent_iter;
46
+ int nndescent_S = 10;
47
+ int nndescent_R = 100;
48
+ int nndescent_L; // set to GK + 50
49
+ int nndescent_iter = 10;
50
50
 
51
51
  explicit IndexNSG(int d = 0, int R = 32, MetricType metric = METRIC_L2);
52
52
  explicit IndexNSG(Index* storage, int R = 32);
@@ -90,7 +90,7 @@ struct IndexNSGFlat : IndexNSG {
90
90
  */
91
91
  struct IndexNSGPQ : IndexNSG {
92
92
  IndexNSGPQ();
93
- IndexNSGPQ(int d, int pq_m, int M);
93
+ IndexNSGPQ(int d, int pq_m, int M, int pq_nbits = 8);
94
94
  void train(idx_t n, const float* x) override;
95
95
  };
96
96