14 #include "VectorTransform.h"
15 #include "FaissAssert.h"
19 namespace faiss {
namespace ivflib {
22 void check_compatible_for_merge (
const Index * index0,
32 FAISS_THROW_IF_NOT_MSG (pt1,
"both indexes should be pretransforms");
34 FAISS_THROW_IF_NOT (pt0->chain.size() == pt1->chain.size());
35 for (
int i = 0; i < pt0->chain.size(); i++) {
36 FAISS_THROW_IF_NOT (
typeid(pt0->chain[i]) ==
typeid(pt1->chain[i]));
42 FAISS_THROW_IF_NOT (
typeid(index0) ==
typeid(index1));
43 FAISS_THROW_IF_NOT (index0->d == index1->d &&
44 index0->metric_type == index1->metric_type);
50 FAISS_THROW_IF_NOT (ivf1);
59 const IndexIVF * extract_index_ivf (
const Index * index)
62 dynamic_cast<const IndexPreTransform *>(index)) {
66 auto *ivf =
dynamic_cast<const IndexIVF *
>(index);
68 FAISS_THROW_IF_NOT (ivf);
73 IndexIVF * extract_index_ivf (Index * index) {
74 return const_cast<IndexIVF*
> (extract_index_ivf ((
const Index*)(index)));
79 check_compatible_for_merge (index0, index1);
80 IndexIVF * ivf0 = extract_index_ivf (index0);
81 IndexIVF * ivf1 = extract_index_ivf (index1);
83 ivf0->merge_from (*ivf1, shift_ids ? ivf0->ntotal : 0);
86 index0->
ntotal = ivf0->ntotal;
87 index1->
ntotal = ivf1->ntotal;
93 const float* x,
int n,
96 std::unique_ptr<float[]> del;
97 if (
auto index_pre = dynamic_cast<faiss::IndexPreTransform*>(index)) {
98 x = index_pre->apply_chain(n, x);
100 index = index_pre->index;
115 idx_t* query_centroid_ids,
116 idx_t* result_centroid_ids)
118 const float *x = xin;
119 std::unique_ptr<float []> del;
120 if (
auto index_pre = dynamic_cast<faiss::IndexPreTransform*>(index)) {
121 x = index_pre->apply_chain(n, x);
122 del.reset((
float*)x);
123 index = index_pre->index;
128 size_t nprobe = index_ivf->
nprobe;
129 std::vector<idx_t> cent_nos (n * nprobe);
130 std::vector<float> cent_dis (n * nprobe);
132 n, x, nprobe, cent_dis.data(), cent_nos.data());
134 if (query_centroid_ids) {
135 for (
size_t i = 0; i < n; i++)
136 query_centroid_ids[i] = cent_nos[i * nprobe];
140 cent_nos.data(), cent_dis.data(),
141 distances, labels,
true);
143 for (
size_t i = 0; i < n * k; i++) {
144 idx_t label = labels[i];
146 if (result_centroid_ids)
147 result_centroid_ids[i] = -1;
149 long list_no = label >> 32;
150 long list_index = label & 0xffffffff;
151 if (result_centroid_ids)
152 result_centroid_ids[i] = list_no;
164 FAISS_THROW_IF_NOT_MSG (
ils,
165 "only supports indexes with ArrayInvertedLists");
170 static void shift_and_add (std::vector<T> & dst,
172 const std::vector<T> & src)
175 memmove (dst.data(), dst.data() +
remove,
176 (dst.size() -
remove) *
sizeof (T));
177 size_t insert_point = dst.size() -
remove;
178 dst.resize (insert_point + src.size());
179 memcpy (dst.data() + insert_point, src.data (), src.size() *
sizeof(T));
183 static void remove_from_begin (std::vector<T> & v,
187 v.erase (v.begin(), v.begin() +
remove);
192 FAISS_THROW_IF_NOT_MSG (!remove_oldest ||
n_slice > 0,
193 "cannot remove slice: there is none");
197 check_compatible_for_merge (index, sub_index);
199 extract_index_ivf (sub_index)->
invlists);
200 FAISS_THROW_IF_NOT_MSG (ils2,
"supports only ArrayInvertedLists");
202 IndexIVF *index_ivf = extract_index_ivf (index);
204 if (remove_oldest && ils2) {
205 for (
int i = 0; i <
nlist; i++) {
206 std::vector<size_t> & sizesi =
sizes[i];
207 size_t amount_to_remove = sizesi[0];
208 index_ivf->
ntotal += ils2->
ids[i].size() - amount_to_remove;
210 shift_and_add (
ils->
ids[i], amount_to_remove, ils2->
ids[i]);
213 for (
int j = 0; j + 1 <
n_slice; j++) {
214 sizesi[j] = sizesi[j + 1] - amount_to_remove;
216 sizesi[n_slice - 1] =
ils->
ids[i].size();
219 for (
int i = 0; i <
nlist; i++) {
220 index_ivf->
ntotal += ils2->
ids[i].size();
221 shift_and_add (
ils->
ids[i], 0, ils2->
ids[i]);
222 shift_and_add (
ils->codes[i], 0, ils2->codes[i]);
226 }
else if (remove_oldest) {
227 for (
int i = 0; i <
nlist; i++) {
228 size_t amount_to_remove =
sizes[i][0];
229 index_ivf->
ntotal -= amount_to_remove;
230 remove_from_begin (
ils->
ids[i], amount_to_remove);
231 remove_from_begin (
ils->codes[i],
233 for (
int j = 0; j + 1 <
n_slice; j++) {
234 sizes[i][j] =
sizes[i][j + 1] - amount_to_remove;
236 sizes[i].pop_back ();
240 FAISS_THROW_MSG (
"nothing to do???");
251 get_invlist_range (
const Index *index,
long i0,
long i1)
253 const IndexIVF *ivf = extract_index_ivf (index);
255 FAISS_THROW_IF_NOT (0 <= i0 && i0 <= i1 && i1 <= ivf->nlist);
261 for (
long i = i0; i < i1; i++) {
262 il->add_entries(i - i0, src->
list_size(i),
271 void set_invlist_range (Index *index,
long i0,
long i1,
272 ArrayInvertedLists * src)
274 IndexIVF *ivf = extract_index_ivf (index);
276 FAISS_THROW_IF_NOT (0 <= i0 && i0 <= i1 && i1 <= ivf->nlist);
278 ArrayInvertedLists *dst =
dynamic_cast<ArrayInvertedLists *
>(ivf->invlists);
279 FAISS_THROW_IF_NOT_MSG (dst,
"only ArrayInvertedLists supported");
280 FAISS_THROW_IF_NOT (src->nlist == i1 - i0 &&
281 dst->code_size == src->code_size);
283 size_t ntotal = index->ntotal;
284 for (
long i = i0 ; i < i1; i++) {
285 ntotal -= dst->list_size (i);
286 ntotal += src->list_size (i - i0);
287 std::swap (src->codes[i - i0], dst->codes[i]);
288 std::swap (src->ids[i - i0], dst->ids[i]);
290 ivf->ntotal = index->ntotal = ntotal;
294 void search_with_parameters (
const Index *index,
295 idx_t n,
const float *x, idx_t k,
296 float *distances, idx_t *labels,
297 IVFSearchParameters *params)
299 FAISS_THROW_IF_NOT (params);
300 const float *prev_x = x;
301 ScopeDeleter<float> del;
303 if (
auto ip = dynamic_cast<const IndexPreTransform *> (index)) {
304 x = ip->apply_chain (n, x);
311 std::vector<idx_t> Iq(params->nprobe * n);
312 std::vector<float> Dq(params->nprobe * n);
314 const IndexIVF *index_ivf =
dynamic_cast<const IndexIVF *
>(index);
315 FAISS_THROW_IF_NOT (index_ivf);
317 index_ivf->quantizer->search(n, x, params->nprobe,
318 Dq.data(), Iq.data());
320 index_ivf->search_preassigned(n, x, k, Iq.data(), Dq.data(),
virtual void search_preassigned(idx_t n, const float *x, idx_t k, const idx_t *assign, const float *centroid_dis, float *distances, idx_t *labels, bool store_pairs, const IVFSearchParameters *params=nullptr) const
simple (default) implementation as an array of inverted lists
void check_compatible_for_merge(const IndexIVF &other) const
size_t nprobe
number of probes at query time
void assign(idx_t n, const float *x, idx_t *labels, idx_t k=1)
virtual size_t list_size(size_t list_no) const =0
get the size of a list
size_t nlist
same as index->nlist
virtual idx_t get_single_id(size_t list_no, size_t offset) const
size_t code_size
code size per vector in bytes
ArrayInvertedLists * ils
InvertedLists of index.
int n_slice
number of slices currently in index
std::vector< std::vector< size_t > > sizes
cumulative list sizes at each slice
SlidingIndexWindow(Index *index)
index should be initially empty and trained
idx_t ntotal
total nb of indexed vectors
virtual void search(idx_t n, const float *x, idx_t k, float *distances, idx_t *labels) const =0
void step(const Index *sub_index, bool remove_oldest)
size_t nlist
number of possible key values
InvertedLists * invlists
Acess to the actual data.
std::vector< std::vector< idx_t > > ids
Inverted lists for indexes.
Index * quantizer
quantizer that maps vectors to inverted lists