usearch 0.4.0 → 0.8.1
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.
- package/.clang-tidy +60 -0
- package/.github/workflows/release.yml +42 -16
- package/.github/workflows/update_version.sh +1 -0
- package/.vscode/launch.json +22 -0
- package/.vscode/settings.json +5 -0
- package/.vscode/tasks.json +4 -4
- package/CITATION.cff +11 -0
- package/CMakeLists.txt +108 -95
- package/Cargo.toml +1 -1
- package/Dockerfile +14 -0
- package/README.md +8 -7
- package/VERSION +1 -1
- package/binding.gyp +2 -2
- package/build.rs +2 -2
- package/cmake/config.cmake.in +15 -0
- package/cmake/pkg-config.pc.in +4 -0
- package/cmake/usearchConfigVersion.cmake.in +20 -0
- package/conanfile.py +1 -1
- package/docs/benchmarks.md +11 -2
- package/docs/{Compilation.md → compilation.md} +54 -27
- package/include/usearch/usearch.hpp +664 -390
- package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +17 -16
- package/javascript/lib.cpp +13 -13
- package/javascript/test.js +1 -1
- package/objc/USearchObjective.mm +46 -29
- package/objc/include/USearchObjective.h +18 -26
- package/package.json +1 -1
- package/pyproject.toml +3 -2
- package/python/lib.cpp +179 -120
- package/python/scripts/bench.py +188 -0
- package/python/scripts/bench_params.py +113 -0
- package/python/{test.py → scripts/test.py} +32 -13
- package/python/usearch/client.py +100 -14
- package/python/usearch/server.py +104 -23
- package/rust/lib.cpp +15 -14
- package/rust/lib.hpp +5 -5
- package/rust/lib.rs +3 -3
- package/setup.py +7 -0
- package/src/CMakeLists.txt +107 -0
- package/src/bench.cpp +45 -15
- package/src/{advanced.hpp → punned.hpp} +227 -199
- package/src/test.cpp +62 -0
- package/swift/Test.swift +1 -1
- package/wolfram/lib.cpp +14 -14
- package/python/bench.py +0 -146
package/rust/lib.cpp
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
using namespace unum::usearch;
|
|
5
5
|
using namespace unum;
|
|
6
6
|
|
|
7
|
-
using
|
|
7
|
+
using punned_t = typename Index::punned_t;
|
|
8
8
|
|
|
9
|
-
Index::Index(std::shared_ptr<
|
|
9
|
+
Index::Index(std::shared_ptr<punned_t> index) : index_(index) {}
|
|
10
10
|
|
|
11
11
|
void Index::add_in_thread(uint32_t label, rust::Slice<float const> vector, size_t thread) const {
|
|
12
12
|
add_config_t config;
|
|
@@ -22,7 +22,8 @@ Matches Index::search_in_thread(rust::Slice<float const> vector, size_t count, s
|
|
|
22
22
|
results.labels.push_back(0), results.distances.push_back(0);
|
|
23
23
|
search_config_t config;
|
|
24
24
|
config.thread = thread;
|
|
25
|
-
results.count =
|
|
25
|
+
results.count =
|
|
26
|
+
index_->search(vector.data(), count, config).dump_to(results.labels.data(), results.distances.data());
|
|
26
27
|
results.labels.truncate(results.count);
|
|
27
28
|
results.distances.truncate(results.count);
|
|
28
29
|
return results;
|
|
@@ -38,7 +39,7 @@ Matches Index::search(rust::Slice<float const> vector, size_t count) const {
|
|
|
38
39
|
results.distances.reserve(count);
|
|
39
40
|
for (size_t i = 0; i != count; ++i)
|
|
40
41
|
results.labels.push_back(0), results.distances.push_back(0);
|
|
41
|
-
results.count = index_->search(vector.data(), count
|
|
42
|
+
results.count = index_->search(vector.data(), count).dump_to(results.labels.data(), results.distances.data());
|
|
42
43
|
results.labels.truncate(results.count);
|
|
43
44
|
results.distances.truncate(results.count);
|
|
44
45
|
return results;
|
|
@@ -57,31 +58,31 @@ void Index::view(rust::Str path) const { index_->view(std::string(path).c_str())
|
|
|
57
58
|
|
|
58
59
|
accuracy_t accuracy(rust::Str quant) { return accuracy_from_name(quant.data(), quant.size()); }
|
|
59
60
|
|
|
60
|
-
std::unique_ptr<Index> wrap(
|
|
61
|
-
std::shared_ptr<
|
|
61
|
+
std::unique_ptr<Index> wrap(punned_t&& index) {
|
|
62
|
+
std::shared_ptr<punned_t> native = std::make_shared<punned_t>(std::move(index));
|
|
62
63
|
return std::unique_ptr<Index>(new Index(native));
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
config_t config(size_t connectivity, size_t exp_add, size_t exp_search) {
|
|
66
67
|
config_t result;
|
|
67
|
-
result.connectivity = connectivity ? connectivity :
|
|
68
|
-
result.expansion_add = exp_add ? exp_add :
|
|
69
|
-
result.expansion_search = exp_search ? exp_search :
|
|
68
|
+
result.connectivity = connectivity ? connectivity : default_connectivity();
|
|
69
|
+
result.expansion_add = exp_add ? exp_add : default_expansion_add();
|
|
70
|
+
result.expansion_search = exp_search ? exp_search : default_expansion_search();
|
|
70
71
|
return result;
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
std::unique_ptr<Index> new_ip(size_t dims, rust::Str quant, size_t connectivity, size_t exp_add, size_t exp_search) {
|
|
74
|
-
return wrap(
|
|
75
|
+
return wrap(punned_t::ip(dims, accuracy(quant), config(connectivity, exp_add, exp_search)));
|
|
75
76
|
}
|
|
76
77
|
|
|
77
|
-
std::unique_ptr<Index>
|
|
78
|
-
return wrap(
|
|
78
|
+
std::unique_ptr<Index> new_l2sq(size_t dims, rust::Str quant, size_t connectivity, size_t exp_add, size_t exp_search) {
|
|
79
|
+
return wrap(punned_t::l2sq(dims, accuracy(quant), config(connectivity, exp_add, exp_search)));
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
std::unique_ptr<Index> new_cos(size_t dims, rust::Str quant, size_t connectivity, size_t exp_add, size_t exp_search) {
|
|
82
|
-
return wrap(
|
|
83
|
+
return wrap(punned_t::cos(dims, accuracy(quant), config(connectivity, exp_add, exp_search)));
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
std::unique_ptr<Index> new_haversine(rust::Str quant, size_t connectivity, size_t exp_add, size_t exp_search) {
|
|
86
|
-
return wrap(
|
|
87
|
+
return wrap(punned_t::haversine(accuracy(quant), config(connectivity, exp_add, exp_search)));
|
|
87
88
|
}
|
package/rust/lib.hpp
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
#include <memory> // `std::shared_ptr`
|
|
5
5
|
|
|
6
|
-
#include "
|
|
6
|
+
#include "punned.hpp"
|
|
7
7
|
|
|
8
8
|
struct Matches;
|
|
9
9
|
|
|
@@ -15,9 +15,9 @@ class Index {
|
|
|
15
15
|
public:
|
|
16
16
|
using label_t = std::uint32_t;
|
|
17
17
|
using distance_t = unum::usearch::punned_distance_t;
|
|
18
|
-
using
|
|
18
|
+
using punned_t = unum::usearch::punned_gt<label_t>;
|
|
19
19
|
|
|
20
|
-
Index(std::shared_ptr<
|
|
20
|
+
Index(std::shared_ptr<punned_t> index);
|
|
21
21
|
|
|
22
22
|
void reserve(size_t) const;
|
|
23
23
|
|
|
@@ -37,10 +37,10 @@ class Index {
|
|
|
37
37
|
void view(rust::Str path) const;
|
|
38
38
|
|
|
39
39
|
private:
|
|
40
|
-
std::shared_ptr<
|
|
40
|
+
std::shared_ptr<punned_t> index_;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
std::unique_ptr<Index> new_ip(size_t dims, rust::Str quant, size_t connectivity, size_t exp_add, size_t exp_search);
|
|
44
|
-
std::unique_ptr<Index>
|
|
44
|
+
std::unique_ptr<Index> new_l2sq(size_t dims, rust::Str quant, size_t connectivity, size_t exp_add, size_t exp_search);
|
|
45
45
|
std::unique_ptr<Index> new_cos(size_t dims, rust::Str quant, size_t connectivity, size_t exp_add, size_t exp_search);
|
|
46
46
|
std::unique_ptr<Index> new_haversine(rust::Str quant, size_t connectivity, size_t exp_add, size_t exp_search);
|
package/rust/lib.rs
CHANGED
|
@@ -15,7 +15,7 @@ pub mod ffi {
|
|
|
15
15
|
type Index;
|
|
16
16
|
|
|
17
17
|
fn new_ip(dimensions: usize, quantization: &str, connectivity: usize, expansion_add: usize, expansion_search: usize) -> Result<UniquePtr<Index>>;
|
|
18
|
-
fn
|
|
18
|
+
fn new_l2sq(dimensions: usize, quantization: &str, connectivity: usize, expansion_add: usize, expansion_search: usize) -> Result<UniquePtr<Index>>;
|
|
19
19
|
fn new_cos(dimensions: usize, quantization: &str, connectivity: usize, expansion_add: usize, expansion_search: usize) -> Result<UniquePtr<Index>>;
|
|
20
20
|
fn new_haversine(quantization: &str, connectivity: usize, expansion_add: usize, expansion_search: usize) -> Result<UniquePtr<Index>>;
|
|
21
21
|
|
|
@@ -42,7 +42,7 @@ pub mod ffi {
|
|
|
42
42
|
#[cfg(test)]
|
|
43
43
|
mod tests {
|
|
44
44
|
use crate::ffi::new_ip;
|
|
45
|
-
use crate::ffi::
|
|
45
|
+
use crate::ffi::new_l2sq;
|
|
46
46
|
use crate::ffi::new_cos;
|
|
47
47
|
use crate::ffi::new_haversine;
|
|
48
48
|
|
|
@@ -76,7 +76,7 @@ mod tests {
|
|
|
76
76
|
|
|
77
77
|
// Make sure every function is called at least once
|
|
78
78
|
assert!(new_ip(5, &quant, 0, 0, 0).is_ok());
|
|
79
|
-
assert!(
|
|
79
|
+
assert!(new_l2sq(5, &quant, 0, 0, 0).is_ok());
|
|
80
80
|
assert!(new_cos(5, &quant, 0, 0, 0).is_ok());
|
|
81
81
|
assert!(new_haversine(&quant, 0, 0, 0).is_ok());
|
|
82
82
|
}
|
package/setup.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import sys
|
|
3
|
+
import platform
|
|
3
4
|
from setuptools import setup
|
|
4
5
|
from pybind11.setup_helpers import Pybind11Extension
|
|
5
6
|
|
|
@@ -10,15 +11,21 @@ link_args = []
|
|
|
10
11
|
if sys.platform == 'linux':
|
|
11
12
|
compile_args.append('-fopenmp')
|
|
12
13
|
link_args.append('-lgomp')
|
|
14
|
+
compile_args.append('-Wno-unknown-pragmas')
|
|
13
15
|
|
|
14
16
|
if sys.platform == 'darwin':
|
|
15
17
|
# MacOS 10.15 orhigher is needed for `aligned_alloc` support.
|
|
16
18
|
# https://github.com/unum-cloud/usearch/actions/runs/4975434891/jobs/8902603392
|
|
17
19
|
compile_args.append('-mmacosx-version-min=10.15')
|
|
20
|
+
compile_args.append('-Wno-unknown-pragmas')
|
|
18
21
|
|
|
19
22
|
if sys.platform == 'win32':
|
|
20
23
|
compile_args = ['/std:c++14', '/O2']
|
|
21
24
|
|
|
25
|
+
if platform.machine() == 'arm64':
|
|
26
|
+
compile_args.append('-march=armv8.2-a+simd+fp16+fp16fml+dotprod')
|
|
27
|
+
elif platform.machine() in ('i386', 'AMD64', 'x86_64'):
|
|
28
|
+
compile_args.append('-march=haswell')
|
|
22
29
|
|
|
23
30
|
ext_modules = [
|
|
24
31
|
Pybind11Extension(
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.1)
|
|
2
|
+
|
|
3
|
+
option(USEARCH_USE_OPENMP "Use OpenMP for a thread pool" OFF)
|
|
4
|
+
option(USEARCH_USE_SIMSIMD "Use SimSIMD hardware-accelerated metrics" OFF)
|
|
5
|
+
option(USEARCH_USE_JEMALLOC "Use JeMalloc for faster memory allocations" OFF)
|
|
6
|
+
|
|
7
|
+
# Make "Release" by default
|
|
8
|
+
if(NOT CMAKE_BUILD_TYPE)
|
|
9
|
+
set(CMAKE_BUILD_TYPE Release)
|
|
10
|
+
endif()
|
|
11
|
+
|
|
12
|
+
# List of all possible compiler IDs:
|
|
13
|
+
# https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER_ID.html
|
|
14
|
+
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|
15
|
+
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address")
|
|
16
|
+
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -Wextra -Wno-conversion -Wno-unknown-pragmas")
|
|
17
|
+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
|
|
18
|
+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fmax-errors=1")
|
|
19
|
+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp")
|
|
20
|
+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
|
|
21
|
+
|
|
22
|
+
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
|
23
|
+
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wfatal-errors")
|
|
24
|
+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp")
|
|
25
|
+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
|
|
26
|
+
|
|
27
|
+
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "NVIDIA" OR CMAKE_CXX_COMPILER_ID STREQUAL "NVHPC")
|
|
28
|
+
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} --expt-relaxed-constexpr --extended-lambda")
|
|
29
|
+
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode arch=compute_86,code=sm_86")
|
|
30
|
+
set_property(SOURCE bench.cpp PROPERTY LANGUAGE CUDA)
|
|
31
|
+
set_target_properties(bench PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
|
32
|
+
set_target_properties(bench PROPERTIES CUDA_ARCHITECTURES "86")
|
|
33
|
+
|
|
34
|
+
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
|
|
35
|
+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w")
|
|
36
|
+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ferror-limit=1")
|
|
37
|
+
|
|
38
|
+
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
|
39
|
+
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /DEBUG")
|
|
40
|
+
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /O2")
|
|
41
|
+
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /O2 /DEBUG")
|
|
42
|
+
else()
|
|
43
|
+
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0")
|
|
44
|
+
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
|
45
|
+
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O3 -pg -g")
|
|
46
|
+
endif()
|
|
47
|
+
|
|
48
|
+
if(APPLE)
|
|
49
|
+
set(CMAKE_THREAD_LIBS_INIT "-lpthread")
|
|
50
|
+
set(CMAKE_HAVE_THREADS_LIBRARY 1)
|
|
51
|
+
set(CMAKE_USE_WIN32_THREADS_INIT 0)
|
|
52
|
+
set(CMAKE_USE_PTHREADS_INIT 1)
|
|
53
|
+
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
|
54
|
+
endif()
|
|
55
|
+
|
|
56
|
+
find_package(Threads REQUIRED)
|
|
57
|
+
|
|
58
|
+
if(${USEARCH_USE_OPENMP})
|
|
59
|
+
find_package(OpenMP REQUIRED)
|
|
60
|
+
include_directories(${OPENMP_INCLUDE_DIRS})
|
|
61
|
+
endif()
|
|
62
|
+
|
|
63
|
+
if(${USEARCH_USE_JEMALLOC})
|
|
64
|
+
include(jemalloc)
|
|
65
|
+
endif()
|
|
66
|
+
|
|
67
|
+
include(clipp)
|
|
68
|
+
|
|
69
|
+
set(USEARCH_PUNNED_INCLUDE_DIRS
|
|
70
|
+
"${CMAKE_CURRENT_SOURCE_DIR}/../include"
|
|
71
|
+
"${CMAKE_CURRENT_SOURCE_DIR}/../fp16/include"
|
|
72
|
+
"${CMAKE_CURRENT_SOURCE_DIR}/../simsimd/include"
|
|
73
|
+
"${CMAKE_CURRENT_SOURCE_DIR}/"
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
if(${USEARCH_BUILD_TEST})
|
|
77
|
+
add_executable(test test.cpp)
|
|
78
|
+
target_link_libraries(test PRIVATE Threads::Threads)
|
|
79
|
+
target_include_directories(test PRIVATE ${USEARCH_PUNNED_INCLUDE_DIRS})
|
|
80
|
+
set_target_properties(test PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
|
81
|
+
|
|
82
|
+
if(${CMAKE_VERSION} VERSION_EQUAL 3.13 OR ${CMAKE_VERSION} VERSION_GREATER 3.13)
|
|
83
|
+
include(CTest)
|
|
84
|
+
enable_testing()
|
|
85
|
+
add_test(NAME test COMMAND test)
|
|
86
|
+
endif()
|
|
87
|
+
endif()
|
|
88
|
+
|
|
89
|
+
if(${USEARCH_BUILD_BENCHMARK})
|
|
90
|
+
add_executable(bench bench.cpp)
|
|
91
|
+
target_link_libraries(bench PRIVATE Threads::Threads)
|
|
92
|
+
target_include_directories(bench PRIVATE ${USEARCH_PUNNED_INCLUDE_DIRS})
|
|
93
|
+
set_target_properties(bench PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
|
94
|
+
|
|
95
|
+
if(${USEARCH_USE_SIMSIMD})
|
|
96
|
+
target_compile_definitions(bench PRIVATE USEARCH_USE_SIMSIMD=1)
|
|
97
|
+
endif()
|
|
98
|
+
|
|
99
|
+
if(${USEARCH_USE_OPENMP})
|
|
100
|
+
target_compile_definitions(bench PRIVATE USEARCH_USE_OPENMP=1)
|
|
101
|
+
target_link_libraries(bench PRIVATE ${OPENMP_LIBRARIES})
|
|
102
|
+
endif()
|
|
103
|
+
|
|
104
|
+
if(${USEARCH_USE_JEMALLOC})
|
|
105
|
+
target_link_libraries(bench PRIVATE ${JEMALLOC_LIBRARIES})
|
|
106
|
+
endif()
|
|
107
|
+
endif()
|
package/src/bench.cpp
CHANGED
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
#include <iostream> // `std::cerr`
|
|
30
30
|
#include <numeric> // `std::iota`
|
|
31
31
|
#include <stdexcept> // `std::invalid_argument`
|
|
32
|
+
#include <string> // `std::to_string`
|
|
32
33
|
#include <thread> // `std::thread::hardware_concurrency()`
|
|
33
34
|
#include <variant> // `std::monostate`
|
|
34
35
|
|
|
@@ -37,7 +38,7 @@
|
|
|
37
38
|
|
|
38
39
|
#include <simsimd/simsimd.h>
|
|
39
40
|
|
|
40
|
-
#include "
|
|
41
|
+
#include "punned.hpp"
|
|
41
42
|
|
|
42
43
|
using namespace unum::usearch;
|
|
43
44
|
using namespace unum;
|
|
@@ -227,7 +228,7 @@ struct running_stats_printer_t {
|
|
|
227
228
|
running_stats_printer_t(std::size_t n, char const* msg) {
|
|
228
229
|
std::printf("%s. %zu items\n", msg, n);
|
|
229
230
|
total = n;
|
|
230
|
-
start_time = std::chrono::high_resolution_clock::now();
|
|
231
|
+
last_printed_time = start_time = std::chrono::high_resolution_clock::now();
|
|
231
232
|
}
|
|
232
233
|
|
|
233
234
|
~running_stats_printer_t() {
|
|
@@ -279,7 +280,8 @@ void index_many(index_at& native, std::size_t n, vector_id_at const* ids, real_a
|
|
|
279
280
|
add_config_t config;
|
|
280
281
|
config.thread = omp_get_thread_num();
|
|
281
282
|
config.store_vector = true;
|
|
282
|
-
|
|
283
|
+
vector_view_t vector{vectors + dims * i, dims};
|
|
284
|
+
native.add(ids[i], vector, config);
|
|
283
285
|
printer.progress++;
|
|
284
286
|
if (omp_get_thread_num() == 0)
|
|
285
287
|
printer.refresh();
|
|
@@ -291,16 +293,35 @@ void search_many( //
|
|
|
291
293
|
index_at& native, std::size_t n, real_at const* vectors, std::size_t dims, std::size_t wanted, vector_id_at* ids,
|
|
292
294
|
real_at* distances) {
|
|
293
295
|
|
|
294
|
-
|
|
296
|
+
std::string name = "Search " + std::to_string(wanted);
|
|
297
|
+
running_stats_printer_t printer{n, name.c_str()};
|
|
295
298
|
|
|
296
299
|
#pragma omp parallel for schedule(static, 32)
|
|
297
300
|
for (std::size_t i = 0; i < n; ++i) {
|
|
298
301
|
search_config_t config;
|
|
299
302
|
config.thread = omp_get_thread_num();
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
303
|
+
vector_view_t vector{vectors + dims * i, dims};
|
|
304
|
+
native.search(vector, wanted, config).dump_to(ids + wanted * i, distances + wanted * i);
|
|
305
|
+
printer.progress++;
|
|
306
|
+
if (omp_get_thread_num() == 0)
|
|
307
|
+
printer.refresh();
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
template <typename index_at, typename vector_id_at, typename real_at>
|
|
312
|
+
void paginate_many( //
|
|
313
|
+
index_at& native, std::size_t n, real_at const* vectors, std::size_t dims, std::size_t wanted,
|
|
314
|
+
vector_id_at const* hints) {
|
|
315
|
+
|
|
316
|
+
std::string name = "Paginate " + std::to_string(wanted);
|
|
317
|
+
running_stats_printer_t printer{n, name.c_str()};
|
|
318
|
+
|
|
319
|
+
#pragma omp parallel for schedule(static, 32)
|
|
320
|
+
for (std::size_t i = 0; i < n; ++i) {
|
|
321
|
+
search_config_t config;
|
|
322
|
+
config.thread = omp_get_thread_num();
|
|
323
|
+
vector_view_t vector{vectors + dims * i, dims};
|
|
324
|
+
native.search_around(hints[i], vector, wanted, config);
|
|
304
325
|
printer.progress++;
|
|
305
326
|
if (omp_get_thread_num() == 0)
|
|
306
327
|
printer.refresh();
|
|
@@ -338,6 +359,15 @@ static void single_shot(dataset_at& dataset, index_at& index, bool construct = t
|
|
|
338
359
|
|
|
339
360
|
std::printf("Recall@1 %.2f %%\n", recall_at_1 * 100.f / dataset.queries_count());
|
|
340
361
|
std::printf("Recall %.2f %%\n", recall_full * 100.f / dataset.queries_count());
|
|
362
|
+
|
|
363
|
+
// Paginate
|
|
364
|
+
std::vector<vector_id_t> hints(dataset.queries_count());
|
|
365
|
+
for (std::size_t i = 0; i != hints.size(); ++i)
|
|
366
|
+
hints[i] = dataset.neighborhood(i)[0];
|
|
367
|
+
paginate_many(index, dataset.queries_count(), dataset.query(0), dataset.dimensions(), 10, hints.data());
|
|
368
|
+
paginate_many(index, dataset.queries_count(), dataset.query(0), dataset.dimensions(), 100, hints.data());
|
|
369
|
+
paginate_many(index, dataset.queries_count(), dataset.query(0), dataset.dimensions(), 1000, hints.data());
|
|
370
|
+
|
|
341
371
|
std::printf("------------\n");
|
|
342
372
|
std::printf("\n");
|
|
343
373
|
}
|
|
@@ -390,9 +420,9 @@ struct args_t {
|
|
|
390
420
|
std::string path_neighbors;
|
|
391
421
|
std::string path_output = "last.usearch";
|
|
392
422
|
|
|
393
|
-
std::size_t connectivity =
|
|
394
|
-
std::size_t expansion_add =
|
|
395
|
-
std::size_t expansion_search =
|
|
423
|
+
std::size_t connectivity = default_connectivity();
|
|
424
|
+
std::size_t expansion_add = default_expansion_add();
|
|
425
|
+
std::size_t expansion_search = default_expansion_search();
|
|
396
426
|
std::size_t threads = std::thread::hardware_concurrency();
|
|
397
427
|
|
|
398
428
|
std::size_t vectors_to_skip = 0;
|
|
@@ -415,7 +445,7 @@ template <typename index_at, typename dataset_at> //
|
|
|
415
445
|
index_at type_punned_index_for_metric(dataset_at& dataset, args_t const& args, config_t config, accuracy_t accuracy) {
|
|
416
446
|
if (args.metric_l2) {
|
|
417
447
|
std::printf("-- Metric: Euclidean\n");
|
|
418
|
-
return index_at::
|
|
448
|
+
return index_at::l2sq(dataset.dimensions(), accuracy, config);
|
|
419
449
|
} else if (args.metric_cos) {
|
|
420
450
|
std::printf("-- Metric: Angular\n");
|
|
421
451
|
return index_at::cos(dataset.dimensions(), accuracy, config);
|
|
@@ -486,7 +516,7 @@ void run_big_or_small(dataset_at& dataset, args_t const& args, config_t config)
|
|
|
486
516
|
run_typed<index_gt<ip_gt<float>, std::size_t, neighbor_id_at>>(dataset, args, config);
|
|
487
517
|
}
|
|
488
518
|
} else
|
|
489
|
-
run_type_punned<
|
|
519
|
+
run_type_punned<punned_gt<std::size_t, neighbor_id_at>>(dataset, args, config);
|
|
490
520
|
}
|
|
491
521
|
|
|
492
522
|
void report_alternative_setups() {
|
|
@@ -563,7 +593,7 @@ int main(int argc, char** argv) {
|
|
|
563
593
|
option("--f8quant").set(args.quantize_f8).doc("Enable `f8_t` quantization")),
|
|
564
594
|
( //
|
|
565
595
|
option("--ip").set(args.metric_ip).doc("Choose Inner Product metric") |
|
|
566
|
-
option("--
|
|
596
|
+
option("--l2sq").set(args.metric_l2).doc("Choose L2 Euclidean metric") |
|
|
567
597
|
option("--cos").set(args.metric_cos).doc("Choose Angular metric") |
|
|
568
598
|
option("--haversine").set(args.metric_haversine).doc("Choose Haversine metric")),
|
|
569
599
|
option("-h", "--help").set(args.help).doc("Print this help information on this tool and exit"));
|
|
@@ -577,7 +607,7 @@ int main(int argc, char** argv) {
|
|
|
577
607
|
exit(0);
|
|
578
608
|
}
|
|
579
609
|
|
|
580
|
-
// Instead of relying on `multithreaded` from "
|
|
610
|
+
// Instead of relying on `multithreaded` from "punned.hpp" we will use OpenMP
|
|
581
611
|
// to better estimate statistics between tasks batches, without having to recreate
|
|
582
612
|
// the threads.
|
|
583
613
|
omp_set_dynamic(true);
|