diff --git a/.gitignore b/.gitignore index 9f0ebe10..da2cb796 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,12 @@ CMakeCache.txt main *.swp +__pycache__/ +lib/ +numpy.i +build/ +dist/ +ivfhnsw.egg-info/ +venv/ +.eggs/ +.pytest_cache/ diff --git a/CMakeLists.txt b/CMakeLists.txt index e8b895e0..d499458a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required (VERSION 2.8) # ivf-hnsw project project(ivf-hnsw C CXX) -include_directories("${PROJECT_BINARY_DIR}") +message("Build type: ${CMAKE_BUILD_TYPE}") add_subdirectory(faiss) add_subdirectory(hnswlib) @@ -13,14 +13,34 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -# specify header and cpp files -file(GLOB ivf-hnsw_cpu_headers ${CMAKE_CURRENT_SOURCE_DIR}/*.h) -file(GLOB ivf-hnsw_cpu_cpp ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include) -add_library(ivf-hnsw STATIC ${ivf-hnsw_cpu_headers} ${ivf-hnsw_cpu_cpp}) +file(GLOB ivfhnsw_src ${PROJECT_SOURCE_DIR}/src/*.cpp) +file(GLOB ivfhnsw_include ${PROJECT_SOURCE_DIR}/include/*.h) -SET( CMAKE_CXX_FLAGS "-Ofast -lrt -DNDEBUG -std=c++11 -DHAVE_CXX0X -openmp -march=native -fpic -w -fopenmp -ftree-vectorize -ftree-vectorizer-verbose=0" ) -target_link_libraries(ivf-hnsw faiss hnswlib) +SET(CMAKE_CXX_FLAGS "-Ofast -lrt -DNDEBUG -std=c++11 -DHAVE_CXX0X -openmp -march=native -fpic -w -fopenmp -ftree-vectorize -ftree-vectorizer-verbose=0") -# build tests -add_subdirectory(tests) \ No newline at end of file +add_library(ivfhnsw STATIC ${ivfhnsw_src}) +target_link_libraries(ivfhnsw faiss hnswlib) + +FIND_PACKAGE(SWIG) +FIND_PACKAGE(PythonLibs) +if(SWIG_FOUND AND PythonLibs_FOUND) + INCLUDE(${SWIG_USE_FILE}) + INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH}) + + file(DOWNLOAD https://raw.githubusercontent.com/numpy/numpy/master/tools/swig/numpy.i ./numpy.i) + file(DOWNLOAD https://raw.githubusercontent.com/numpy/numpy/master/tools/swig/pyfragments.swg ./pyfragments.swg) + + set(CMAKE_SWIG_OUTDIR ${CMAKE_BINARY_DIR}/lib) + set(SWIG_FEATURES "-Iinclude") + file(GLOB swig_interface interface/wrapper.i) + + SET_SOURCE_FILES_PROPERTIES(${swig_interface} PROPERTIES CPLUSPLUS ON) + + swig_add_module(wrapper python ${swig_interface} ${ivfhnsw_src}) + swig_link_libraries(wrapper faiss hnswlib ${PYTHON_LIBRARIES}) + +endif() + +add_subdirectory(tests) diff --git a/CMakeLists.txt.faiss b/CMakeLists.txt.faiss index 90880f9e..1250323c 100644 --- a/CMakeLists.txt.faiss +++ b/CMakeLists.txt.faiss @@ -35,4 +35,4 @@ file(GLOB faiss_cpu_cpp ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) set(faiss_lib faiss) add_library(${faiss_lib} STATIC ${faiss_cpu_headers} ${faiss_cpu_cpp}) -target_link_libraries(${faiss_lib} ${OpenMP_CXX_FLAGS} ${BLAS_LIB}) \ No newline at end of file +target_link_libraries(${faiss_lib} ${OpenMP_CXX_FLAGS} ${BLAS_LIB}) diff --git a/hnswlib/CMakeLists.txt b/hnswlib/CMakeLists.txt index 59330055..8797a784 100644 --- a/hnswlib/CMakeLists.txt +++ b/hnswlib/CMakeLists.txt @@ -11,8 +11,8 @@ file(GLOB headers ${CMAKE_CURRENT_SOURCE_DIR}/*.h) file(GLOB sources ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) # Build each source file independently -include_directories(../../) # ivf-hnsw root directory +include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src) # ivf-hnsw root directory add_library(hnswlib STATIC ${headers} ${sources}) SET( CMAKE_CXX_FLAGS "-Ofast -lrt -DNDEBUG -std=c++11 -DHAVE_CXX0X -openmp -march=native -fpic -w -fopenmp -ftree-vectorize -ftree-vectorizer-verbose=0" ) -target_link_libraries(hnswlib) \ No newline at end of file +target_link_libraries(hnswlib) diff --git a/IndexIVF_HNSW.h b/include/IndexIVF_HNSW.h similarity index 100% rename from IndexIVF_HNSW.h rename to include/IndexIVF_HNSW.h diff --git a/IndexIVF_HNSW_Grouping.h b/include/IndexIVF_HNSW_Grouping.h similarity index 100% rename from IndexIVF_HNSW_Grouping.h rename to include/IndexIVF_HNSW_Grouping.h diff --git a/include/Parser.h b/include/Parser.h new file mode 100644 index 00000000..fc75f589 --- /dev/null +++ b/include/Parser.h @@ -0,0 +1,67 @@ +#ifndef IVF_HNSW_LIB_PARSER_H +#define IVF_HNSW_LIB_PARSER_H + +//============== +// Parser Class +//============== +struct Parser +{ + const char *cmd; ///< main command - argv[0] + + //================= + // HNSW parameters + //================= + size_t M; ///< Min number of edges per point + size_t efConstruction; ///< Max number of candidate vertices in priority queue to observe during construction + + //================= + // Data parameters + //================= + size_t nb; ///< Number of base vectors + size_t nt; ///< Number of learn vectors + size_t nsubt; ///< Number of learn vectors to train (random subset of the learn set) + size_t nc; ///< Number of centroids for HNSW quantizer + size_t nsubc; ///< Number of subcentroids per group + size_t nq; ///< Number of queries + size_t ngt; ///< Number of groundtruth neighbours per query + size_t d; ///< Vector dimension + + //================= + // PQ parameters + //================= + size_t code_size; ///< Code size per vector in bytes + bool do_opq; ///< Turn on/off OPQ fine encoding + + //=================== + // Search parameters + //=================== + size_t k; ///< Number of the closest vertices to search + size_t nprobe; ///< Number of probes at query time + size_t max_codes; ///< Max number of codes to visit to do a query + size_t efSearch; ///< Max number of candidate vertices in priority queue to observe during searching + bool do_pruning; ///< Turn on/off pruning in the grouping scheme + + //======= + // Paths + //======= + const char *path_base; ///< Path to a base set + const char *path_learn; ///< Path to a learn set + const char *path_q; ///< Path to queries + const char *path_gt; ///< Path to groundtruth + const char *path_centroids; ///< Path to coarse centroids + + const char *path_precomputed_idxs; ///< Path to coarse centroid indices for base points + + const char *path_info; ///< Path to parameters of HNSW graph + const char *path_edges; ///< Path to edges of HNSW graph + + const char *path_pq; ///< Path to the product quantizer for residuals + const char *path_opq_matrix; ///< Path to OPQ rotation matrix for OPQ fine encoding + const char *path_norm_pq; ///< Path to the product quantizer for norms of reconstructed base points + const char *path_index; ///< Path to the constructed index + + Parser(int argc, char **argv); + void usage(); +}; + +#endif //IVF_HNSW_LIB_PARSER_H diff --git a/utils.h b/include/utils.h similarity index 100% rename from utils.h rename to include/utils.h diff --git a/interface/.gitignore b/interface/.gitignore new file mode 100644 index 00000000..57a16aaa --- /dev/null +++ b/interface/.gitignore @@ -0,0 +1,4 @@ +* + +!.gitignore +!wrapper.i diff --git a/interface/wrapper.i b/interface/wrapper.i new file mode 100644 index 00000000..534dcbe5 --- /dev/null +++ b/interface/wrapper.i @@ -0,0 +1,120 @@ +%module wrapper +%{ +#define SWIG_FILE_WITH_INIT +#include "IndexIVF_HNSW.h" +#include "IndexIVF_HNSW_Grouping.h" +%} + +%include "numpy.i" + +%init %{ +import_array(); +%} + +%apply (float* IN_ARRAY1, int DIM1) {(const float *x, size_t d)}; +%apply (float* IN_ARRAY2, int DIM1, int DIM2) {(const float *x, size_t n, size_t d)}; +%apply (unsigned int* ARGOUT_ARRAY1, int DIM1) {(ivfhnsw::IndexIVF_HNSW::idx_t *labels, size_t k)}; +%apply (unsigned int* IN_ARRAY1, int DIM1) {(const ivfhnsw::IndexIVF_HNSW::idx_t *xids, size_t n1)}; +%apply (unsigned int* IN_ARRAY1, int DIM1) {(const ivfhnsw::IndexIVF_HNSW::idx_t *precomputed_idx, size_t n2)}; +%apply (long* ARGOUT_ARRAY1, int DIM1) {(long *labels, size_t k)}; +%apply (float* ARGOUT_ARRAY1, int DIM1) {(float* distances, size_t k_)}; + + +/* +Wrapper for IndexIVF_HNSW::assign +*/ +%rename (assign) assign_numpy; +%exception assign_numpy { + $action + if (PyErr_Occurred()) SWIG_fail; +} +%extend ivfhnsw::IndexIVF_HNSW { +void assign_numpy(const float *x, size_t n, size_t d, idx_t *labels, size_t k) { + if (d != $self->d) { + PyErr_Format(PyExc_ValueError, + "Query vectors must be of length d=%d, got %d", + $self->d, d); + return; + } + return $self->assign(n, x, labels, k); +} +} +%ignore assign; + +/* +Wrapper for IndexIVF_HNSW::train_pq +*/ +%exception train_pq { + $action + if (PyErr_Occurred()) SWIG_fail; +} +%extend ivfhnsw::IndexIVF_HNSW { +void train_pq(const float *x, size_t n, size_t d) { + if (d != $self->d) { + PyErr_Format(PyExc_ValueError, + "Query vectors must be of length d=%d, got %d", + $self->d, d); + return; + } + return $self->train_pq(n, x); +} +} +%ignore train_pq; + + +/* +Wrapper for IndexIVF_HNSW::search +*/ +%exception search { + $action + if (PyErr_Occurred()) SWIG_fail; +} +%extend ivfhnsw::IndexIVF_HNSW { +void search(const float *x, size_t d, float* distances, size_t k_, long *labels, size_t k) { + if (d != $self->d) { + PyErr_Format(PyExc_ValueError, + "Query vectors must be of length d=%d, got %d", + $self->d, d); + return; + } + if (k != k_) { + PyErr_Format(PyExc_ValueError, + "Output sizes must be the same, got %d and %d", + k_, k); + return; + } + $self->search(k, x, distances, labels); +} +} +%ignore search; + + +/* +Wrapper for IndexIVF_HNSW::add_batch +*/ +%exception add_batch { + $action + if (PyErr_Occurred()) SWIG_fail; +} +%extend ivfhnsw::IndexIVF_HNSW { +void add_batch(const float *x, size_t n, size_t d, const idx_t* xids, size_t n1, const idx_t *precomputed_idx, size_t n2) { + if (d != $self->d) { + PyErr_Format(PyExc_ValueError, + "Query vectors must be of length d=%d, got %d", + $self->d, d); + return; + } + if (!(n == n1 && n == n2)) { + PyErr_Format(PyExc_ValueError, + "Arrays must have the same first dimention size, got %d, %d, %d", + n, n1, n2); + return; + } + $self->add_batch(n, x, xids, precomputed_idx); +} +} +%ignore add_batch; + +%include "IndexIVF_HNSW.h" +%include "IndexIVF_HNSW_Grouping.h" + diff --git a/python-src/ivfhnsw/.gitignore b/python-src/ivfhnsw/.gitignore new file mode 100644 index 00000000..5a59a147 --- /dev/null +++ b/python-src/ivfhnsw/.gitignore @@ -0,0 +1 @@ +wrapper.py diff --git a/python-src/ivfhnsw/__init__.py b/python-src/ivfhnsw/__init__.py new file mode 100644 index 00000000..99d06cb4 --- /dev/null +++ b/python-src/ivfhnsw/__init__.py @@ -0,0 +1,7 @@ +from .index import Index +from .index_grouping import IndexGrouping + +__all__ = ( + 'Index', + 'IndexGrouping', +) diff --git a/python-src/ivfhnsw/index.py b/python-src/ivfhnsw/index.py new file mode 100644 index 00000000..0e3067e1 --- /dev/null +++ b/python-src/ivfhnsw/index.py @@ -0,0 +1,12 @@ +from .wrapper import IndexIVF_HNSW + +class Index(IndexIVF_HNSW): + def search(self, x, k): + """ + Query n vectors of dimension d to the index. + + Return at most k vectors. If there are not enough results for the query, + the result array is padded with -1s. + """ + return super().search(x, k, k) + diff --git a/python-src/ivfhnsw/index_grouping.py b/python-src/ivfhnsw/index_grouping.py new file mode 100644 index 00000000..90d9ec65 --- /dev/null +++ b/python-src/ivfhnsw/index_grouping.py @@ -0,0 +1,6 @@ +from .wrapper import IndexIVF_HNSW_Grouping +from .index import Index + + +class IndexGrouping(IndexIVF_HNSW_Grouping, Index): + pass diff --git a/python-tests/test_wrapper.py b/python-tests/test_wrapper.py new file mode 100644 index 00000000..c77d1852 --- /dev/null +++ b/python-tests/test_wrapper.py @@ -0,0 +1,18 @@ +def test_import_ivfhnsw(): + import ivfhnsw + + +def test_lowlevel_constructor_and_destructor_wrappers(): + from ivfhnsw import _wrapper + i = _wrapper.new_IndexIVF_HNSW(4,4,4,4) + _wrapper.delete_IndexIVF_HNSW(i) + + +def test_pipeline(): + from ivfhnsw import Index + index = Index(4,4,4,4) + index.build_quantizer('', '', '') + index.assign([[5,5,5,5]], 2) + distances, labels = index.search([1,2,3,4], 3) + assert distances.shape[0] == 3 + assert labels.shape[0] == 3 diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 00000000..5ec4ad2d --- /dev/null +++ b/setup.cfg @@ -0,0 +1,5 @@ +[aliases] +test=pytest + +[tool:pytest] +testpaths=python-tests diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..6e65ed6c --- /dev/null +++ b/setup.py @@ -0,0 +1,104 @@ +import contextlib +from pprint import pprint +from urllib.request import urlretrieve +import sys +import platform +import subprocess +import os + +from setuptools import setup, Extension, find_packages +from setuptools.command.build_ext import build_ext +from setuptools.command.install_scripts import install_scripts +from distutils.version import LooseVersion + + +project_dir = os.path.dirname(os.path.abspath(__file__)) +python_src = os.path.join(os.curdir, 'python-src') +build_type = os.environ.get('CMAKE_BUILD_TYPE', 'release') + +class custom_install_scripts(install_scripts): + def run(self): + print(self.build_dir) + super().run() + + +class custom_build_ext(build_ext): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._swig_outdir = None + + def run(self): + # Store self.inplace flag because it gets overriden somehow + # by `python setup.py test` pipeline + self._real_inplace = self.inplace + print('Inplace:', self.inplace) + super().run() + self.run_command('build_py') + + @contextlib.contextmanager + def set_inplace(self, inplace): + saved_inplace, self.inplace = self.inplace, inplace + yield + self.inplace = saved_inplace + + def build_extension(self, ext): + interface_temp = os.path.join(self.build_temp, 'interface') + os.makedirs(interface_temp, exist_ok=True) + + # Download numpy.i dependency to be used by swig + urlretrieve('https://raw.githubusercontent.com/numpy/numpy/master/tools/swig/numpy.i', + os.path.join(interface_temp, 'numpy.i'),) + + # Build only ivfhnsw static library + build_args = ['--target', 'ivfhnsw'] + cmake_args = ['-DCMAKE_BUILD_TYPE={}'.format(build_type.upper())] + env = os.environ.copy() + subprocess.check_call(['cmake', project_dir] + cmake_args, cwd=self.build_temp, env=env) + subprocess.check_call(['cmake', '--build', os.curdir] + build_args, cwd=self.build_temp) + + # Add path to the compiled static libraries + ext.library_dirs.append(os.path.join(self.build_temp, 'lib')) + # Add path to the temporary swig interface files directory + ext.swig_opts.append('-I' + os.path.join(self.build_temp, 'interface')) + + with self.set_inplace(self._real_inplace): + _swig_outdir = os.path.dirname(self.get_ext_fullpath(ext.name)) + os.makedirs(_swig_outdir, exist_ok=True) + ext.swig_opts.extend(['-outdir', _swig_outdir]) + print('SWIG outdir:', _swig_outdir) + + import numpy + ext.include_dirs.append(numpy.get_include()) + return super().build_extension(ext) + + +names = ['wrapper'] +ext = [Extension(name='.'.join(['ivfhnsw', '_' + name]), + sources=[os.path.join('interface', '.'.join([name, 'i']))], + swig_opts=['-Iinclude', '-c++'], + include_dirs=['include', os.curdir], + libraries=['ivfhnsw', 'hnswlib', 'faiss', 'gomp', 'lapack',], + extra_compile_args=['-std=c++11', '-static'],) + for name in names] + + +setup( + name='ivfhnsw', + version='0.1', + ext_modules=ext, + package_dir={'': python_src}, + packages=find_packages(python_src), + setup_requires=[ + 'pytest-runner', + 'numpy', + ], + install_requires=[ + 'numpy', + ], + tests_require=['pytest>2.8'], + include_package_data=True, + cmdclass={ + 'build_ext': custom_build_ext, + 'install_scripts': custom_install_scripts, + } +) diff --git a/IndexIVF_HNSW.cpp b/src/IndexIVF_HNSW.cpp similarity index 100% rename from IndexIVF_HNSW.cpp rename to src/IndexIVF_HNSW.cpp diff --git a/IndexIVF_HNSW_Grouping.cpp b/src/IndexIVF_HNSW_Grouping.cpp similarity index 100% rename from IndexIVF_HNSW_Grouping.cpp rename to src/IndexIVF_HNSW_Grouping.cpp diff --git a/Parser.h b/src/Parser.cpp similarity index 69% rename from Parser.h rename to src/Parser.cpp index 9b85a630..c678168b 100644 --- a/Parser.h +++ b/src/Parser.cpp @@ -1,69 +1,8 @@ -#ifndef IVF_HNSW_LIB_PARSER_H -#define IVF_HNSW_LIB_PARSER_H - #include #include +#include "Parser.h" -//============== -// Parser Class -//============== -struct Parser -{ - const char *cmd; ///< main command - argv[0] - - //================= - // HNSW parameters - //================= - size_t M; ///< Min number of edges per point - size_t efConstruction; ///< Max number of candidate vertices in priority queue to observe during construction - - //================= - // Data parameters - //================= - size_t nb; ///< Number of base vectors - size_t nt; ///< Number of learn vectors - size_t nsubt; ///< Number of learn vectors to train (random subset of the learn set) - size_t nc; ///< Number of centroids for HNSW quantizer - size_t nsubc; ///< Number of subcentroids per group - size_t nq; ///< Number of queries - size_t ngt; ///< Number of groundtruth neighbours per query - size_t d; ///< Vector dimension - - //================= - // PQ parameters - //================= - size_t code_size; ///< Code size per vector in bytes - bool do_opq; ///< Turn on/off OPQ fine encoding - - //=================== - // Search parameters - //=================== - size_t k; ///< Number of the closest vertices to search - size_t nprobe; ///< Number of probes at query time - size_t max_codes; ///< Max number of codes to visit to do a query - size_t efSearch; ///< Max number of candidate vertices in priority queue to observe during searching - bool do_pruning; ///< Turn on/off pruning in the grouping scheme - - //======= - // Paths - //======= - const char *path_base; ///< Path to a base set - const char *path_learn; ///< Path to a learn set - const char *path_q; ///< Path to queries - const char *path_gt; ///< Path to groundtruth - const char *path_centroids; ///< Path to coarse centroids - - const char *path_precomputed_idxs; ///< Path to coarse centroid indices for base points - - const char *path_info; ///< Path to parameters of HNSW graph - const char *path_edges; ///< Path to edges of HNSW graph - - const char *path_pq; ///< Path to the product quantizer for residuals - const char *path_opq_matrix; ///< Path to OPQ rotation matrix for OPQ fine encoding - const char *path_norm_pq; ///< Path to the product quantizer for norms of reconstructed base points - const char *path_index; ///< Path to the constructed index - - Parser(int argc, char **argv) + Parser::Parser(int argc, char **argv) { cmd = argv[0]; if (argc == 1) @@ -132,7 +71,7 @@ struct Parser } } - void usage() + void Parser::usage() { printf ("Usage: %s [options]\n", cmd); printf ("###################\n" @@ -186,6 +125,3 @@ struct Parser ); exit(0); } -}; - -#endif //IVF_HNSW_LIB_PARSER_H diff --git a/utils.cpp b/src/utils.cpp similarity index 100% rename from utils.cpp rename to src/utils.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 28b64d87..ff9e7cee 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -3,14 +3,17 @@ cmake_minimum_required (VERSION 2.8) file(GLOB srcs ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) # Build each source file independently -include_directories(../../) # ivf-hnsw root directory +include_directories(${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include) # ivf-hnsw root directory + +add_custom_target(tests) foreach(source ${srcs}) get_filename_component(name ${source} NAME_WE) # target add_executable(${name} ${source}) - target_link_libraries(${name} ivf-hnsw faiss) + target_link_libraries(${name} ivfhnsw faiss) + add_dependencies(tests ${name}) # Install install(TARGETS ${name} DESTINATION test) diff --git a/tests/test_dummy.cpp b/tests/test_dummy.cpp new file mode 100644 index 00000000..748e719a --- /dev/null +++ b/tests/test_dummy.cpp @@ -0,0 +1,10 @@ +#include +#include "IndexIVF_HNSW.h" + + +int main(int argc, char **argv) { + ivfhnsw::IndexIVF_HNSW* index = new ivfhnsw::IndexIVF_HNSW(4,4,4,4); + delete index; + std::cout << "OK" << std::endl; + return 0; +} diff --git a/tests/test_ivfhnsw_deep1b.cpp b/tests/test_ivfhnsw_deep1b.cpp index 6f4abf6b..1740d82e 100644 --- a/tests/test_ivfhnsw_deep1b.cpp +++ b/tests/test_ivfhnsw_deep1b.cpp @@ -5,8 +5,8 @@ #include #include -#include -#include +#include "IndexIVF_HNSW.h" +#include "Parser.h" using namespace hnswlib; using namespace ivfhnsw; @@ -212,4 +212,4 @@ int main(int argc, char **argv) delete index; return 0; -} \ No newline at end of file +} diff --git a/tests/test_ivfhnsw_grouping_deep1b.cpp b/tests/test_ivfhnsw_grouping_deep1b.cpp index 1b11bd76..94d1bfd0 100644 --- a/tests/test_ivfhnsw_grouping_deep1b.cpp +++ b/tests/test_ivfhnsw_grouping_deep1b.cpp @@ -5,8 +5,8 @@ #include #include -#include -#include +#include "IndexIVF_HNSW_Grouping.h" +#include "Parser.h" using namespace hnswlib; using namespace ivfhnsw; @@ -259,4 +259,4 @@ int main(int argc, char **argv) delete index; return 0; -} \ No newline at end of file +} diff --git a/tests/test_ivfhnsw_grouping_sift1b.cpp b/tests/test_ivfhnsw_grouping_sift1b.cpp index f19cdc11..cb34be85 100644 --- a/tests/test_ivfhnsw_grouping_sift1b.cpp +++ b/tests/test_ivfhnsw_grouping_sift1b.cpp @@ -5,8 +5,8 @@ #include #include -#include -#include +#include "IndexIVF_HNSW_Grouping.h" +#include "Parser.h" using namespace hnswlib; using namespace ivfhnsw; @@ -257,4 +257,4 @@ int main(int argc, char **argv) { delete index; return 0; -} \ No newline at end of file +} diff --git a/tests/test_ivfhnsw_sift1b.cpp b/tests/test_ivfhnsw_sift1b.cpp index 26449fd2..0d70b112 100644 --- a/tests/test_ivfhnsw_sift1b.cpp +++ b/tests/test_ivfhnsw_sift1b.cpp @@ -5,8 +5,8 @@ #include #include -#include -#include +#include "IndexIVF_HNSW.h" +#include "Parser.h" using namespace hnswlib; using namespace ivfhnsw; @@ -215,4 +215,4 @@ int main(int argc, char **argv) delete index; return 0; -} \ No newline at end of file +}