faiss 0.5.2 → 0.6.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/LICENSE.txt +1 -1
- data/ext/faiss/ext.cpp +1 -1
- data/ext/faiss/extconf.rb +5 -6
- data/ext/faiss/index_binary.cpp +76 -17
- data/ext/faiss/{index.cpp → index_rb.cpp} +108 -35
- data/ext/faiss/kmeans.cpp +12 -9
- data/ext/faiss/numo.hpp +11 -9
- data/ext/faiss/pca_matrix.cpp +10 -8
- data/ext/faiss/product_quantizer.cpp +14 -12
- data/ext/faiss/{utils.cpp → utils_rb.cpp} +10 -3
- data/ext/faiss/{utils.h → utils_rb.h} +6 -0
- data/lib/faiss/version.rb +1 -1
- data/lib/faiss.rb +1 -1
- data/vendor/faiss/faiss/AutoTune.cpp +130 -11
- data/vendor/faiss/faiss/AutoTune.h +14 -1
- data/vendor/faiss/faiss/Clustering.cpp +59 -10
- data/vendor/faiss/faiss/Clustering.h +12 -0
- data/vendor/faiss/faiss/IVFlib.cpp +31 -28
- data/vendor/faiss/faiss/Index.cpp +20 -8
- data/vendor/faiss/faiss/Index.h +25 -3
- data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +19 -24
- data/vendor/faiss/faiss/IndexBinary.cpp +1 -0
- data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +9 -4
- data/vendor/faiss/faiss/IndexBinaryIVF.cpp +45 -11
- data/vendor/faiss/faiss/IndexFastScan.cpp +35 -22
- data/vendor/faiss/faiss/IndexFastScan.h +10 -1
- data/vendor/faiss/faiss/IndexFlat.cpp +193 -136
- data/vendor/faiss/faiss/IndexFlat.h +16 -1
- data/vendor/faiss/faiss/IndexFlatCodes.cpp +46 -22
- data/vendor/faiss/faiss/IndexFlatCodes.h +7 -1
- data/vendor/faiss/faiss/IndexHNSW.cpp +24 -50
- data/vendor/faiss/faiss/IndexHNSW.h +14 -12
- data/vendor/faiss/faiss/IndexIDMap.cpp +1 -1
- data/vendor/faiss/faiss/IndexIVF.cpp +76 -49
- data/vendor/faiss/faiss/IndexIVF.h +14 -4
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +11 -8
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.h +2 -2
- data/vendor/faiss/faiss/IndexIVFFastScan.cpp +25 -14
- data/vendor/faiss/faiss/IndexIVFFastScan.h +26 -22
- data/vendor/faiss/faiss/IndexIVFFlat.cpp +10 -61
- data/vendor/faiss/faiss/IndexIVFFlatPanorama.cpp +39 -111
- data/vendor/faiss/faiss/IndexIVFPQ.cpp +89 -147
- data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +37 -5
- data/vendor/faiss/faiss/IndexIVFPQR.cpp +2 -1
- data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +42 -30
- data/vendor/faiss/faiss/IndexIVFRaBitQ.h +2 -2
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +246 -97
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +32 -29
- data/vendor/faiss/faiss/IndexLSH.cpp +8 -6
- data/vendor/faiss/faiss/IndexLattice.cpp +29 -24
- data/vendor/faiss/faiss/IndexNNDescent.cpp +1 -0
- data/vendor/faiss/faiss/IndexNSG.cpp +2 -1
- data/vendor/faiss/faiss/IndexNSG.h +0 -2
- data/vendor/faiss/faiss/IndexNeuralNetCodec.cpp +1 -1
- data/vendor/faiss/faiss/IndexPQ.cpp +19 -10
- data/vendor/faiss/faiss/IndexRaBitQ.cpp +26 -13
- data/vendor/faiss/faiss/IndexRaBitQ.h +2 -2
- data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +132 -78
- data/vendor/faiss/faiss/IndexRaBitQFastScan.h +14 -12
- data/vendor/faiss/faiss/IndexRefine.cpp +0 -30
- data/vendor/faiss/faiss/IndexShards.cpp +3 -4
- data/vendor/faiss/faiss/MetricType.h +16 -0
- data/vendor/faiss/faiss/VectorTransform.cpp +120 -0
- data/vendor/faiss/faiss/VectorTransform.h +23 -0
- data/vendor/faiss/faiss/clone_index.cpp +7 -4
- data/vendor/faiss/faiss/{cppcontrib/factory_tools.cpp → factory_tools.cpp} +1 -1
- data/vendor/faiss/faiss/gpu/GpuCloner.cpp +1 -1
- data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +37 -11
- data/vendor/faiss/faiss/impl/AuxIndexStructures.h +0 -28
- data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +367 -0
- data/vendor/faiss/faiss/impl/ClusteringInitialization.h +107 -0
- data/vendor/faiss/faiss/impl/CodePacker.cpp +4 -0
- data/vendor/faiss/faiss/impl/CodePacker.h +11 -3
- data/vendor/faiss/faiss/impl/CodePackerRaBitQ.cpp +83 -0
- data/vendor/faiss/faiss/impl/CodePackerRaBitQ.h +47 -0
- data/vendor/faiss/faiss/impl/FaissAssert.h +60 -2
- data/vendor/faiss/faiss/impl/HNSW.cpp +25 -34
- data/vendor/faiss/faiss/impl/HNSW.h +8 -6
- data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +34 -27
- data/vendor/faiss/faiss/impl/NNDescent.cpp +1 -1
- data/vendor/faiss/faiss/impl/NSG.cpp +6 -5
- data/vendor/faiss/faiss/impl/NSG.h +17 -7
- data/vendor/faiss/faiss/impl/Panorama.cpp +53 -46
- data/vendor/faiss/faiss/impl/Panorama.h +22 -6
- data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +16 -5
- data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +70 -58
- data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +92 -0
- data/vendor/faiss/faiss/impl/RaBitQUtils.h +93 -31
- data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +12 -28
- data/vendor/faiss/faiss/impl/RaBitQuantizer.h +3 -10
- data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +15 -41
- data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.h +0 -4
- data/vendor/faiss/faiss/impl/ResidualQuantizer.cpp +14 -9
- data/vendor/faiss/faiss/impl/ResultHandler.h +131 -50
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +67 -2358
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +0 -2
- data/vendor/faiss/faiss/impl/VisitedTable.cpp +42 -0
- data/vendor/faiss/faiss/impl/VisitedTable.h +69 -0
- data/vendor/faiss/faiss/impl/expanded_scanners.h +158 -0
- data/vendor/faiss/faiss/impl/index_read.cpp +829 -471
- data/vendor/faiss/faiss/impl/index_read_utils.h +0 -1
- data/vendor/faiss/faiss/impl/index_write.cpp +17 -8
- data/vendor/faiss/faiss/impl/lattice_Zn.cpp +47 -20
- data/vendor/faiss/faiss/impl/mapped_io.cpp +9 -2
- data/vendor/faiss/faiss/impl/pq4_fast_scan.cpp +7 -2
- data/vendor/faiss/faiss/impl/pq4_fast_scan.h +11 -3
- data/vendor/faiss/faiss/impl/pq4_fast_scan_search_1.cpp +19 -13
- data/vendor/faiss/faiss/impl/pq4_fast_scan_search_qbs.cpp +29 -21
- data/vendor/faiss/faiss/impl/{code_distance/code_distance-avx2.h → pq_code_distance/pq_code_distance-avx2.cpp} +42 -215
- data/vendor/faiss/faiss/impl/{code_distance/code_distance-avx512.h → pq_code_distance/pq_code_distance-avx512.cpp} +68 -107
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +141 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-inl.h +23 -0
- data/vendor/faiss/faiss/impl/{code_distance/code_distance-sve.h → pq_code_distance/pq_code_distance-sve.cpp} +57 -144
- data/vendor/faiss/faiss/impl/residual_quantizer_encode_steps.cpp +9 -6
- data/vendor/faiss/faiss/impl/scalar_quantizer/codecs.h +121 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +136 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +280 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/scanners.h +164 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/similarities.h +94 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +455 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +430 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +329 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +467 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/training.cpp +203 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/training.h +42 -0
- data/vendor/faiss/faiss/impl/simd_dispatch.h +139 -0
- data/vendor/faiss/faiss/impl/simd_result_handlers.h +18 -18
- data/vendor/faiss/faiss/index_factory.cpp +35 -16
- data/vendor/faiss/faiss/index_io.h +29 -3
- data/vendor/faiss/faiss/invlists/BlockInvertedLists.cpp +7 -4
- data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +1 -1
- data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +9 -19
- data/vendor/faiss/faiss/svs/IndexSVSFlat.h +2 -0
- data/vendor/faiss/faiss/svs/IndexSVSVamana.h +2 -1
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +9 -1
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.h +9 -0
- data/vendor/faiss/faiss/utils/Heap.cpp +46 -0
- data/vendor/faiss/faiss/utils/Heap.h +21 -0
- data/vendor/faiss/faiss/utils/NeuralNet.cpp +10 -7
- data/vendor/faiss/faiss/utils/distances.cpp +141 -23
- data/vendor/faiss/faiss/utils/distances.h +98 -0
- data/vendor/faiss/faiss/utils/distances_dispatch.h +170 -0
- data/vendor/faiss/faiss/utils/distances_simd.cpp +74 -3511
- data/vendor/faiss/faiss/utils/extra_distances-inl.h +164 -157
- data/vendor/faiss/faiss/utils/extra_distances.cpp +52 -95
- data/vendor/faiss/faiss/utils/extra_distances.h +47 -1
- data/vendor/faiss/faiss/utils/hamming_distance/generic-inl.h +0 -1
- data/vendor/faiss/faiss/utils/partitioning.cpp +1 -1
- data/vendor/faiss/faiss/utils/pq_code_distance.h +251 -0
- data/vendor/faiss/faiss/utils/rabitq_simd.h +260 -0
- data/vendor/faiss/faiss/utils/simd_impl/distances_aarch64.cpp +150 -0
- data/vendor/faiss/faiss/utils/simd_impl/distances_arm_sve.cpp +568 -0
- data/vendor/faiss/faiss/utils/simd_impl/distances_autovec-inl.h +153 -0
- data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +1185 -0
- data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +1092 -0
- data/vendor/faiss/faiss/utils/simd_impl/distances_sse-inl.h +391 -0
- data/vendor/faiss/faiss/utils/simd_levels.cpp +322 -0
- data/vendor/faiss/faiss/utils/simd_levels.h +91 -0
- data/vendor/faiss/faiss/utils/simdlib_avx2.h +12 -1
- data/vendor/faiss/faiss/utils/simdlib_avx512.h +69 -0
- data/vendor/faiss/faiss/utils/simdlib_neon.h +6 -0
- data/vendor/faiss/faiss/utils/sorting.cpp +4 -4
- data/vendor/faiss/faiss/utils/utils.cpp +16 -9
- metadata +47 -18
- data/vendor/faiss/faiss/impl/code_distance/code_distance-generic.h +0 -81
- data/vendor/faiss/faiss/impl/code_distance/code_distance.h +0 -186
- /data/vendor/faiss/faiss/{cppcontrib/factory_tools.h → factory_tools.h} +0 -0
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
#include <faiss/impl/FaissException.h>
|
|
14
14
|
#include <faiss/impl/platform_macros.h>
|
|
15
|
+
#include <cinttypes>
|
|
15
16
|
#include <cstdio>
|
|
16
17
|
#include <cstdlib>
|
|
17
18
|
#include <string>
|
|
@@ -69,7 +70,7 @@
|
|
|
69
70
|
|
|
70
71
|
#define FAISS_THROW_MSG(MSG) \
|
|
71
72
|
do { \
|
|
72
|
-
throw faiss::FaissException(
|
|
73
|
+
throw ::faiss::FaissException( \
|
|
73
74
|
MSG, __PRETTY_FUNCTION__, __FILE__, __LINE__); \
|
|
74
75
|
} while (false)
|
|
75
76
|
|
|
@@ -79,7 +80,7 @@
|
|
|
79
80
|
int __size = snprintf(nullptr, 0, FMT, __VA_ARGS__); \
|
|
80
81
|
__s.resize(__size + 1); \
|
|
81
82
|
snprintf(&__s[0], __s.size(), FMT, __VA_ARGS__); \
|
|
82
|
-
throw faiss::FaissException(
|
|
83
|
+
throw ::faiss::FaissException( \
|
|
83
84
|
__s, __PRETTY_FUNCTION__, __FILE__, __LINE__); \
|
|
84
85
|
} while (false)
|
|
85
86
|
|
|
@@ -110,4 +111,61 @@
|
|
|
110
111
|
} \
|
|
111
112
|
} while (false)
|
|
112
113
|
|
|
114
|
+
///
|
|
115
|
+
/// Safe arithmetic
|
|
116
|
+
///
|
|
117
|
+
|
|
118
|
+
#include <limits>
|
|
119
|
+
|
|
120
|
+
namespace faiss {
|
|
121
|
+
|
|
122
|
+
/// Multiplication that throws on overflow instead of wrapping
|
|
123
|
+
inline size_t mul_no_overflow(size_t a, size_t b, const char* context) {
|
|
124
|
+
if (a != 0 && b > (std::numeric_limits<size_t>::max)() / a) {
|
|
125
|
+
FAISS_THROW_FMT("integer overflow in %s: %zu * %zu", context, a, b);
|
|
126
|
+
}
|
|
127
|
+
return a * b;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/// Addition that throws on overflow instead of wrapping
|
|
131
|
+
inline size_t add_no_overflow(size_t a, size_t b, const char* context) {
|
|
132
|
+
if (a > (std::numeric_limits<size_t>::max)() - b) {
|
|
133
|
+
FAISS_THROW_FMT("integer overflow in %s: %zu + %zu", context, a, b);
|
|
134
|
+
}
|
|
135
|
+
return a + b;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
} // namespace faiss
|
|
139
|
+
|
|
140
|
+
///
|
|
141
|
+
/// Bounds checking
|
|
142
|
+
///
|
|
143
|
+
|
|
144
|
+
/// Check that val is in half-open range [lo, hi). Throws with the
|
|
145
|
+
/// stringified expression, its value, and the bounds on failure.
|
|
146
|
+
#define FAISS_CHECK_RANGE(val, lo, hi) \
|
|
147
|
+
FAISS_THROW_IF_NOT_FMT( \
|
|
148
|
+
(int64_t)(val) >= (int64_t)(lo) && (int64_t)(val) < (int64_t)(hi), \
|
|
149
|
+
"%s (= %" PRId64 ") out of range [%" PRId64 ", %" PRId64 ")", \
|
|
150
|
+
#val, \
|
|
151
|
+
(int64_t)(val), \
|
|
152
|
+
(int64_t)(lo), \
|
|
153
|
+
(int64_t)(hi))
|
|
154
|
+
|
|
155
|
+
/// Debug-only variant of FAISS_CHECK_RANGE. Aborts in debug builds
|
|
156
|
+
/// (when NDEBUG is not defined); compiled out in release builds to
|
|
157
|
+
/// avoid overhead in hot paths.
|
|
158
|
+
#ifndef NDEBUG
|
|
159
|
+
#define FAISS_CHECK_RANGE_DEBUG(val, lo, hi) \
|
|
160
|
+
FAISS_ASSERT_FMT( \
|
|
161
|
+
(int64_t)(val) >= (int64_t)(lo) && (int64_t)(val) < (int64_t)(hi), \
|
|
162
|
+
"%s (= %" PRId64 ") out of range [%" PRId64 ", %" PRId64 ")", \
|
|
163
|
+
#val, \
|
|
164
|
+
(int64_t)(val), \
|
|
165
|
+
(int64_t)(lo), \
|
|
166
|
+
(int64_t)(hi))
|
|
167
|
+
#else
|
|
168
|
+
#define FAISS_CHECK_RANGE_DEBUG(val, lo, hi) ((void)0)
|
|
169
|
+
#endif
|
|
170
|
+
|
|
113
171
|
#endif
|
|
@@ -7,15 +7,15 @@
|
|
|
7
7
|
|
|
8
8
|
#include <faiss/impl/HNSW.h>
|
|
9
9
|
|
|
10
|
+
#include <cinttypes>
|
|
10
11
|
#include <cstddef>
|
|
11
12
|
|
|
12
13
|
#include <faiss/IndexHNSW.h>
|
|
13
14
|
|
|
14
|
-
#include <faiss/impl/AuxIndexStructures.h>
|
|
15
15
|
#include <faiss/impl/DistanceComputer.h>
|
|
16
16
|
#include <faiss/impl/IDSelector.h>
|
|
17
17
|
#include <faiss/impl/ResultHandler.h>
|
|
18
|
-
#include <faiss/
|
|
18
|
+
#include <faiss/impl/VisitedTable.h>
|
|
19
19
|
|
|
20
20
|
#ifdef __AVX2__
|
|
21
21
|
#include <immintrin.h>
|
|
@@ -45,11 +45,15 @@ void HNSW::set_nb_neighbors(int level_no, int n) {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
int HNSW::cum_nb_neighbors(int layer_no) const {
|
|
48
|
+
FAISS_CHECK_RANGE_DEBUG(layer_no, 0, (int)cum_nneighbor_per_level.size());
|
|
48
49
|
return cum_nneighbor_per_level[layer_no];
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
void HNSW::neighbor_range(idx_t no, int layer_no, size_t* begin, size_t* end)
|
|
52
53
|
const {
|
|
54
|
+
FAISS_CHECK_RANGE_DEBUG(no, 0, (idx_t)offsets.size());
|
|
55
|
+
FAISS_CHECK_RANGE_DEBUG(
|
|
56
|
+
layer_no, 0, (int)cum_nneighbor_per_level.size() - 1);
|
|
53
57
|
size_t o = offsets[no];
|
|
54
58
|
*begin = o + cum_nb_neighbors(layer_no);
|
|
55
59
|
*end = o + cum_nb_neighbors(layer_no + 1);
|
|
@@ -407,10 +411,9 @@ void search_neighbors_to_add(
|
|
|
407
411
|
if (nodeId < 0) {
|
|
408
412
|
break;
|
|
409
413
|
}
|
|
410
|
-
if (vt.
|
|
414
|
+
if (!vt.set(nodeId)) {
|
|
411
415
|
continue;
|
|
412
416
|
}
|
|
413
|
-
vt.set(nodeId);
|
|
414
417
|
|
|
415
418
|
float dis = qdis(nodeId);
|
|
416
419
|
NodeDistFarther evE1(dis, nodeId);
|
|
@@ -448,10 +451,9 @@ void search_neighbors_to_add(
|
|
|
448
451
|
if (nodeId < 0) {
|
|
449
452
|
break;
|
|
450
453
|
}
|
|
451
|
-
if (vt.
|
|
454
|
+
if (!vt.set(nodeId)) {
|
|
452
455
|
continue;
|
|
453
456
|
}
|
|
454
|
-
vt.set(nodeId);
|
|
455
457
|
|
|
456
458
|
buffered_ids[n_buffered] = nodeId;
|
|
457
459
|
n_buffered += 1;
|
|
@@ -616,7 +618,7 @@ static inline void extract_search_params(
|
|
|
616
618
|
int search_from_candidates(
|
|
617
619
|
const HNSW& hnsw,
|
|
618
620
|
DistanceComputer& qdis,
|
|
619
|
-
ResultHandler
|
|
621
|
+
ResultHandler& res,
|
|
620
622
|
MinimaxHeap& candidates,
|
|
621
623
|
VisitedTable& vt,
|
|
622
624
|
HNSWStats& stats,
|
|
@@ -675,7 +677,7 @@ int search_from_candidates(
|
|
|
675
677
|
break;
|
|
676
678
|
}
|
|
677
679
|
|
|
678
|
-
|
|
680
|
+
vt.prefetch(v1);
|
|
679
681
|
jmax += 1;
|
|
680
682
|
}
|
|
681
683
|
|
|
@@ -699,10 +701,8 @@ int search_from_candidates(
|
|
|
699
701
|
for (size_t j = begin; j < jmax; j++) {
|
|
700
702
|
int v1 = hnsw.neighbors[j];
|
|
701
703
|
|
|
702
|
-
bool vget = vt.get(v1);
|
|
703
|
-
vt.set(v1);
|
|
704
704
|
saved_j[counter] = v1;
|
|
705
|
-
counter +=
|
|
705
|
+
counter += vt.set(v1) ? 1 : 0;
|
|
706
706
|
|
|
707
707
|
if (counter == 4) {
|
|
708
708
|
float dis[4];
|
|
@@ -755,7 +755,7 @@ int search_from_candidates_panorama(
|
|
|
755
755
|
const HNSW& hnsw,
|
|
756
756
|
const IndexHNSW* index,
|
|
757
757
|
DistanceComputer& qdis,
|
|
758
|
-
ResultHandler
|
|
758
|
+
ResultHandler& res,
|
|
759
759
|
MinimaxHeap& candidates,
|
|
760
760
|
VisitedTable& vt,
|
|
761
761
|
HNSWStats& stats,
|
|
@@ -802,13 +802,8 @@ int search_from_candidates_panorama(
|
|
|
802
802
|
std::vector<float> exact_distances(M);
|
|
803
803
|
|
|
804
804
|
const float* query = flat_codes_qdis->q;
|
|
805
|
-
std::vector<float> query_cum_sums(panorama_index->
|
|
806
|
-
|
|
807
|
-
query,
|
|
808
|
-
query_cum_sums.data(),
|
|
809
|
-
panorama_index->d,
|
|
810
|
-
panorama_index->num_panorama_levels,
|
|
811
|
-
panorama_index->panorama_level_width);
|
|
805
|
+
std::vector<float> query_cum_sums(panorama_index->pano.n_levels + 1);
|
|
806
|
+
panorama_index->pano.compute_query_cum_sums(query, query_cum_sums.data());
|
|
812
807
|
float query_norm_sq = query_cum_sums[0] * query_cum_sums[0];
|
|
813
808
|
|
|
814
809
|
int nstep = 0;
|
|
@@ -847,21 +842,19 @@ int search_from_candidates_panorama(
|
|
|
847
842
|
query_norm_sq + cum_sums_v1[0] * cum_sums_v1[0];
|
|
848
843
|
|
|
849
844
|
bool is_selected = !sel || sel->is_member(v1);
|
|
850
|
-
initial_size += is_selected &&
|
|
851
|
-
|
|
852
|
-
vt.set(v1);
|
|
845
|
+
initial_size += is_selected && vt.set(v1) ? 1 : 0;
|
|
853
846
|
}
|
|
854
847
|
|
|
855
848
|
size_t batch_size = initial_size;
|
|
856
849
|
size_t curr_panorama_level = 0;
|
|
857
|
-
const size_t num_panorama_levels = panorama_index->
|
|
850
|
+
const size_t num_panorama_levels = panorama_index->pano.n_levels;
|
|
858
851
|
while (curr_panorama_level < num_panorama_levels && batch_size > 0) {
|
|
859
852
|
float query_cum_norm = query_cum_sums[curr_panorama_level + 1];
|
|
860
853
|
|
|
861
|
-
|
|
862
|
-
panorama_index->
|
|
863
|
-
size_t
|
|
864
|
-
|
|
854
|
+
size_t start_dim = curr_panorama_level *
|
|
855
|
+
panorama_index->pano.level_width_floats;
|
|
856
|
+
size_t end_dim = (curr_panorama_level + 1) *
|
|
857
|
+
panorama_index->pano.level_width_floats;
|
|
865
858
|
end_dim = std::min(end_dim, static_cast<size_t>(panorama_index->d));
|
|
866
859
|
|
|
867
860
|
size_t i = 0;
|
|
@@ -1037,7 +1030,7 @@ std::priority_queue<HNSW::Node> search_from_candidate_unbounded(
|
|
|
1037
1030
|
break;
|
|
1038
1031
|
}
|
|
1039
1032
|
|
|
1040
|
-
|
|
1033
|
+
vt->prefetch(v1);
|
|
1041
1034
|
jmax += 1;
|
|
1042
1035
|
}
|
|
1043
1036
|
|
|
@@ -1059,10 +1052,8 @@ std::priority_queue<HNSW::Node> search_from_candidate_unbounded(
|
|
|
1059
1052
|
for (size_t j = begin; j < jmax; j++) {
|
|
1060
1053
|
int v1 = hnsw.neighbors[j];
|
|
1061
1054
|
|
|
1062
|
-
bool vget = vt->get(v1);
|
|
1063
|
-
vt->set(v1);
|
|
1064
1055
|
saved_j[counter] = v1;
|
|
1065
|
-
counter +=
|
|
1056
|
+
counter += vt->set(v1) ? 1 : 0;
|
|
1066
1057
|
|
|
1067
1058
|
if (counter == 4) {
|
|
1068
1059
|
float dis[4];
|
|
@@ -1187,7 +1178,7 @@ using Node = HNSW::Node;
|
|
|
1187
1178
|
using C = HNSW::C;
|
|
1188
1179
|
|
|
1189
1180
|
// just used as a lower bound for the minmaxheap, but it is set for heap search
|
|
1190
|
-
int extract_k_from_ResultHandler(ResultHandler
|
|
1181
|
+
int extract_k_from_ResultHandler(ResultHandler& res) {
|
|
1191
1182
|
using RH = HeapBlockResultHandler<C>;
|
|
1192
1183
|
if (auto hres = dynamic_cast<RH::SingleResultHandler*>(&res)) {
|
|
1193
1184
|
return hres->k;
|
|
@@ -1200,7 +1191,7 @@ int extract_k_from_ResultHandler(ResultHandler<C>& res) {
|
|
|
1200
1191
|
HNSWStats HNSW::search(
|
|
1201
1192
|
DistanceComputer& qdis,
|
|
1202
1193
|
const IndexHNSW* index,
|
|
1203
|
-
ResultHandler
|
|
1194
|
+
ResultHandler& res,
|
|
1204
1195
|
VisitedTable& vt,
|
|
1205
1196
|
const SearchParameters* params) const {
|
|
1206
1197
|
HNSWStats stats;
|
|
@@ -1277,7 +1268,7 @@ HNSWStats HNSW::search(
|
|
|
1277
1268
|
|
|
1278
1269
|
void HNSW::search_level_0(
|
|
1279
1270
|
DistanceComputer& qdis,
|
|
1280
|
-
ResultHandler
|
|
1271
|
+
ResultHandler& res,
|
|
1281
1272
|
idx_t nprobe,
|
|
1282
1273
|
const storage_idx_t* nearest_i,
|
|
1283
1274
|
const float* nearest_d,
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
#pragma once
|
|
9
9
|
|
|
10
|
+
#include <optional>
|
|
10
11
|
#include <queue>
|
|
11
12
|
#include <vector>
|
|
12
13
|
|
|
@@ -45,8 +46,6 @@ struct IndexHNSWFlatPanorama;
|
|
|
45
46
|
struct VisitedTable;
|
|
46
47
|
struct DistanceComputer; // from AuxIndexStructures
|
|
47
48
|
struct HNSWStats;
|
|
48
|
-
template <class C>
|
|
49
|
-
struct ResultHandler;
|
|
50
49
|
|
|
51
50
|
struct SearchParametersHNSW : SearchParameters {
|
|
52
51
|
int efSearch = 16;
|
|
@@ -153,6 +152,9 @@ struct HNSW {
|
|
|
153
152
|
/// use Panorama progressive pruning in search
|
|
154
153
|
bool is_panorama = false;
|
|
155
154
|
|
|
155
|
+
// See impl/VisitedTable.h.
|
|
156
|
+
std::optional<bool> use_visited_hashset;
|
|
157
|
+
|
|
156
158
|
// methods that initialize the tree sizes
|
|
157
159
|
|
|
158
160
|
/// initialize the assign_probas and cum_nneighbor_per_level to
|
|
@@ -212,14 +214,14 @@ struct HNSW {
|
|
|
212
214
|
HNSWStats search(
|
|
213
215
|
DistanceComputer& qdis,
|
|
214
216
|
const IndexHNSW* index,
|
|
215
|
-
ResultHandler
|
|
217
|
+
ResultHandler& res,
|
|
216
218
|
VisitedTable& vt,
|
|
217
219
|
const SearchParameters* params = nullptr) const;
|
|
218
220
|
|
|
219
221
|
/// search only in level 0 from a given vertex
|
|
220
222
|
void search_level_0(
|
|
221
223
|
DistanceComputer& qdis,
|
|
222
|
-
ResultHandler
|
|
224
|
+
ResultHandler& res,
|
|
223
225
|
idx_t nprobe,
|
|
224
226
|
const storage_idx_t* nearest_i,
|
|
225
227
|
const float* nearest_d,
|
|
@@ -272,7 +274,7 @@ FAISS_API extern HNSWStats hnsw_stats;
|
|
|
272
274
|
int search_from_candidates(
|
|
273
275
|
const HNSW& hnsw,
|
|
274
276
|
DistanceComputer& qdis,
|
|
275
|
-
ResultHandler
|
|
277
|
+
ResultHandler& res,
|
|
276
278
|
HNSW::MinimaxHeap& candidates,
|
|
277
279
|
VisitedTable& vt,
|
|
278
280
|
HNSWStats& stats,
|
|
@@ -288,7 +290,7 @@ int search_from_candidates_panorama(
|
|
|
288
290
|
const HNSW& hnsw,
|
|
289
291
|
const IndexHNSW* index,
|
|
290
292
|
DistanceComputer& qdis,
|
|
291
|
-
ResultHandler
|
|
293
|
+
ResultHandler& res,
|
|
292
294
|
HNSW::MinimaxHeap& candidates,
|
|
293
295
|
VisitedTable& vt,
|
|
294
296
|
HNSWStats& stats,
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
#include <faiss/impl/AuxIndexStructures.h>
|
|
20
20
|
#include <faiss/impl/FaissAssert.h>
|
|
21
|
+
#include <faiss/impl/simd_dispatch.h>
|
|
21
22
|
#include <faiss/utils/distances.h>
|
|
22
23
|
#include <faiss/utils/utils.h>
|
|
23
24
|
|
|
@@ -684,22 +685,24 @@ void LocalSearchQuantizer::perturb_codes(
|
|
|
684
685
|
void LocalSearchQuantizer::compute_binary_terms(float* binaries) const {
|
|
685
686
|
LSQTimerScope scope(&lsq_timer, "compute_binary_terms");
|
|
686
687
|
|
|
688
|
+
with_simd_level([&]<SIMDLevel SL>() {
|
|
687
689
|
#pragma omp parallel for
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
690
|
+
for (int64_t m12 = 0; m12 < M * M; m12++) {
|
|
691
|
+
size_t m1 = m12 / M;
|
|
692
|
+
size_t m2 = m12 % M;
|
|
693
|
+
|
|
694
|
+
for (size_t code1 = 0; code1 < K; code1++) {
|
|
695
|
+
for (size_t code2 = 0; code2 < K; code2++) {
|
|
696
|
+
const float* c1 = codebooks.data() + m1 * K * d + code1 * d;
|
|
697
|
+
const float* c2 = codebooks.data() + m2 * K * d + code2 * d;
|
|
698
|
+
float ip = fvec_inner_product<SL>(c1, c2, d);
|
|
699
|
+
// binaries[m1, m2, code1, code2] = ip * 2
|
|
700
|
+
binaries[m1 * M * K * K + m2 * K * K + code1 * K + code2] =
|
|
701
|
+
ip * 2;
|
|
702
|
+
}
|
|
700
703
|
}
|
|
701
704
|
}
|
|
702
|
-
}
|
|
705
|
+
});
|
|
703
706
|
}
|
|
704
707
|
|
|
705
708
|
void LocalSearchQuantizer::compute_unary_terms(
|
|
@@ -760,23 +763,27 @@ float LocalSearchQuantizer::evaluate(
|
|
|
760
763
|
std::vector<float> decoded_x(n * d, 0.0f);
|
|
761
764
|
float obj = 0.0f;
|
|
762
765
|
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
766
|
+
with_simd_level([&]<SIMDLevel SL>() {
|
|
767
|
+
float local_obj = 0.0f;
|
|
768
|
+
#pragma omp parallel for reduction(+ : local_obj)
|
|
769
|
+
for (int64_t i = 0; i < n; i++) {
|
|
770
|
+
const auto code = codes + i * M;
|
|
771
|
+
const auto decoded_i = decoded_x.data() + i * d;
|
|
772
|
+
for (size_t m = 0; m < M; m++) {
|
|
773
|
+
// c = codebooks[m, code[m]]
|
|
774
|
+
const auto c = codebooks.data() + m * K * d + code[m] * d;
|
|
775
|
+
fvec_add(d, decoded_i, c, decoded_i);
|
|
776
|
+
}
|
|
772
777
|
|
|
773
|
-
|
|
774
|
-
|
|
778
|
+
float err = fvec_L2sqr<SL>(x + i * d, decoded_i, d);
|
|
779
|
+
local_obj += err;
|
|
775
780
|
|
|
776
|
-
|
|
777
|
-
|
|
781
|
+
if (objs) {
|
|
782
|
+
objs[i] = err;
|
|
783
|
+
}
|
|
778
784
|
}
|
|
779
|
-
|
|
785
|
+
obj = local_obj;
|
|
786
|
+
});
|
|
780
787
|
|
|
781
788
|
obj = obj / n;
|
|
782
789
|
return obj;
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
#include <stack>
|
|
14
14
|
|
|
15
15
|
#include <faiss/impl/DistanceComputer.h>
|
|
16
|
+
#include <faiss/impl/VisitedTable.h>
|
|
16
17
|
|
|
17
18
|
namespace faiss {
|
|
18
19
|
|
|
@@ -233,7 +234,7 @@ void NSG::init_graph(Index* storage, const nsg::Graph<idx_t>& knn_graph) {
|
|
|
233
234
|
std::unique_ptr<DistanceComputer> dis(storage_distance_computer(storage));
|
|
234
235
|
|
|
235
236
|
dis->set_query(center.get());
|
|
236
|
-
VisitedTable vt(ntotal);
|
|
237
|
+
VisitedTable vt(ntotal, use_visited_hashset);
|
|
237
238
|
|
|
238
239
|
// Do not collect the visited nodes
|
|
239
240
|
search_on_graph<false>(knn_graph, *dis, vt, ep, L, retset, tmpset);
|
|
@@ -304,7 +305,7 @@ void NSG::search_on_graph(
|
|
|
304
305
|
size_t nneigh_for_n = graph.get_neighbors(n, neighbors.data());
|
|
305
306
|
for (int m = 0; m < nneigh_for_n; m++) {
|
|
306
307
|
int id = neighbors[m];
|
|
307
|
-
if (id
|
|
308
|
+
if (id >= ntotal || vt.get(id)) {
|
|
308
309
|
continue;
|
|
309
310
|
}
|
|
310
311
|
vt.set(id);
|
|
@@ -341,7 +342,7 @@ void NSG::link(
|
|
|
341
342
|
std::vector<Node> pool;
|
|
342
343
|
std::vector<Neighbor> tmp;
|
|
343
344
|
|
|
344
|
-
VisitedTable vt(ntotal);
|
|
345
|
+
VisitedTable vt(ntotal, use_visited_hashset);
|
|
345
346
|
std::unique_ptr<DistanceComputer> dis(
|
|
346
347
|
storage_distance_computer(storage));
|
|
347
348
|
|
|
@@ -513,8 +514,8 @@ void NSG::add_reverse_links(
|
|
|
513
514
|
|
|
514
515
|
int NSG::tree_grow(Index* storage, std::vector<int>& degrees) {
|
|
515
516
|
int root = enterpoint;
|
|
516
|
-
VisitedTable vt(ntotal);
|
|
517
|
-
VisitedTable vt2(ntotal);
|
|
517
|
+
VisitedTable vt(ntotal, use_visited_hashset);
|
|
518
|
+
VisitedTable vt2(ntotal, use_visited_hashset);
|
|
518
519
|
|
|
519
520
|
int num_attached = 0;
|
|
520
521
|
int cnt = 0;
|
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
|
|
10
10
|
#include <memory>
|
|
11
11
|
#include <mutex>
|
|
12
|
+
#include <optional>
|
|
12
13
|
#include <vector>
|
|
13
14
|
|
|
14
15
|
#include <omp.h>
|
|
15
16
|
|
|
16
17
|
#include <faiss/Index.h>
|
|
17
|
-
#include <faiss/impl/AuxIndexStructures.h>
|
|
18
18
|
#include <faiss/impl/FaissAssert.h>
|
|
19
19
|
#include <faiss/utils/Heap.h>
|
|
20
20
|
#include <faiss/utils/random.h>
|
|
@@ -38,6 +38,7 @@ namespace faiss {
|
|
|
38
38
|
*/
|
|
39
39
|
|
|
40
40
|
struct DistanceComputer; // from AuxIndexStructures
|
|
41
|
+
struct VisitedTable;
|
|
41
42
|
|
|
42
43
|
namespace nsg {
|
|
43
44
|
|
|
@@ -65,12 +66,14 @@ struct Graph {
|
|
|
65
66
|
// construct an empty graph
|
|
66
67
|
// NOTE: the newly allocated data needs to be destroyed at destruction time
|
|
67
68
|
Graph(int N, int K) : K(K), N(N), own_fields(true) {
|
|
68
|
-
|
|
69
|
+
size_t total = faiss::mul_no_overflow(
|
|
70
|
+
(size_t)N, (size_t)K, "Graph allocation");
|
|
71
|
+
data = new node_t[total];
|
|
69
72
|
}
|
|
70
73
|
|
|
71
74
|
// copy constructor
|
|
72
75
|
Graph(const Graph& g) : Graph(g.N, g.K) {
|
|
73
|
-
memcpy(data, g.data, N * K * sizeof(node_t));
|
|
76
|
+
memcpy(data, g.data, (size_t)N * (size_t)K * sizeof(node_t));
|
|
74
77
|
}
|
|
75
78
|
|
|
76
79
|
// release the allocated memory if needed
|
|
@@ -82,21 +85,25 @@ struct Graph {
|
|
|
82
85
|
|
|
83
86
|
// access the j-th neighbor of node i
|
|
84
87
|
inline node_t at(int i, int j) const {
|
|
85
|
-
|
|
88
|
+
FAISS_CHECK_RANGE_DEBUG(i, 0, N);
|
|
89
|
+
FAISS_CHECK_RANGE_DEBUG(j, 0, K);
|
|
90
|
+
return data[(size_t)i * K + j];
|
|
86
91
|
}
|
|
87
92
|
|
|
88
93
|
// access the j-th neighbor of node i by reference
|
|
89
94
|
inline node_t& at(int i, int j) {
|
|
90
|
-
|
|
95
|
+
FAISS_CHECK_RANGE_DEBUG(i, 0, N);
|
|
96
|
+
FAISS_CHECK_RANGE_DEBUG(j, 0, K);
|
|
97
|
+
return data[(size_t)i * K + j];
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
// get all neighbors of node i (used during search only)
|
|
94
101
|
virtual size_t get_neighbors(int i, node_t* neighbors) const {
|
|
95
102
|
for (int j = 0; j < K; j++) {
|
|
96
|
-
if (data[i * K + j] < 0) {
|
|
103
|
+
if (data[(size_t)i * K + j] < 0) {
|
|
97
104
|
return j;
|
|
98
105
|
}
|
|
99
|
-
neighbors[j] = data[i * K + j];
|
|
106
|
+
neighbors[j] = data[(size_t)i * K + j];
|
|
100
107
|
}
|
|
101
108
|
return K;
|
|
102
109
|
}
|
|
@@ -122,6 +129,9 @@ struct NSG {
|
|
|
122
129
|
// search-time parameters
|
|
123
130
|
int search_L = 16; ///< length of the search path
|
|
124
131
|
|
|
132
|
+
// See impl/VisitedTable.h.
|
|
133
|
+
std::optional<bool> use_visited_hashset;
|
|
134
|
+
|
|
125
135
|
int enterpoint; ///< enterpoint
|
|
126
136
|
|
|
127
137
|
std::shared_ptr<nsg::Graph<int32_t>> final_graph; ///< NSG graph structure
|