/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { // parameters to use for the test int d = 64; size_t nb = 1000; size_t nq = 100; size_t nt = 500; int k = 10; int nlist = 40; using namespace faiss; typedef faiss::Index::idx_t idx_t; std::vector get_data (size_t nb, int seed) { std::vector x (nb * d); float_randn (x.data(), nb * d, seed); return x; } void test_index_type(const char *factory_string) { // transfer inverted lists in nslice slices int nslice = 3; /**************************************************************** * trained reference index ****************************************************************/ std::unique_ptr trained (index_factory (d, factory_string)); { auto xt = get_data (nt, 123); trained->train (nt, xt.data()); } // sample nq query vectors to check if results are the same auto xq = get_data (nq, 818); /**************************************************************** * source index ***************************************************************/ std::unique_ptr src_index (clone_index (trained.get())); { // add some data to source index auto xb = get_data (nb, 245); src_index->add (nb, xb.data()); } ParameterSpace().set_index_parameter (src_index.get(), "nprobe", 4); // remember reference search result on source index std::vector Iref (nq * k); std::vector Dref (nq * k); src_index->search (nq, xq.data(), k, Dref.data(), Iref.data()); /**************************************************************** * destination index -- should be replaced by source index ***************************************************************/ std::unique_ptr dst_index (clone_index (trained.get())); { // initial state: filled in with some garbage int nb2 = nb + 10; auto xb = get_data (nb2, 366); dst_index->add (nb2, xb.data()); } std::vector Inew (nq * k); std::vector Dnew (nq * k); ParameterSpace().set_index_parameter (dst_index.get(), "nprobe", 4); // transfer from source to destination in nslice slices for (int sl = 0; sl < nslice; sl++) { // so far, the indexes are different dst_index->search (nq, xq.data(), k, Dnew.data(), Inew.data()); EXPECT_TRUE (Iref != Inew); EXPECT_TRUE (Dref != Dnew); // range of inverted list indices to transfer long i0 = sl * nlist / nslice; long i1 = (sl + 1) * nlist / nslice; std::vector data_to_transfer; { std::unique_ptr il (ivflib::get_invlist_range (src_index.get(), i0, i1)); // serialize inverted lists VectorIOWriter wr; write_InvertedLists (il.get(), &wr); data_to_transfer.swap (wr.data); } // transfer data here from source machine to dest machine { VectorIOReader reader; reader.data.swap (data_to_transfer); // deserialize inverted lists std::unique_ptr il (dynamic_cast (read_InvertedLists (&reader))); // swap inverted lists. Block searches here! { ivflib::set_invlist_range (dst_index.get(), i0, i1, il.get()); } } } EXPECT_EQ (dst_index->ntotal, src_index->ntotal); // now, the indexes are the same dst_index->search (nq, xq.data(), k, Dnew.data(), Inew.data()); EXPECT_TRUE (Iref == Inew); EXPECT_TRUE (Dref == Dnew); } } // namespace TEST(TRANS, IVFFlat) { test_index_type ("IVF40,Flat"); } TEST(TRANS, IVFFlatPreproc) { test_index_type ("PCAR32,IVF40,Flat"); }