usearch 2.20.0 → 2.20.2
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/README.md
CHANGED
package/cpp/bench.cpp
CHANGED
|
@@ -76,7 +76,7 @@ struct alignas(32) persisted_matrix_gt {
|
|
|
76
76
|
|
|
77
77
|
persisted_matrix_gt(char const* path) noexcept(false) {
|
|
78
78
|
if (!path || !std::strlen(path))
|
|
79
|
-
|
|
79
|
+
return; // Empty path results in default-constructed matrix
|
|
80
80
|
#if defined(USEARCH_DEFINED_WINDOWS)
|
|
81
81
|
|
|
82
82
|
HANDLE file_handle =
|
|
@@ -147,13 +147,14 @@ struct persisted_dataset_gt {
|
|
|
147
147
|
persisted_matrix_gt<scalar_t> vectors_;
|
|
148
148
|
persisted_matrix_gt<scalar_t> queries_;
|
|
149
149
|
persisted_matrix_gt<compressed_slot_t> neighborhoods_;
|
|
150
|
+
std::vector<default_key_t> vector_ids_;
|
|
150
151
|
std::vector<compressed_slot_t> neighborhoods_iota_{};
|
|
151
152
|
std::size_t vectors_to_skip_{};
|
|
152
153
|
std::size_t vectors_to_take_{};
|
|
153
154
|
|
|
154
155
|
persisted_dataset_gt(char const* path_vectors, std::size_t vectors_to_skip = 0,
|
|
155
156
|
std::size_t vectors_to_take = 0) noexcept(false)
|
|
156
|
-
: vectors_(path_vectors), queries_(), neighborhoods_(), vectors_to_skip_(vectors_to_skip),
|
|
157
|
+
: vectors_(path_vectors), queries_(), neighborhoods_(), vector_ids_(), vectors_to_skip_(vectors_to_skip),
|
|
157
158
|
vectors_to_take_(vectors_to_take) {
|
|
158
159
|
neighborhoods_iota_.resize(vectors_.rows);
|
|
159
160
|
std::iota(neighborhoods_iota_.begin(), neighborhoods_iota_.end(), 0);
|
|
@@ -161,8 +162,8 @@ struct persisted_dataset_gt {
|
|
|
161
162
|
|
|
162
163
|
persisted_dataset_gt(char const* path_vectors, char const* path_queries, char const* path_neighbors,
|
|
163
164
|
std::size_t vectors_to_skip = 0, std::size_t vectors_to_take = 0) noexcept(false)
|
|
164
|
-
: vectors_(path_vectors), queries_(path_queries), neighborhoods_(path_neighbors),
|
|
165
|
-
vectors_to_skip_(vectors_to_skip), vectors_to_take_(vectors_to_take) {
|
|
165
|
+
: vectors_(path_vectors), queries_(path_queries), neighborhoods_(path_neighbors), vector_ids_(),
|
|
166
|
+
neighborhoods_iota_(), vectors_to_skip_(vectors_to_skip), vectors_to_take_(vectors_to_take) {
|
|
166
167
|
|
|
167
168
|
if (vectors_.cols != queries_.cols)
|
|
168
169
|
throw std::invalid_argument("Contents and queries have different dimensionality");
|
|
@@ -170,7 +171,45 @@ struct persisted_dataset_gt {
|
|
|
170
171
|
throw std::invalid_argument("Number of ground-truth neighborhoods doesn't match number of queries");
|
|
171
172
|
}
|
|
172
173
|
|
|
174
|
+
persisted_dataset_gt(char const* path_vectors, char const* path_queries, char const* path_neighbors,
|
|
175
|
+
char const* path_ids, std::size_t vectors_to_skip = 0,
|
|
176
|
+
std::size_t vectors_to_take = 0) noexcept(false)
|
|
177
|
+
: vectors_(path_vectors), queries_(path_queries), neighborhoods_(path_neighbors), vector_ids_(),
|
|
178
|
+
neighborhoods_iota_(), vectors_to_skip_(vectors_to_skip), vectors_to_take_(vectors_to_take) {
|
|
179
|
+
|
|
180
|
+
// Handle self-search case (no queries/neighbors)
|
|
181
|
+
if (!queries_.scalars && !neighborhoods_.scalars) {
|
|
182
|
+
neighborhoods_iota_.resize(vectors_.rows);
|
|
183
|
+
std::iota(neighborhoods_iota_.begin(), neighborhoods_iota_.end(), 0);
|
|
184
|
+
} else {
|
|
185
|
+
if (vectors_.cols != queries_.cols)
|
|
186
|
+
throw std::invalid_argument("Contents and queries have different dimensionality");
|
|
187
|
+
if (queries_.rows != neighborhoods_.rows)
|
|
188
|
+
throw std::invalid_argument("Number of ground-truth neighborhoods doesn't match number of queries");
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Load IDs file if provided
|
|
192
|
+
if (path_ids && std::strlen(path_ids)) {
|
|
193
|
+
persisted_matrix_gt<std::int32_t> ids_matrix(path_ids);
|
|
194
|
+
if (ids_matrix.rows != vectors_.rows)
|
|
195
|
+
throw std::invalid_argument("Number of vector IDs doesn't match number of vectors");
|
|
196
|
+
if (ids_matrix.cols != 1)
|
|
197
|
+
throw std::invalid_argument("Vector IDs file should have exactly 1 column");
|
|
198
|
+
|
|
199
|
+
// Convert and copy IDs into memory
|
|
200
|
+
vector_ids_.resize(ids_matrix.rows);
|
|
201
|
+
for (std::size_t i = 0; i < ids_matrix.rows; ++i)
|
|
202
|
+
vector_ids_[i] = static_cast<default_key_t>(*ids_matrix.row(i));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
173
206
|
bool search_itself() const noexcept { return vectors_count() && !queries_.rows; }
|
|
207
|
+
bool has_vector_ids() const noexcept { return !vector_ids_.empty(); }
|
|
208
|
+
|
|
209
|
+
default_key_t vector_id(std::size_t i) const noexcept {
|
|
210
|
+
return has_vector_ids() ? vector_ids_[i + vectors_to_skip_]
|
|
211
|
+
: static_cast<default_key_t>(i + vectors_to_skip_);
|
|
212
|
+
}
|
|
174
213
|
|
|
175
214
|
std::size_t dimensions() const noexcept { return vectors_.cols; }
|
|
176
215
|
std::size_t queries_count() const noexcept { return search_itself() ? vectors_count() : queries_.rows; }
|
|
@@ -214,6 +253,7 @@ struct in_memory_dataset_gt {
|
|
|
214
253
|
std::size_t vectors_count() const noexcept { return vectors_count_; }
|
|
215
254
|
std::size_t queries_count() const noexcept { return vectors_count(); }
|
|
216
255
|
std::size_t neighborhood_size() const noexcept { return 1; }
|
|
256
|
+
default_key_t vector_id(std::size_t i) const noexcept { return static_cast<default_key_t>(i); }
|
|
217
257
|
scalar_t const* vector(std::size_t i) const noexcept { return vectors_.data() + i * dimensions_; }
|
|
218
258
|
scalar_t const* query(std::size_t i) const noexcept { return queries_.data() + i * dimensions_; }
|
|
219
259
|
compressed_slot_t const* neighborhood(std::size_t i) const noexcept {
|
|
@@ -299,8 +339,7 @@ void index_many(index_at& index, std::size_t n, vector_id_at const* ids, scalar_
|
|
|
299
339
|
#if USEARCH_USE_OPENMP
|
|
300
340
|
config.thread = omp_get_thread_num();
|
|
301
341
|
#endif
|
|
302
|
-
|
|
303
|
-
index.add(ids[i], vector, config.thread);
|
|
342
|
+
index.add(ids[i], vectors + dims * i, config.thread);
|
|
304
343
|
printer.progress++;
|
|
305
344
|
if (config.thread == 0)
|
|
306
345
|
printer.refresh();
|
|
@@ -347,7 +386,8 @@ static void single_shot(dataset_at& dataset, index_at& index, bool construct = t
|
|
|
347
386
|
if (construct) {
|
|
348
387
|
// Perform insertions, evaluate speed
|
|
349
388
|
std::vector<default_key_t> ids(dataset.vectors_count());
|
|
350
|
-
std::
|
|
389
|
+
for (std::size_t i = 0; i < dataset.vectors_count(); ++i)
|
|
390
|
+
ids[i] = static_cast<default_key_t>(dataset.vector_id(i));
|
|
351
391
|
index_many(index, dataset.vectors_count(), ids.data(), dataset.vector(0), dataset.dimensions());
|
|
352
392
|
}
|
|
353
393
|
|
|
@@ -433,7 +473,7 @@ void handler(int sig) {
|
|
|
433
473
|
name = "<unknown>";
|
|
434
474
|
}
|
|
435
475
|
DWORD bytes_written;
|
|
436
|
-
WriteFile(STDERR_FILENO, name, strlen(name), &bytes_written, NULL);
|
|
476
|
+
WriteFile(STDERR_FILENO, name, std::strlen(name), &bytes_written, NULL);
|
|
437
477
|
WriteFile(STDERR_FILENO, "\n", 1, &bytes_written, NULL);
|
|
438
478
|
}
|
|
439
479
|
free(symbol);
|
|
@@ -454,6 +494,7 @@ struct args_t {
|
|
|
454
494
|
std::string path_vectors;
|
|
455
495
|
std::string path_queries;
|
|
456
496
|
std::string path_neighbors;
|
|
497
|
+
std::string path_ids;
|
|
457
498
|
std::string path_output = "last.usearch";
|
|
458
499
|
|
|
459
500
|
std::size_t connectivity = default_connectivity();
|
|
@@ -557,17 +598,9 @@ void run_typed(dataset_at& dataset, args_t const& args, index_config_t config, i
|
|
|
557
598
|
|
|
558
599
|
template <typename dataset_scalar_at> void bench_with_args(args_t const& args) {
|
|
559
600
|
using dataset_t = persisted_dataset_gt<dataset_scalar_at, compressed_slot_t>;
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
args.vectors_to_take //
|
|
564
|
-
)
|
|
565
|
-
: dataset_t(args.path_vectors.c_str(), //
|
|
566
|
-
args.path_queries.c_str(), //
|
|
567
|
-
args.path_neighbors.c_str(), //
|
|
568
|
-
args.vectors_to_skip, //
|
|
569
|
-
args.vectors_to_take //
|
|
570
|
-
);
|
|
601
|
+
|
|
602
|
+
dataset_t dataset(args.path_vectors.c_str(), args.path_queries.c_str(), args.path_neighbors.c_str(),
|
|
603
|
+
args.path_ids.c_str(), args.vectors_to_skip, args.vectors_to_take);
|
|
571
604
|
std::printf("-- Dimensions: %zu\n", dataset.dimensions());
|
|
572
605
|
std::printf("-- Vectors count: %zu\n", dataset.vectors_count());
|
|
573
606
|
std::printf("-- Queries count: %zu\n", dataset.queries_count());
|
|
@@ -602,9 +635,12 @@ int main(int argc, char** argv) {
|
|
|
602
635
|
|
|
603
636
|
auto args = args_t{};
|
|
604
637
|
auto cli = ( //
|
|
605
|
-
(option("--vectors") & value("path", args.path_vectors))
|
|
606
|
-
|
|
607
|
-
(option("--
|
|
638
|
+
(option("--vectors") & value("path", args.path_vectors))
|
|
639
|
+
.doc(".[fhbd]bin, .i8bin, .f32bin file path to construct the index"),
|
|
640
|
+
(option("--queries") & value("path", args.path_queries))
|
|
641
|
+
.doc(".[fhbd]bin, .i8bin, .f32bin file path to query the index"),
|
|
642
|
+
(option("--neighbors") & value("path", args.path_neighbors)).doc(".ibin, .i32bin file path with ground truth"),
|
|
643
|
+
(option("--ids") & value("path", args.path_ids)).doc(".i32bin file path with vector IDs (optional)"),
|
|
608
644
|
(option("-o", "--output") & value("path", args.path_output)).doc(".usearch output file path"),
|
|
609
645
|
(option("-b", "--big").set(args.big)).doc("Will switch to uint40_t for neighbors lists with over 4B entries"),
|
|
610
646
|
(option("-j", "--threads") & value("integer", args.threads)).doc("Uses all available cores by default"),
|
|
@@ -665,6 +701,10 @@ int main(int argc, char** argv) {
|
|
|
665
701
|
bench_with_args<f16_t>(args);
|
|
666
702
|
else if (ends_with(args.path_vectors, ".bbin"))
|
|
667
703
|
bench_with_args<b1x8_t>(args);
|
|
704
|
+
else if (ends_with(args.path_vectors, ".i8bin"))
|
|
705
|
+
bench_with_args<i8_t>(args);
|
|
706
|
+
else if (ends_with(args.path_vectors, ".f32bin"))
|
|
707
|
+
bench_with_args<f32_t>(args);
|
|
668
708
|
else
|
|
669
709
|
throw std::runtime_error("Unknown input file path");
|
|
670
710
|
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|