usearch 0.22.2 → 1.0.0

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.
Files changed (96) hide show
  1. package/.github/workflows/prerelease.yml +3 -3
  2. package/.releaserc +9 -0
  3. package/.vscode/launch.json +15 -11
  4. package/.vscode/settings.json +12 -2
  5. package/.vscode/tasks.json +4 -4
  6. package/CMakeLists.txt +6 -1
  7. package/Cargo.toml +2 -2
  8. package/README.md +39 -46
  9. package/build.rs +2 -2
  10. package/c/CMakeLists.txt +48 -0
  11. package/c/README.md +34 -0
  12. package/c/lib.cpp +83 -72
  13. package/c/test.c +20 -20
  14. package/c/usearch.h +132 -32
  15. package/conanfile.py +1 -1
  16. package/cpp/CMakeLists.txt +3 -1
  17. package/cpp/README.md +16 -16
  18. package/cpp/bench.cpp +50 -126
  19. package/cpp/test.cpp +164 -77
  20. package/docs/benchmarks.md +26 -5
  21. package/docs/c/reference.rst +3 -3
  22. package/docs/compilation.md +49 -45
  23. package/docs/cpp/index.rst +2 -2
  24. package/docs/cpp/reference.rst +13 -3
  25. package/docs/index.rst +8 -8
  26. package/docs/java/reference.rst +1 -1
  27. package/golang/lib.go +275 -141
  28. package/golang/lib_test.go +105 -0
  29. package/include/usearch/index.hpp +1733 -1659
  30. package/include/usearch/index_dense.hpp +1400 -0
  31. package/include/usearch/index_plugins.hpp +1263 -0
  32. package/java/README.md +1 -1
  33. package/java/cloud/unum/usearch/Index.java +10 -10
  34. package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +34 -37
  35. package/java/test/IndexTest.java +1 -1
  36. package/javascript/README.md +7 -7
  37. package/javascript/lib.cpp +94 -55
  38. package/javascript/test.js +25 -11
  39. package/javascript/usearch.d.ts +87 -0
  40. package/javascript/usearch.js +2 -118
  41. package/objc/USearchObjective.mm +57 -31
  42. package/objc/include/USearchObjective.h +32 -22
  43. package/package.json +5 -3
  44. package/pyproject.toml +3 -3
  45. package/python/README.md +23 -14
  46. package/python/lib.cpp +472 -444
  47. package/python/scripts/bench.ipynb +3 -2
  48. package/python/scripts/bench.py +4 -4
  49. package/python/scripts/index_faiss.py +5 -5
  50. package/python/scripts/join.py +4 -4
  51. package/python/scripts/test.py +152 -61
  52. package/python/scripts/test_jit.py +10 -12
  53. package/python/scripts/test_sparse.py +32 -0
  54. package/python/usearch/client.py +26 -28
  55. package/python/usearch/eval.py +73 -23
  56. package/python/usearch/index.py +520 -228
  57. package/python/usearch/io.py +57 -25
  58. package/python/usearch/numba.py +4 -4
  59. package/python/usearch/server.py +10 -10
  60. package/rust/lib.cpp +22 -27
  61. package/rust/lib.hpp +11 -12
  62. package/rust/lib.rs +3 -3
  63. package/setup.py +5 -2
  64. package/simsimd/.github/workflows/prerelease.yml +73 -0
  65. package/simsimd/.github/workflows/release.yml +110 -0
  66. package/simsimd/.github/workflows/update_version.sh +3 -0
  67. package/simsimd/.releaserc +77 -0
  68. package/simsimd/.vscode/launch.json +27 -1
  69. package/simsimd/.vscode/settings.json +22 -1
  70. package/simsimd/.vscode/tasks.json +6 -0
  71. package/simsimd/CMakeLists.txt +3 -2
  72. package/simsimd/README.md +82 -46
  73. package/simsimd/bench.cxx +63 -24
  74. package/simsimd/include/simsimd/simsimd.h +88 -66
  75. package/simsimd/include/simsimd/simsimd_chem.h +126 -0
  76. package/simsimd/package.json +8 -0
  77. package/simsimd/pyproject.toml +42 -0
  78. package/simsimd/python/python.c +81 -0
  79. package/simsimd/python/run.sh +1 -0
  80. package/simsimd/python/test.c +109 -0
  81. package/simsimd/python/test.py +23 -0
  82. package/simsimd/setup.py +44 -0
  83. package/swift/Index+Sugar.swift +75 -23
  84. package/swift/README.md +26 -2
  85. package/swift/Test.swift +19 -7
  86. package/swift/USearch.swift +2 -2
  87. package/tsconfig.json +8 -0
  88. package/wasm/CMakeLists.txt +1 -0
  89. package/wasmer.toml +5 -1
  90. package/wolfram/CMakeLists.txt +1 -0
  91. package/wolfram/lib.cpp +11 -13
  92. package/golang/usearch.h +0 -9
  93. package/golang/usearch_par_test.go +0 -40
  94. package/golang/usearch_test.go +0 -82
  95. package/include/usearch/index_punned_dense.hpp +0 -871
  96. package/include/usearch/index_punned_helpers.hpp +0 -566
package/c/lib.cpp CHANGED
@@ -1,6 +1,6 @@
1
1
  #include <cassert>
2
2
 
3
- #include <usearch/index_punned_dense.hpp>
3
+ #include <usearch/index_dense.hpp>
4
4
 
5
5
  #ifndef USEARCH_EXPORT
6
6
  #define USEARCH_EXPORT
@@ -13,13 +13,12 @@ extern "C" {
13
13
  using namespace unum::usearch;
14
14
  using namespace unum;
15
15
 
16
- using label_t = usearch_label_t;
17
- using distance_t = usearch_distance_t;
18
- using index_t = index_punned_dense_gt<label_t>;
19
- using add_result_t = index_t::add_result_t;
20
- using search_result_t = index_t::search_result_t;
21
- using serialization_result_t = index_t::serialization_result_t;
22
- using vector_view_t = span_gt<float>;
16
+ using add_result_t = typename index_dense_t::add_result_t;
17
+ using search_result_t = typename index_dense_t::search_result_t;
18
+ using labeling_result_t = typename index_dense_t::labeling_result_t;
19
+
20
+ static_assert(std::is_same<usearch_key_t, index_dense_t::key_t>::value, "Type mismatch between C and C++");
21
+ static_assert(std::is_same<usearch_distance_t, index_dense_t::distance_t>::value, "Type mismatch between C and C++");
23
22
 
24
23
  // helper functions that are not part of the C ABI
25
24
  metric_kind_t to_native_metric(usearch_metric_kind_t kind) {
@@ -42,133 +41,139 @@ scalar_kind_t to_native_scalar(usearch_scalar_kind_t kind) {
42
41
  case usearch_scalar_f32_k: return scalar_kind_t::f32_k;
43
42
  case usearch_scalar_f64_k: return scalar_kind_t::f64_k;
44
43
  case usearch_scalar_f16_k: return scalar_kind_t::f16_k;
45
- case usearch_scalar_f8_k: return scalar_kind_t::f8_k;
44
+ case usearch_scalar_i8_k: return scalar_kind_t::i8_k;
46
45
  case usearch_scalar_b1_k: return scalar_kind_t::b1x8_k;
47
46
  default: return scalar_kind_t::unknown_k;
48
47
  }
49
48
  }
50
49
 
51
- add_result_t add_(index_t* index, usearch_label_t label, void const* vector, scalar_kind_t kind) {
50
+ add_result_t add_(index_dense_t* index, usearch_key_t key, void const* vector, scalar_kind_t kind) {
52
51
  switch (kind) {
53
- case scalar_kind_t::f32_k: return index->add(label, (f32_t const*)vector);
54
- case scalar_kind_t::f64_k: return index->add(label, (f64_t const*)vector);
55
- case scalar_kind_t::f16_k: return index->add(label, (f16_t const*)vector);
56
- case scalar_kind_t::f8_k: return index->add(label, (f8_bits_t const*)vector);
57
- case scalar_kind_t::b1x8_k: return index->add(label, (b1x8_t const*)vector);
52
+ case scalar_kind_t::f32_k: return index->add(key, (f32_t const*)vector);
53
+ case scalar_kind_t::f64_k: return index->add(key, (f64_t const*)vector);
54
+ case scalar_kind_t::f16_k: return index->add(key, (f16_t const*)vector);
55
+ case scalar_kind_t::i8_k: return index->add(key, (i8_bits_t const*)vector);
56
+ case scalar_kind_t::b1x8_k: return index->add(key, (b1x8_t const*)vector);
58
57
  default: return add_result_t{}.failed("Unknown scalar kind!");
59
58
  }
60
59
  }
61
60
 
62
- bool get_(index_t* index, label_t label, void* vector, scalar_kind_t kind) {
61
+ bool get_(index_dense_t* index, usearch_key_t key, void* vector, scalar_kind_t kind) {
63
62
  switch (kind) {
64
- case scalar_kind_t::f32_k: return index->get(label, (f32_t*)vector);
65
- case scalar_kind_t::f64_k: return index->get(label, (f64_t*)vector);
66
- case scalar_kind_t::f16_k: return index->get(label, (f16_t*)vector);
67
- case scalar_kind_t::f8_k: return index->get(label, (f8_bits_t*)vector);
68
- case scalar_kind_t::b1x8_k: return index->get(label, (b1x8_t*)vector);
69
- default: return index->empty_search_result().failed("Unknown scalar kind!");
63
+ case scalar_kind_t::f32_k: return index->get(key, (f32_t*)vector);
64
+ case scalar_kind_t::f64_k: return index->get(key, (f64_t*)vector);
65
+ case scalar_kind_t::f16_k: return index->get(key, (f16_t*)vector);
66
+ case scalar_kind_t::i8_k: return index->get(key, (i8_bits_t*)vector);
67
+ case scalar_kind_t::b1x8_k: return index->get(key, (b1x8_t*)vector);
68
+ default: return search_result_t().failed("Unknown scalar kind!");
70
69
  }
71
70
  }
72
71
 
73
- search_result_t search_(index_t* index, void const* vector, scalar_kind_t kind, size_t n) {
72
+ search_result_t search_(index_dense_t* index, void const* vector, scalar_kind_t kind, size_t n) {
74
73
  switch (kind) {
75
74
  case scalar_kind_t::f32_k: return index->search((f32_t const*)vector, n);
76
75
  case scalar_kind_t::f64_k: return index->search((f64_t const*)vector, n);
77
76
  case scalar_kind_t::f16_k: return index->search((f16_t const*)vector, n);
78
- case scalar_kind_t::f8_k: return index->search((f8_bits_t const*)vector, n);
77
+ case scalar_kind_t::i8_k: return index->search((i8_bits_t const*)vector, n);
79
78
  case scalar_kind_t::b1x8_k: return index->search((b1x8_t const*)vector, n);
80
- default: return index->empty_search_result().failed("Unknown scalar kind!");
79
+ default: return search_result_t().failed("Unknown scalar kind!");
81
80
  }
82
81
  }
83
82
 
84
- index_punned_dense_metric_t udf(metric_kind_t kind, usearch_metric_t raw_ptr) {
85
- index_punned_dense_metric_t result;
86
- result.kind_ = kind;
87
- result.func_ = [raw_ptr](punned_vector_view_t a, punned_vector_view_t b) -> distance_t {
88
- return raw_ptr((void const*)a.data(), (void const*)b.data());
89
- };
90
- return result;
91
- }
92
-
93
83
  extern "C" {
94
84
 
95
85
  USEARCH_EXPORT usearch_index_t usearch_init(usearch_init_options_t* options, usearch_error_t* error) {
96
86
 
97
87
  assert(options && error);
98
88
 
99
- index_config_t config;
100
- config.connectivity = options->connectivity;
101
- index_t index = //
102
- options->metric ? //
103
- index_t::make( //
104
- options->dimensions, udf(to_native_metric(options->metric_kind), options->metric), config,
105
- to_native_scalar(options->quantization), options->expansion_add, options->expansion_search)
106
- : //
107
- index_t::make( //
108
- options->dimensions, to_native_metric(options->metric_kind), config,
109
- to_native_scalar(options->quantization), options->expansion_add, options->expansion_search);
110
-
111
- index_t* result_ptr = new index_t(std::move(index));
89
+ index_dense_config_t config(options->connectivity, options->expansion_add, options->expansion_search);
90
+ metric_kind_t metric_kind = to_native_metric(options->metric_kind);
91
+ scalar_kind_t scalar_kind = to_native_scalar(options->quantization);
92
+
93
+ auto metric_lambda = [options](byte_t const* a, byte_t const* b) -> usearch_distance_t {
94
+ return options->metric((void const*)a, (void const*)b);
95
+ };
96
+ metric_punned_t metric = //
97
+ options->metric ? metric_punned_t(metric_lambda, options->dimensions, metric_kind, scalar_kind)
98
+ : metric_punned_t(options->dimensions, metric_kind, scalar_kind);
99
+
100
+ index_dense_t index = index_dense_t::make(metric, config);
101
+ index_dense_t* result_ptr = new index_dense_t(std::move(index));
112
102
  return result_ptr;
113
103
  }
114
104
 
115
- USEARCH_EXPORT void usearch_free(usearch_index_t index, usearch_error_t*) { delete reinterpret_cast<index_t*>(index); }
105
+ USEARCH_EXPORT void usearch_free(usearch_index_t index, usearch_error_t*) {
106
+ delete reinterpret_cast<index_dense_t*>(index);
107
+ }
116
108
 
117
109
  USEARCH_EXPORT void usearch_save(usearch_index_t index, char const* path, usearch_error_t* error) {
118
- serialization_result_t result = reinterpret_cast<index_t*>(index)->save(path);
110
+
111
+ assert(index && path && error);
112
+ serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->save(path);
119
113
  if (!result)
120
114
  *error = result.error.what();
121
115
  }
122
116
 
123
117
  USEARCH_EXPORT void usearch_load(usearch_index_t index, char const* path, usearch_error_t* error) {
124
- serialization_result_t result = reinterpret_cast<index_t*>(index)->load(path);
118
+
119
+ assert(index && path && error);
120
+ serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->load(path);
125
121
  if (!result)
126
122
  *error = result.error.what();
127
123
  }
128
124
 
129
125
  USEARCH_EXPORT void usearch_view(usearch_index_t index, char const* path, usearch_error_t* error) {
130
- serialization_result_t result = reinterpret_cast<index_t*>(index)->view(path);
126
+
127
+ assert(index && path && error);
128
+ serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->view(path);
131
129
  if (!result)
132
130
  *error = result.error.what();
133
131
  }
134
132
 
135
133
  USEARCH_EXPORT size_t usearch_size(usearch_index_t index, usearch_error_t*) { //
136
- return reinterpret_cast<index_t*>(index)->size();
134
+ return reinterpret_cast<index_dense_t*>(index)->size();
137
135
  }
138
136
 
139
137
  USEARCH_EXPORT size_t usearch_capacity(usearch_index_t index, usearch_error_t*) {
140
- return reinterpret_cast<index_t*>(index)->capacity();
138
+ return reinterpret_cast<index_dense_t*>(index)->capacity();
141
139
  }
142
140
 
143
141
  USEARCH_EXPORT size_t usearch_dimensions(usearch_index_t index, usearch_error_t*) {
144
- return reinterpret_cast<index_t*>(index)->dimensions();
142
+ return reinterpret_cast<index_dense_t*>(index)->dimensions();
145
143
  }
146
144
 
147
145
  USEARCH_EXPORT size_t usearch_connectivity(usearch_index_t index, usearch_error_t*) {
148
- return reinterpret_cast<index_t*>(index)->connectivity();
146
+ return reinterpret_cast<index_dense_t*>(index)->connectivity();
149
147
  }
150
148
 
151
- USEARCH_EXPORT void usearch_reserve(usearch_index_t index, size_t capacity, usearch_error_t*) {
152
- // TODO: Consider returning the new capacity.
153
- reinterpret_cast<index_t*>(index)->reserve(capacity);
149
+ USEARCH_EXPORT void usearch_reserve(usearch_index_t index, size_t capacity, usearch_error_t* error) {
150
+ assert(index && error);
151
+ if (!reinterpret_cast<index_dense_t*>(index)->reserve(capacity))
152
+ *error = "Out of memory!";
154
153
  }
155
154
 
156
- USEARCH_EXPORT void usearch_add( //
157
- usearch_index_t index, usearch_label_t label, void const* vector, usearch_scalar_kind_t kind, //
155
+ USEARCH_EXPORT void usearch_add( //
156
+ usearch_index_t index, usearch_key_t key, void const* vector, usearch_scalar_kind_t kind, //
158
157
  usearch_error_t* error) {
159
- add_result_t result = add_(reinterpret_cast<index_t*>(index), label, vector, to_native_scalar(kind));
158
+
159
+ assert(index && vector && error);
160
+ add_result_t result = add_(reinterpret_cast<index_dense_t*>(index), key, vector, to_native_scalar(kind));
160
161
  if (!result)
161
162
  *error = result.error.what();
162
163
  }
163
164
 
164
- USEARCH_EXPORT bool usearch_contains(usearch_index_t index, usearch_label_t label, usearch_error_t*) {
165
- return reinterpret_cast<index_t*>(index)->contains(label);
165
+ USEARCH_EXPORT bool usearch_contains(usearch_index_t index, usearch_key_t key, usearch_error_t*) {
166
+ assert(index);
167
+ return reinterpret_cast<index_dense_t*>(index)->contains(key);
166
168
  }
167
169
 
168
- USEARCH_EXPORT size_t usearch_search( //
170
+ USEARCH_EXPORT size_t usearch_search( //
169
171
  usearch_index_t index, void const* vector, usearch_scalar_kind_t kind, size_t results_limit, //
170
- usearch_label_t* found_labels, usearch_distance_t* found_distances, usearch_error_t* error) {
171
- search_result_t result = search_(reinterpret_cast<index_t*>(index), vector, to_native_scalar(kind), results_limit);
172
+ usearch_key_t* found_labels, usearch_distance_t* found_distances, usearch_error_t* error) {
173
+
174
+ assert(index && vector && error);
175
+ search_result_t result =
176
+ search_(reinterpret_cast<index_dense_t*>(index), vector, to_native_scalar(kind), results_limit);
172
177
  if (!result) {
173
178
  *error = result.error.what();
174
179
  return 0;
@@ -177,14 +182,20 @@ USEARCH_EXPORT size_t usearch_search(
177
182
  return result.dump_to(found_labels, found_distances);
178
183
  }
179
184
 
180
- USEARCH_EXPORT bool usearch_get( //
181
- usearch_index_t index, usearch_label_t label, //
185
+ USEARCH_EXPORT bool usearch_get( //
186
+ usearch_index_t index, usearch_key_t key, //
182
187
  void* vector, usearch_scalar_kind_t kind, usearch_error_t*) {
183
- return get_(reinterpret_cast<index_t*>(index), label, vector, to_native_scalar(kind));
188
+
189
+ assert(index && vector);
190
+ return get_(reinterpret_cast<index_dense_t*>(index), key, vector, to_native_scalar(kind));
184
191
  }
185
192
 
186
- USEARCH_EXPORT void usearch_remove(usearch_index_t, usearch_label_t, usearch_error_t* error) {
187
- if (error != nullptr)
188
- *error = "USearch does not support removal of elements yet.";
193
+ USEARCH_EXPORT bool usearch_remove(usearch_index_t index, usearch_key_t key, usearch_error_t* error) {
194
+
195
+ assert(index && error);
196
+ labeling_result_t result = reinterpret_cast<index_dense_t*>(index)->remove(key);
197
+ if (!result)
198
+ *error = result.error.what();
199
+ return result.completed;
189
200
  }
190
201
  }
package/c/test.c CHANGED
@@ -107,8 +107,8 @@ void test_add_vector(size_t vectors_count, size_t vector_dimension, float const*
107
107
 
108
108
  // Add vectors
109
109
  for (size_t i = 0; i < vectors_count; ++i) {
110
- usearch_label_t label = i;
111
- usearch_add(idx, label, data + i * vector_dimension, usearch_scalar_f32_k, &error);
110
+ usearch_key_t key = i;
111
+ usearch_add(idx, key, data + i * vector_dimension, usearch_scalar_f32_k, &error);
112
112
  ASSERT(!error, error);
113
113
  }
114
114
 
@@ -117,10 +117,10 @@ void test_add_vector(size_t vectors_count, size_t vector_dimension, float const*
117
117
 
118
118
  // Check vectors in the index
119
119
  for (size_t i = 0; i < vectors_count; ++i) {
120
- usearch_label_t label = i;
121
- ASSERT(usearch_contains(idx, label, &error), error);
120
+ usearch_key_t key = i;
121
+ ASSERT(usearch_contains(idx, key, &error), error);
122
122
  }
123
- ASSERT(!usearch_contains(idx, -1, &error), error); // Non existing label
123
+ ASSERT(!usearch_contains(idx, -1, &error), error); // Non existing key
124
124
 
125
125
  usearch_free(idx, &error);
126
126
  printf("Test: Add Vector - PASSED\n");
@@ -137,21 +137,21 @@ void test_find_vector(size_t vectors_count, size_t vector_dimension, float const
137
137
 
138
138
  // Create result buffers
139
139
  int results_count = 10;
140
- usearch_label_t* labels = (usearch_label_t*)malloc(results_count * sizeof(usearch_label_t));
140
+ usearch_key_t* keys = (usearch_key_t*)malloc(results_count * sizeof(usearch_key_t));
141
141
  float* distances = (float*)malloc(results_count * sizeof(float));
142
- ASSERT(labels && distances, "Failed to allocate memory");
142
+ ASSERT(keys && distances, "Failed to allocate memory");
143
143
 
144
144
  // Add vectors
145
145
  for (size_t i = 0; i < vectors_count; ++i) {
146
- usearch_label_t label = i;
147
- usearch_add(idx, label, data + i * vector_dimension, usearch_scalar_f32_k, &error);
146
+ usearch_key_t key = i;
147
+ usearch_add(idx, key, data + i * vector_dimension, usearch_scalar_f32_k, &error);
148
148
  ASSERT(!error, error);
149
149
  }
150
150
 
151
151
  // Find the vectors
152
152
  for (size_t i = 0; i < vectors_count; i++) {
153
153
  const void *query_vector = data + i * vector_dimension;
154
- size_t found_count = usearch_search(idx, query_vector, usearch_scalar_f32_k, results_count, labels, distances, &error);
154
+ size_t found_count = usearch_search(idx, query_vector, usearch_scalar_f32_k, results_count, keys, distances, &error);
155
155
  ASSERT(!error, error);
156
156
  ASSERT(found_count = results_count, "Vector is missing");
157
157
  }
@@ -171,15 +171,15 @@ void test_remove_vector(size_t vectors_count, size_t vector_dimension, float con
171
171
 
172
172
  // Add vectors
173
173
  for (size_t i = 0; i < vectors_count; ++i) {
174
- usearch_label_t label = i;
175
- usearch_add(idx, label, data + i * vector_dimension, usearch_scalar_f32_k, &error);
174
+ usearch_key_t key = i;
175
+ usearch_add(idx, key, data + i * vector_dimension, usearch_scalar_f32_k, &error);
176
176
  ASSERT(!error, error);
177
177
  }
178
178
 
179
179
  // Remove the vectors
180
180
  for (size_t i = 0; i < vectors_count; i++) {
181
- usearch_label_t label = i;
182
- usearch_remove(idx, label, &error);
181
+ usearch_key_t key = i;
182
+ usearch_remove(idx, key, &error);
183
183
  ASSERT(error, "Currently, Remove is not supported");
184
184
  }
185
185
 
@@ -198,8 +198,8 @@ void test_save_load(size_t vectors_count, size_t vector_dimension, float const*
198
198
 
199
199
  // Add vectors
200
200
  for (size_t i = 0; i < vectors_count; ++i) {
201
- usearch_label_t label = i;
202
- usearch_add(idx, label, data + i * vector_dimension, usearch_scalar_f32_k, &error);
201
+ usearch_key_t key = i;
202
+ usearch_add(idx, key, data + i * vector_dimension, usearch_scalar_f32_k, &error);
203
203
  ASSERT(!error, error);
204
204
  }
205
205
 
@@ -224,8 +224,8 @@ void test_save_load(size_t vectors_count, size_t vector_dimension, float const*
224
224
 
225
225
  // Check vectors in the index
226
226
  for (size_t i = 0; i < vectors_count; ++i) {
227
- usearch_label_t label = i;
228
- ASSERT(usearch_contains(idx, label, &error), error);
227
+ usearch_key_t key = i;
228
+ ASSERT(usearch_contains(idx, key, &error), error);
229
229
  }
230
230
 
231
231
  usearch_free(idx, &error);
@@ -243,8 +243,8 @@ void test_view(size_t vectors_count, size_t vector_dimension, float const* data)
243
243
 
244
244
  // Add vectors
245
245
  for (size_t i = 0; i < vectors_count; ++i) {
246
- usearch_label_t label = i;
247
- usearch_add(idx, label, data + i * vector_dimension, usearch_scalar_f32_k, &error);
246
+ usearch_key_t key = i;
247
+ usearch_add(idx, key, data + i * vector_dimension, usearch_scalar_f32_k, &error);
248
248
  ASSERT(!error, error);
249
249
  }
250
250
 
package/c/usearch.h CHANGED
@@ -1,6 +1,6 @@
1
1
  #ifndef UNUM_USEARCH_H
2
2
  #define UNUM_USEARCH_H
3
- // in case the header is included from cpp code
3
+
4
4
  #ifdef __cplusplus
5
5
  extern "C" {
6
6
  #endif
@@ -11,79 +11,179 @@ extern "C" {
11
11
  #include <stdint.h> // `size_t`
12
12
 
13
13
  USEARCH_EXPORT typedef void* usearch_index_t;
14
- USEARCH_EXPORT typedef uint32_t usearch_label_t;
14
+ USEARCH_EXPORT typedef uint64_t usearch_key_t;
15
15
  USEARCH_EXPORT typedef float usearch_distance_t;
16
+
17
+ /**
18
+ * @brief Pointer to a null-terminated error message.
19
+ * Returned error messages @b don't need to be deallocated.
20
+ */
16
21
  USEARCH_EXPORT typedef char const* usearch_error_t;
17
22
 
23
+ /**
24
+ * @brief Type-punned callback for "metrics" or "distance functions",
25
+ * that accepts pointers to two vectors and measures their @b dis-similarity.
26
+ */
18
27
  USEARCH_EXPORT typedef usearch_distance_t (*usearch_metric_t)(void const*, void const*);
19
28
 
29
+ /**
30
+ * @brief Enumerator for the most common kinds of `usearch_metric_t`.
31
+ * Those are supported out of the box, with SIMD-optimizations for most common hardware.
32
+ */
20
33
  USEARCH_EXPORT typedef enum usearch_metric_kind_t {
21
- usearch_metric_ip_k = 0,
22
- usearch_metric_l2sq_k,
34
+ usearch_metric_unknown_k = 0,
23
35
  usearch_metric_cos_k,
36
+ usearch_metric_ip_k,
37
+ usearch_metric_l2sq_k,
24
38
  usearch_metric_haversine_k,
25
39
  usearch_metric_pearson_k,
26
40
  usearch_metric_jaccard_k,
27
41
  usearch_metric_hamming_k,
28
42
  usearch_metric_tanimoto_k,
29
43
  usearch_metric_sorensen_k,
30
- usearch_metric_unknown_k,
31
44
  } usearch_metric_kind_t;
32
45
 
33
46
  USEARCH_EXPORT typedef enum usearch_scalar_kind_t {
34
- usearch_scalar_f32_k = 0,
47
+ usearch_scalar_unknown_k = 0,
48
+ usearch_scalar_f32_k,
35
49
  usearch_scalar_f64_k,
36
50
  usearch_scalar_f16_k,
37
- usearch_scalar_f8_k,
51
+ usearch_scalar_i8_k,
38
52
  usearch_scalar_b1_k,
39
- usearch_scalar_unknown_k,
40
53
  } usearch_scalar_kind_t;
41
54
 
42
55
  USEARCH_EXPORT typedef struct usearch_init_options_t {
43
-
56
+ /**
57
+ * @brief The metric kind used for distance calculation between vectors.
58
+ */
44
59
  usearch_metric_kind_t metric_kind;
60
+ /**
61
+ * @brief The @b optional custom distance metric function used for distance calculation between vectors.
62
+ * If the `metric_kind` is set to `usearch_metric_unknown_k`, this function pointer mustn't be `NULL`.
63
+ */
45
64
  usearch_metric_t metric;
46
-
65
+ /**
66
+ * @brief The scalar kind used for quantization of vector data during indexing.
67
+ */
47
68
  usearch_scalar_kind_t quantization;
69
+ /**
70
+ * @brief The number of dimensions in the vectors to be indexed.
71
+ * Must be defined for most metrics, but can be avoided for `usearch_metric_haversine_k`.
72
+ */
48
73
  size_t dimensions;
74
+ /**
75
+ * @brief The @b optional connectivity parameter that limits connections-per-node in graph.
76
+ */
49
77
  size_t connectivity;
78
+ /**
79
+ * @brief The @b optional expansion factor used for index construction when adding vectors.
80
+ */
50
81
  size_t expansion_add;
82
+ /**
83
+ * @brief The @b optional expansion factor used for index construction during search operations.
84
+ */
51
85
  size_t expansion_search;
52
86
  } usearch_init_options_t;
53
87
 
54
- USEARCH_EXPORT usearch_index_t usearch_init(usearch_init_options_t*, usearch_error_t*);
55
- USEARCH_EXPORT void usearch_free(usearch_index_t, usearch_error_t*);
88
+ /**
89
+ * @brief Initializes a new instance of the index.
90
+ * @param options Pointer to the `usearch_init_options_t` structure containing initialization options.
91
+ * @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
92
+ * @return A handle to the initialized USearch index, or `NULL` on failure.
93
+ */
94
+ USEARCH_EXPORT usearch_index_t usearch_init(usearch_init_options_t* options, usearch_error_t* error);
56
95
 
57
- USEARCH_EXPORT void usearch_save(usearch_index_t, char const* path, usearch_error_t*);
58
- USEARCH_EXPORT void usearch_load(usearch_index_t, char const* path, usearch_error_t*);
59
- USEARCH_EXPORT void usearch_view(usearch_index_t, char const* path, usearch_error_t*);
96
+ /**
97
+ * @brief Frees the resources associated with the index.
98
+ * @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
99
+ */
100
+ USEARCH_EXPORT void usearch_free(usearch_index_t, usearch_error_t* error);
60
101
 
61
- USEARCH_EXPORT size_t usearch_size(usearch_index_t, usearch_error_t*);
62
- USEARCH_EXPORT size_t usearch_capacity(usearch_index_t, usearch_error_t*);
63
- USEARCH_EXPORT size_t usearch_dimensions(usearch_index_t, usearch_error_t*);
64
- USEARCH_EXPORT size_t usearch_connectivity(usearch_index_t, usearch_error_t*);
102
+ /**
103
+ * @brief Saves the index to a file.
104
+ * @param[in] path The file path where the index will be saved.
105
+ * @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
106
+ */
107
+ USEARCH_EXPORT void usearch_save(usearch_index_t, char const* path, usearch_error_t* error);
65
108
 
66
- USEARCH_EXPORT void usearch_reserve(usearch_index_t, size_t capacity, usearch_error_t*);
109
+ /**
110
+ * @brief Loads the index from a file.
111
+ * @param[in] path The file path from where the index will be loaded.
112
+ * @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
113
+ */
114
+ USEARCH_EXPORT void usearch_load(usearch_index_t, char const* path, usearch_error_t* error);
67
115
 
68
- USEARCH_EXPORT void usearch_add( //
69
- usearch_index_t, usearch_label_t, void const* vector, usearch_scalar_kind_t vector_kind, //
70
- usearch_error_t*);
116
+ /**
117
+ * @brief Creates a view of the index from a file without loading it into memory.
118
+ * @param[in] path The file path from where the view will be created.
119
+ * @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
120
+ */
121
+ USEARCH_EXPORT void usearch_view(usearch_index_t, char const* path, usearch_error_t* error);
71
122
 
72
- USEARCH_EXPORT bool usearch_contains(usearch_index_t, usearch_label_t, usearch_error_t*);
123
+ USEARCH_EXPORT size_t usearch_size(usearch_index_t, usearch_error_t* error);
124
+ USEARCH_EXPORT size_t usearch_capacity(usearch_index_t, usearch_error_t* error);
125
+ USEARCH_EXPORT size_t usearch_dimensions(usearch_index_t, usearch_error_t* error);
126
+ USEARCH_EXPORT size_t usearch_connectivity(usearch_index_t, usearch_error_t* error);
73
127
 
74
128
  /**
75
- * @brief Performs k-Approximate Nearest Neighbors Search.
76
- * @return Number of found matches.
129
+ * @brief Reserves memory for a specified number of incoming vectors.
130
+ * @param[in] capacity The desired total capacity including current size.
131
+ * @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
77
132
  */
78
- USEARCH_EXPORT size_t usearch_search( //
133
+ USEARCH_EXPORT void usearch_reserve(usearch_index_t, size_t capacity, usearch_error_t* error);
134
+
135
+ /**
136
+ * @brief Adds a vector with a key to the index.
137
+ * @param[in] key The key associated with the vector.
138
+ * @param[in] vector Pointer to the vector data.
139
+ * @param[in] vector_kind The scalar type used in the vector data.
140
+ * @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
141
+ */
142
+ USEARCH_EXPORT void usearch_add( //
143
+ usearch_index_t, usearch_key_t key, //
144
+ void const* vector, usearch_scalar_kind_t vector_kind, usearch_error_t* error);
145
+
146
+ /**
147
+ * @brief Checks if the index contains a vector with a specific key.
148
+ * @param[in] key The key to be checked.
149
+ * @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
150
+ * @return `true` if the index contains the vector with the given key, `false` otherwise.
151
+ */
152
+ USEARCH_EXPORT bool usearch_contains(usearch_index_t, usearch_key_t, usearch_error_t* error);
153
+
154
+ /**
155
+ * @brief Performs k-Approximate Nearest Neighbors (kANN) Search for closest vectors to query.
156
+ * @param[in] query_vector Pointer to the query vector data.
157
+ * @param[in] query_kind The scalar type used in the query vector data.
158
+ * @param[in] results_limit Upper bound on the number of neighbors to search, the "k" in "kANN".
159
+ * @param[out] found_keys Output buffer for up to `results_limit` nearest neighbors keys.
160
+ * @param[out] found_distances Output buffer for up to `results_limit` distances to nearest neighbors.
161
+ * @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
162
+ * @return Number of found matches.
163
+ */
164
+ USEARCH_EXPORT size_t usearch_search( //
79
165
  usearch_index_t, void const* query_vector, usearch_scalar_kind_t query_kind, size_t results_limit, //
80
- usearch_label_t* found_labels, usearch_distance_t* found_distances, usearch_error_t*);
166
+ usearch_key_t* found_keys, usearch_distance_t* found_distances, usearch_error_t* error);
81
167
 
82
- USEARCH_EXPORT bool usearch_get( //
83
- usearch_index_t, usearch_label_t, //
84
- void* vector, usearch_scalar_kind_t vector_kind, usearch_error_t*);
168
+ /**
169
+ * @brief Retrieves the vector associated with the given key from the index.
170
+ * @param[in] key The key of the vector to retrieve.
171
+ * @param[out] vector Pointer to the memory where the vector data will be copied.
172
+ * @param[in] vector_kind The scalar type used in the vector data.
173
+ * @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
174
+ * @return `true` if the vector is successfully retrieved, `false` if the vector is not found.
175
+ */
176
+ USEARCH_EXPORT bool usearch_get( //
177
+ usearch_index_t, usearch_key_t key, //
178
+ void* vector, usearch_scalar_kind_t vector_kind, usearch_error_t* error);
85
179
 
86
- USEARCH_EXPORT void usearch_remove(usearch_index_t, usearch_label_t, usearch_error_t*);
180
+ /**
181
+ * @brief Removes the vector associated with the given key from the index.
182
+ * @param[in] key The key of the vector to be removed.
183
+ * @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
184
+ * @return `true` if the vector is successfully removed, `false` if the vector is not found.
185
+ */
186
+ USEARCH_EXPORT bool usearch_remove(usearch_index_t, usearch_key_t key, usearch_error_t* error);
87
187
 
88
188
  #ifdef __cplusplus
89
189
  }
package/conanfile.py CHANGED
@@ -4,7 +4,7 @@ from conans import ConanFile
4
4
  class USearchConan(ConanFile):
5
5
 
6
6
  name = 'USearch'
7
- version = '0.22.2'
7
+ version = '1.0.0'
8
8
  license = 'Apache 2.0'
9
9
  url = 'https://github.com/unum-cloud/usearch'
10
10
  description = 'Smaller & Faster Single-File Vector Search Engine from Unum'
@@ -83,6 +83,7 @@ if(${USEARCH_BUILD_TEST})
83
83
  target_link_libraries(test PRIVATE Threads::Threads)
84
84
  target_include_directories(test PRIVATE ${USEARCH_PUNNED_INCLUDE_DIRS})
85
85
  set_target_properties(test PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
86
+ set_target_properties(test PROPERTIES CXX_STANDARD 17)
86
87
 
87
88
  if(${CMAKE_VERSION} VERSION_EQUAL 3.13 OR ${CMAKE_VERSION} VERSION_GREATER 3.13)
88
89
  include(CTest)
@@ -96,6 +97,7 @@ if(${USEARCH_BUILD_BENCHMARK})
96
97
  target_link_libraries(bench PRIVATE Threads::Threads)
97
98
  target_include_directories(bench PRIVATE ${USEARCH_PUNNED_INCLUDE_DIRS})
98
99
  set_target_properties(bench PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
100
+ set_target_properties(bench PROPERTIES CXX_STANDARD 17)
99
101
 
100
102
  if(${USEARCH_USE_SIMSIMD})
101
103
  target_compile_definitions(bench PRIVATE USEARCH_USE_SIMSIMD=1)
@@ -107,6 +109,6 @@ if(${USEARCH_BUILD_BENCHMARK})
107
109
  endif()
108
110
 
109
111
  if(${USEARCH_USE_JEMALLOC})
110
- target_link_libraries(bench PRIVATE ${JEMALLOC_LIBRARIES})
112
+ target_link_libraries(bench PRIVATE ${JEMALLOC_LIBRARIES})
111
113
  endif()
112
114
  endif()