usearch 0.22.3 → 1.1.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 (93) hide show
  1. package/.github/workflows/prerelease.yml +3 -3
  2. package/.releaserc +10 -2
  3. package/.vscode/launch.json +10 -10
  4. package/.vscode/settings.json +9 -1
  5. package/.vscode/tasks.json +4 -4
  6. package/CMakeLists.txt +6 -1
  7. package/Cargo.toml +2 -2
  8. package/README.md +35 -41
  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 -80
  20. package/docs/benchmarks.md +26 -5
  21. package/docs/c/reference.rst +3 -3
  22. package/docs/compilation.md +31 -49
  23. package/docs/cpp/index.rst +1 -1
  24. package/docs/cpp/reference.rst +4 -4
  25. package/golang/lib.go +275 -141
  26. package/golang/lib_test.go +105 -0
  27. package/include/usearch/index.hpp +1681 -1656
  28. package/include/usearch/index_dense.hpp +1400 -0
  29. package/include/usearch/index_plugins.hpp +1263 -0
  30. package/java/README.md +1 -1
  31. package/java/cloud/unum/usearch/Index.java +10 -10
  32. package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +34 -37
  33. package/java/test/IndexTest.java +1 -1
  34. package/javascript/README.md +6 -6
  35. package/javascript/lib.cpp +156 -55
  36. package/javascript/test.js +26 -11
  37. package/javascript/usearch.d.ts +102 -0
  38. package/javascript/usearch.js +2 -118
  39. package/objc/USearchObjective.mm +57 -31
  40. package/objc/include/USearchObjective.h +32 -22
  41. package/package.json +5 -3
  42. package/python/README.md +23 -14
  43. package/python/lib.cpp +468 -444
  44. package/python/scripts/bench.ipynb +3 -2
  45. package/python/scripts/bench.py +4 -4
  46. package/python/scripts/index_faiss.py +5 -5
  47. package/python/scripts/join.py +4 -4
  48. package/python/scripts/test.py +152 -61
  49. package/python/scripts/test_jit.py +10 -12
  50. package/python/scripts/test_sparse.py +32 -0
  51. package/python/usearch/client.py +26 -28
  52. package/python/usearch/eval.py +73 -23
  53. package/python/usearch/index.py +520 -228
  54. package/python/usearch/io.py +57 -25
  55. package/python/usearch/numba.py +4 -4
  56. package/python/usearch/server.py +10 -10
  57. package/rust/lib.cpp +34 -30
  58. package/rust/lib.hpp +14 -12
  59. package/rust/lib.rs +8 -7
  60. package/setup.py +5 -2
  61. package/simsimd/.github/workflows/prerelease.yml +73 -0
  62. package/simsimd/.github/workflows/release.yml +110 -0
  63. package/simsimd/.github/workflows/update_version.sh +3 -0
  64. package/simsimd/.releaserc +77 -0
  65. package/simsimd/.vscode/launch.json +27 -1
  66. package/simsimd/.vscode/settings.json +22 -1
  67. package/simsimd/.vscode/tasks.json +6 -0
  68. package/simsimd/CMakeLists.txt +3 -2
  69. package/simsimd/README.md +82 -46
  70. package/simsimd/bench.cxx +63 -24
  71. package/simsimd/include/simsimd/simsimd.h +88 -66
  72. package/simsimd/include/simsimd/simsimd_chem.h +126 -0
  73. package/simsimd/package.json +8 -0
  74. package/simsimd/pyproject.toml +42 -0
  75. package/simsimd/python/python.c +81 -0
  76. package/simsimd/python/run.sh +1 -0
  77. package/simsimd/python/test.c +109 -0
  78. package/simsimd/python/test.py +23 -0
  79. package/simsimd/setup.py +44 -0
  80. package/swift/Index+Sugar.swift +75 -23
  81. package/swift/README.md +26 -2
  82. package/swift/Test.swift +19 -7
  83. package/swift/USearch.swift +2 -2
  84. package/tsconfig.json +8 -0
  85. package/wasm/CMakeLists.txt +1 -0
  86. package/wasmer.toml +1 -1
  87. package/wolfram/CMakeLists.txt +1 -0
  88. package/wolfram/lib.cpp +11 -13
  89. package/golang/usearch.h +0 -9
  90. package/golang/usearch_par_test.go +0 -40
  91. package/golang/usearch_test.go +0 -82
  92. package/include/usearch/index_punned_dense.hpp +0 -1001
  93. package/include/usearch/index_punned_helpers.hpp +0 -676
package/cpp/test.cpp CHANGED
@@ -3,8 +3,11 @@
3
3
  */
4
4
  #include <algorithm>
5
5
  #include <stdexcept>
6
+ #include <unordered_map>
6
7
 
7
- #include <usearch/index_punned_dense.hpp>
8
+ #include <usearch/index.hpp>
9
+ #include <usearch/index_dense.hpp>
10
+ #include <usearch/index_plugins.hpp>
8
11
 
9
12
  using namespace unum::usearch;
10
13
  using namespace unum;
@@ -14,94 +17,197 @@ void expect(bool must_be_true) {
14
17
  throw std::runtime_error("Failed!");
15
18
  }
16
19
 
17
- template <typename scalar_at, typename index_at> void test3d(index_at&& index) {
20
+ template <bool punned_ak, typename index_at, typename scalar_at, typename... extra_args_at>
21
+ void test_cosine(index_at& index, std::vector<std::vector<scalar_at>> const& vectors, extra_args_at&&... args) {
18
22
 
19
23
  using scalar_t = scalar_at;
20
- using view_t = span_gt<scalar_t const>;
21
- using index_t = typename std::remove_reference<index_at>::type;
24
+ using index_t = index_at;
25
+ using key_t = typename index_t::key_t;
22
26
  using distance_t = typename index_t::distance_t;
23
- using label_t = typename index_t::label_t;
24
27
 
25
- scalar_t vec[3] = {10, 20, 15};
26
- scalar_t vec_a[3] = {15, 16, 17};
27
- scalar_t vec_b[3] = {16, 17, 18};
28
+ // Generate some keys starting from end,
29
+ // for three vectors from the dataset
30
+ key_t const key_max = default_free_value<key_t>() - 1;
31
+ key_t const key_first = key_max - 0;
32
+ key_t const key_second = key_max - 1;
33
+ key_t const key_third = key_max - 2;
34
+ scalar_t const* vector_first = vectors[0].data();
35
+ scalar_t const* vector_second = vectors[1].data();
36
+ scalar_t const* vector_third = vectors[2].data();
37
+ std::size_t dimensions = vectors[0].size();
28
38
 
29
39
  index.reserve(10);
30
- index.add(42, view_t{&vec[0], 3ul});
40
+ index.add(key_first, vector_first, args...);
31
41
 
32
42
  // Default approximate search
33
- label_t matched_labels[10] = {0};
43
+ key_t matched_labels[10] = {0};
34
44
  distance_t matched_distances[10] = {0};
35
- std::size_t matched_count = index.search(view_t{&vec[0], 3ul}, 5).dump_to(matched_labels, matched_distances);
45
+ std::size_t matched_count = index.search(vector_first, 5, args...).dump_to(matched_labels, matched_distances);
36
46
 
37
47
  expect(matched_count == 1);
38
- expect(matched_labels[0] == 42);
48
+ expect(matched_labels[0] == key_first);
39
49
  expect(std::abs(matched_distances[0]) < 0.01);
40
50
 
41
51
  // Add more entries
42
- search_config_t search_config;
52
+ index_search_config_t search_config;
43
53
  search_config.exact = true;
44
- index.add(43, view_t{&vec_a[0], 3ul});
45
- index.add(44, view_t{&vec_b[0], 3ul});
54
+ index.add(key_second, vector_second, args...);
55
+ index.add(key_third, vector_third, args...);
46
56
  expect(index.size() == 3);
47
57
 
48
58
  // Perform exact search
49
- matched_count = index.search(view_t{&vec[0], 3ul}, 5, search_config).dump_to(matched_labels, matched_distances);
59
+ matched_count = index.search(vector_first, 5, args..., search_config).dump_to(matched_labels, matched_distances);
50
60
 
51
61
  // Validate scans
52
62
  std::size_t count = 0;
53
63
  for (auto member : index) {
54
- label_t id = member.label;
55
- expect(id >= 42 && id <= 44);
64
+ key_t id = member.key;
65
+ expect(id <= key_first && id >= key_third);
56
66
  count++;
57
67
  }
58
68
  expect((count == 3));
59
69
  expect((index.stats(0).nodes == 3));
60
70
 
71
+ // Try removals and replacements
72
+ if constexpr (punned_ak) {
73
+ using labeling_result_t = typename index_t::labeling_result_t;
74
+ labeling_result_t result = index.remove(key_third);
75
+ expect(bool(result));
76
+ expect(index.size() == 2);
77
+ index.add(key_third, vector_third, args...);
78
+ expect(index.size() == 3);
79
+ }
80
+
61
81
  // Search again over reconstructed index
62
82
  index.save("tmp.usearch");
63
83
  index.load("tmp.usearch");
64
- matched_count = index.search(view_t{&vec[0], 3ul}, 5).dump_to(matched_labels, matched_distances);
84
+ matched_count = index.search(vector_first, 5, args...).dump_to(matched_labels, matched_distances);
65
85
  expect(matched_count == 3);
66
- expect(matched_labels[0] == 42);
86
+ expect(matched_labels[0] == key_first);
67
87
  expect(std::abs(matched_distances[0]) < 0.01);
68
88
 
89
+ if constexpr (punned_ak) {
90
+ std::vector<scalar_t> vec_recovered_from_load(dimensions);
91
+ index.get(key_second, vec_recovered_from_load.data());
92
+ expect(std::equal(vector_second, vector_second + dimensions, vec_recovered_from_load.data()));
93
+ }
94
+
95
+ // Try batch requests
96
+ executor_default_t executor;
97
+ index.reserve({vectors.size(), executor.size()});
98
+ executor.execute_bulk(vectors.size() - 3, [&](std::size_t thread, std::size_t task) {
99
+ index_update_config_t config;
100
+ config.thread = thread;
101
+ index.add(key_max - task - 3, vectors[task + 3].data(), args..., config);
102
+ });
103
+
69
104
  // Search again over mapped index
70
- file_head_result_t head = index_metadata("tmp.usearch");
71
- expect(head.size == 3);
105
+ // file_head_result_t head = index_dense_metadata("tmp.usearch");
106
+ // expect(head.size == 3);
72
107
  index.view("tmp.usearch");
73
- matched_count = index.search(view_t{&vec[0], 3ul}, 5).dump_to(matched_labels, matched_distances);
108
+ matched_count = index.search(vector_first, 5, args...).dump_to(matched_labels, matched_distances);
74
109
  expect(matched_count == 3);
75
- expect(matched_labels[0] == 42);
110
+ expect(matched_labels[0] == key_first);
76
111
  expect(std::abs(matched_distances[0]) < 0.01);
77
112
 
113
+ if constexpr (punned_ak) {
114
+ std::vector<scalar_t> vec_recovered_from_view(dimensions);
115
+ index.get(key_second, vec_recovered_from_view.data());
116
+ expect(std::equal(vector_second, vector_second + dimensions, vec_recovered_from_view.data()));
117
+
118
+ auto compaction_result = index.compact();
119
+ expect(bool(compaction_result));
120
+ }
121
+
78
122
  expect(index.memory_usage() > 0);
79
123
  expect(index.stats().max_edges > 0);
124
+
125
+ // Check metadata
126
+ if constexpr (punned_ak) {
127
+ index_dense_metadata_result_t meta = index_dense_metadata("tmp.usearch");
128
+ expect(bool(meta));
129
+ }
80
130
  }
81
131
 
82
- template <typename scalar_at, typename index_at> void test3d_punned(index_at&& index) {
132
+ template <typename scalar_at, typename key_at, typename slot_at> //
133
+ void test_cosine(std::size_t collection_size, std::size_t dimensions) {
83
134
 
84
135
  using scalar_t = scalar_at;
85
- using view_t = span_gt<scalar_t const>;
86
- using span_t = span_gt<scalar_at>;
136
+ using key_t = key_at;
137
+ using slot_t = slot_at;
87
138
 
88
- scalar_t vec42[3] = {10, 20, 15};
89
- scalar_t vec43[3] = {19, 22, 11};
139
+ using index_typed_t = index_gt<float, key_t, slot_t>;
140
+ using member_cref_t = typename index_typed_t::member_cref_t;
141
+ using member_citerator_t = typename index_typed_t::member_citerator_t;
90
142
 
91
- index.reserve(10);
92
- index.add(42, view_t{&vec42[0], 3ul});
93
-
94
- // Reconstruct
95
- scalar_t vec42_reconstructed[3] = {0, 0, 0};
96
- index.get(42, span_t{&vec42_reconstructed[0], 3ul});
97
- expect(vec42_reconstructed[0] == vec42[0]);
98
- expect(vec42_reconstructed[1] == vec42[1]);
99
- expect(vec42_reconstructed[2] == vec42[2]);
100
-
101
- index.add(43, view_t{&vec43[0], 3ul});
102
- expect(index.size() == 2);
103
- index.remove(43);
104
- expect(index.size() == 1);
143
+ std::vector<std::vector<scalar_at>> matrix(collection_size);
144
+ for (std::vector<scalar_at>& vector : matrix) {
145
+ vector.resize(dimensions);
146
+ std::generate(vector.begin(), vector.end(), [=] { return float(std::rand()) / float(INT_MAX); });
147
+ }
148
+
149
+ struct metric_t {
150
+ std::vector<std::vector<scalar_at>> const* matrix_ptr;
151
+ std::size_t dimensions;
152
+
153
+ scalar_t const* row(std::size_t i) const noexcept { return (*matrix_ptr)[i].data(); }
154
+
155
+ float operator()(member_cref_t const& a, member_cref_t const& b) const {
156
+ return metric_cos_gt<scalar_t>{}(row(get_slot(b)), row(get_slot(a)), dimensions);
157
+ }
158
+ float operator()(scalar_t const* some_vector, member_cref_t const& member) const {
159
+ return metric_cos_gt<scalar_t>{}(some_vector, row(get_slot(member)), dimensions);
160
+ }
161
+ float operator()(member_citerator_t const& a, member_citerator_t const& b) const {
162
+ return metric_cos_gt<scalar_t>{}(row(get_slot(b)), row(get_slot(a)), dimensions);
163
+ }
164
+ float operator()(scalar_t const* some_vector, member_citerator_t const& member) const {
165
+ return metric_cos_gt<scalar_t>{}(some_vector, row(get_slot(member)), dimensions);
166
+ }
167
+ };
168
+
169
+ // Template:
170
+ for (std::size_t connectivity : {3, 13, 50}) {
171
+ std::printf("- templates with connectivity %zu \n", connectivity);
172
+ metric_t metric{&matrix, dimensions};
173
+ index_config_t config(connectivity);
174
+ index_typed_t index_typed(config);
175
+ test_cosine<false>(index_typed, matrix, metric);
176
+ }
177
+
178
+ // Type-punned:
179
+ for (std::size_t connectivity : {3, 13, 50}) {
180
+ std::printf("- punned with connectivity %zu \n", connectivity);
181
+ using index_t = index_dense_gt<key_t, slot_t>;
182
+ metric_punned_t metric(dimensions, metric_kind_t::cos_k, scalar_kind<scalar_at>());
183
+ index_config_t config(connectivity);
184
+ index_t index = index_t::make(metric, config);
185
+ test_cosine<true>(index, matrix);
186
+ }
187
+ }
188
+
189
+ template <typename key_at, typename slot_at> void test_tanimoto(std::size_t dimensions, std::size_t connectivity) {
190
+
191
+ using key_t = key_at;
192
+ using slot_t = slot_at;
193
+
194
+ using index_punned_t = index_dense_gt<key_t, slot_t>;
195
+ std::size_t words = divide_round_up<CHAR_BIT>(dimensions);
196
+ metric_punned_t metric(words, metric_kind_t::tanimoto_k, scalar_kind_t::b1x8_k);
197
+ index_config_t config(connectivity);
198
+ index_punned_t index = index_punned_t::make(metric, config);
199
+
200
+ executor_default_t executor;
201
+ std::size_t batch_size = 1000;
202
+ std::vector<b1x8_t> scalars(batch_size * index.scalar_words());
203
+ std::generate(scalars.begin(), scalars.end(), [] { return static_cast<b1x8_t>(std::rand()); });
204
+
205
+ index.reserve({batch_size + index.size(), executor.size()});
206
+ executor.execute_bulk(batch_size, [&](std::size_t thread, std::size_t task) {
207
+ index_update_config_t config;
208
+ config.thread = thread;
209
+ index.add(task + 25000, scalars.data() + index.scalar_words() * task, config);
210
+ });
105
211
  }
106
212
 
107
213
  template <typename index_at> void test_sets(index_at&& index) {
@@ -122,18 +228,18 @@ template <typename index_at> void test_sets(index_at&& index) {
122
228
  expect(index.size() == 3);
123
229
  }
124
230
 
125
- template <typename index_at> void test_sets_moved() {
231
+ template <typename index_at> void test_sets_moved(index_config_t const& config) {
126
232
  {
127
- index_at index;
233
+ index_at index{config};
128
234
  test_sets(index);
129
235
  }
130
236
  {
131
- index_at index;
237
+ index_at index{config};
132
238
  index.reserve(1);
133
239
  test_sets(index_at(std::move(index)));
134
240
  }
135
241
  {
136
- index_at index;
242
+ index_at index{config};
137
243
  index.reserve(1);
138
244
  index_at index_moved = std::move(index);
139
245
  test_sets(index_moved);
@@ -142,39 +248,17 @@ template <typename index_at> void test_sets_moved() {
142
248
 
143
249
  int main(int, char**) {
144
250
 
145
- static_assert(!std::is_same<index_gt<ip_gt<>>::value_type, std::true_type>());
146
- static_assert(!std::is_same<index_gt<cos_gt<>>::value_type, std::true_type>());
147
- static_assert(!std::is_same<index_gt<l2sq_gt<>>::value_type, std::true_type>());
148
-
149
- static_assert(has_reset<memory_mapping_allocator_t>());
150
- // static_assert(!std::is_same<index_gt<hamming_gt<>>::value_type, std::true_type>());
151
- // static_assert(!std::is_same<index_gt<tanimoto_gt<>>::value_type, std::true_type>());
152
- // static_assert(!std::is_same<index_gt<sorensen_gt<>>::value_type, std::true_type>());
153
- // static_assert(!std::is_same<index_gt<jaccard_gt<>>::value_type, std::true_type>());
154
- // static_assert(!std::is_same<index_gt<pearson_correlation_gt<>>::value_type, std::true_type>());
155
- // static_assert(!std::is_same<index_gt<haversine_gt<>>::value_type, std::true_type>());
156
-
157
- using big_point_id_t = std::int64_t;
158
- test3d<float>(index_gt<cos_gt<float>, big_point_id_t, std::uint32_t>{});
159
- test3d<float>(index_gt<l2sq_gt<float>, big_point_id_t, std::uint32_t>{});
160
-
161
- test3d<double>(index_gt<cos_gt<double>, big_point_id_t, std::uint32_t>{});
162
- test3d<double>(index_gt<l2sq_gt<double>, big_point_id_t, std::uint32_t>{});
163
-
164
- test3d<float>(punned_small_t::make(3, metric_kind_t::cos_k));
165
- test3d<float>(punned_small_t::make(3, metric_kind_t::l2sq_k));
166
-
167
- test3d<double>(punned_small_t::make(3, metric_kind_t::cos_k));
168
- test3d<double>(punned_small_t::make(3, metric_kind_t::l2sq_k));
169
-
170
- test3d_punned<float>(punned_small_t::make(3, metric_kind_t::cos_k));
171
- test3d_punned<float>(punned_small_t::make(3, metric_kind_t::l2sq_k));
172
-
173
- test_sets(index_gt<jaccard_gt<std::int32_t, float>, big_point_id_t, std::uint32_t>{});
174
- test_sets(index_gt<jaccard_gt<std::int64_t, float>, big_point_id_t, std::uint32_t>{});
175
-
176
- test_sets_moved<index_gt<jaccard_gt<std::int32_t, float>, big_point_id_t, std::uint32_t>>();
177
- test_sets_moved<index_gt<jaccard_gt<std::int64_t, float>, big_point_id_t, std::uint32_t>>();
251
+ for (std::size_t collection_size : {10, 500})
252
+ for (std::size_t dimensions : {97, 256}) {
253
+ std::printf("Indexing %zu vectors with cos: <float, std::int64_t, std::uint32_t> \n", collection_size);
254
+ test_cosine<float, std::int64_t, std::uint32_t>(collection_size, dimensions);
255
+ std::printf("Indexing %zu vectors with cos: <float, std::int64_t, uint40_t> \n", collection_size);
256
+ test_cosine<float, std::int64_t, uint40_t>(collection_size, dimensions);
257
+ }
258
+
259
+ for (std::size_t connectivity : {3, 13, 50})
260
+ for (std::size_t dimensions : {97, 256})
261
+ test_tanimoto<std::int64_t, std::uint32_t>(dimensions, connectivity);
178
262
 
179
263
  return 0;
180
264
  }
@@ -39,24 +39,24 @@ The main columns are:
39
39
  | `f32` x256 | 16 | 64 | 32 | 128'644 | 228'422 | 97.2% |
40
40
  | `f32` x256 | 16 | 256 | 128 | 39'981 | 69'065 | 99.2% |
41
41
 
42
- ### Different vectors "accuracy"
42
+ ### Different vectors "quantization"
43
43
 
44
44
  | Vectors | Connectivity | EF @ A | EF @ S | **Add**, QPS | **Search**, QPS | **Recall @1** |
45
45
  | :----------- | :----------: | :----: | :----: | :----------: | :-------------: | ------------: |
46
46
  | `f32` x256 | 16 | 128 | 64 | 87'995 | 171'856 | 99.1% |
47
47
  | `f16` x256 | 16 | 128 | 64 | 87'270 | 153'788 | 98.4% |
48
48
  | `f16` x256 ✳️ | 16 | 128 | 64 | 71'454 | 132'673 | 98.4% |
49
- | `f8` x256 | 16 | 128 | 64 | 115'923 | 274'653 | 98.9% |
49
+ | `i8` x256 | 16 | 128 | 64 | 115'923 | 274'653 | 98.9% |
50
50
 
51
- As seen on the chart, for `f16` accuracy, performance may differ depending on native hardware support for that numeric type.
52
- Also worth noting, 8-bit quantization results in almost no accuracy loss and may perform better than `f16`.
51
+ As seen on the chart, for `f16` quantization, performance may differ depending on native hardware support for that numeric type.
52
+ Also worth noting, 8-bit quantization results in almost no quantization loss and may perform better than `f16`.
53
53
 
54
54
  ## Utilities
55
55
 
56
56
  Within this repository you will find two commonly used utilities:
57
57
 
58
58
  - `cpp/bench.cpp` the produces the `bench` binary for broad USearch benchmarks.
59
- - `python/bench.py` for simple benchmarks against FAISS.
59
+ - `python/bench.py` and `python/bench.ipynb` for interactive charts against FAISS.
60
60
 
61
61
  To achieve best highest results we suggest compiling locally for the target architecture.
62
62
 
@@ -112,6 +112,27 @@ OPTIONS
112
112
  -h, --help Print this help information on this tool and exit
113
113
  ```
114
114
 
115
+ Here is an example of running the C++ benchmark:
116
+
117
+ ```sh
118
+ ./build_release/bench \
119
+ --vectors datasets/wiki_1M/base.1M.fbin \
120
+ --queries datasets/wiki_1M/query.public.100K.fbin \
121
+ --neighbors datasets/wiki_1M/groundtruth.public.100K.ibin
122
+
123
+ ./build_release/bench \
124
+ --vectors datasets/t2i_1B/base.1B.fbin \
125
+ --queries datasets/t2i_1B/query.public.100K.fbin \
126
+ --neighbors datasets/t2i_1B/groundtruth.public.100K.ibin \
127
+ --output datasets/t2i_1B/index.usearch \
128
+ --cos
129
+ ```
130
+
131
+
132
+ > Optional parameters include `connectivity`, `expansion_add`, `expansion_search`.
133
+
134
+ For Python, jut open the Jupyter Notebook and start playing around.
135
+
115
136
  ## Datasets
116
137
 
117
138
  BigANN benchmark is a good starting point, if you are searching for large collections of high-dimensional vectors.
@@ -1,7 +1,7 @@
1
1
  API Reference
2
2
  ===============
3
3
 
4
- ===============
5
- usearch
6
- ===============
4
+ ==================
5
+ usearch/usearch.h
6
+ ==================
7
7
  .. doxygenfile:: usearch.h
@@ -44,10 +44,10 @@ cmake -B ./build_release \
44
44
  Linting:
45
45
 
46
46
  ```sh
47
- cppcheck --enable=all --suppress=cstyleCast --suppress=unusedFunction \
47
+ cppcheck --enable=all --force --suppress=cstyleCast --suppress=unusedFunction \
48
48
  include/usearch/index.hpp \
49
- include/index_punned_dense.hpp \
50
- include/index_punned_helpers.hpp
49
+ include/index_dense.hpp \
50
+ include/index_plugins.hpp
51
51
  ```
52
52
 
53
53
  Testing:
@@ -56,22 +56,6 @@ Testing:
56
56
  cmake -DCMAKE_CXX_COMPILER=gcc-12 -DCMAKE_CXX_COMPILER=g++-12 -DCMAKE_BUILD_TYPE=Debug -B ./build_debug && make -C ./build_debug && ./build_debug/test
57
57
  ```
58
58
 
59
- Benchmarking:
60
-
61
- ```sh
62
- ./build_release/bench \
63
- --vectors datasets/wiki_1M/base.1M.fbin \
64
- --queries datasets/wiki_1M/query.public.100K.fbin \
65
- --neighbors datasets/wiki_1M/groundtruth.public.100K.ibin
66
-
67
- ./build_release/bench \
68
- --vectors datasets/t2i_1B/base.1B.fbin \
69
- --queries datasets/t2i_1B/query.public.100K.fbin \
70
- --neighbors datasets/t2i_1B/groundtruth.public.100K.ibin \
71
- --output datasets/t2i_1B/index.usearch \
72
- --cos
73
- ```
74
-
75
59
  ## Python 3
76
60
 
77
61
  Use PyTest to validate the build.
@@ -96,25 +80,6 @@ pip install cibuildwheel
96
80
  cibuildwheel --platform linux
97
81
  ```
98
82
 
99
- Benchmarking:
100
-
101
- ```sh
102
- pip install faiss-cpu
103
- python python/scripts/bench.py speed \
104
- --vectors datasets/wiki_1M/base.1M.fbin \
105
- --queries datasets/wiki_1M/query.public.100K.fbin \
106
- --neighbors datasets/wiki_1M/groundtruth.public.100K.ibin
107
- ```
108
-
109
- > Optional parameters include `connectivity`, `expansion_add`, `expansion_search`.
110
-
111
- Checking the effect of different embedding dimensions on construction speed:
112
-
113
- ```sh
114
- python python/scripts/bench.py dimensions ...
115
- python python/scripts/bench.py connectivity ...
116
- ```
117
-
118
83
  ## JavaScript
119
84
 
120
85
  Node.JS:
@@ -178,34 +143,51 @@ java -cp . -Djava.library.path="$(pwd)/java/cloud/unum/usearch/" Index.java
178
143
  java -cp . -Djava.library.path="$(pwd)/java" cloud.unum.usearch.Index
179
144
  ```
180
145
 
181
- ## Wolfram
146
+ ## Objective-C and Swift
182
147
 
183
148
  ```sh
184
- brew install --cask wolfram-engine
149
+ swift build
150
+ swift test -v
185
151
  ```
186
152
 
187
- ## GoLang
153
+ ## C 99
154
+
155
+ There are a few ways to compile the C 99 USearch SDK.
156
+ Using the Makefile:
188
157
 
189
158
  ```sh
190
- cd golang
191
- go test -v
159
+ make -C ./c build
192
160
  ```
193
161
 
194
- ## Objective-C and Swift
162
+ Using CMake:
195
163
 
196
164
  ```sh
197
- swift build
198
- swift test -v
165
+ cmake -B ./build_release -DUSEARCH_BUILD_C=1 && make -C ./build_release -j
199
166
  ```
200
167
 
201
- ## C99
202
-
203
168
  Linux:
204
169
 
205
170
  ```sh
206
- g++ -shared -fPIC lib.cpp -I ../include/ -I ../fp16/include/ -o libusearch.so
171
+ g++ -std=c++11 -shared -fPIC c/lib.cpp -I ./include/ -I ./fp16/include/ -I ./robin-map/include/ -o libusearch.so
207
172
  ```
208
173
 
174
+
175
+ ## GoLang
176
+
177
+ GoLang bindings are based on C.
178
+ So one should first compile the C library, link it with GoLang, and only then run tests.
179
+
180
+ ```sh
181
+ cd golang && make -C ../c build && mv ../c/libusearch.so libusearch.so && go test -v
182
+ ```
183
+
184
+ ## Wolfram
185
+
186
+ ```sh
187
+ brew install --cask wolfram-engine
188
+ ```
189
+
190
+
209
191
  ## Docker
210
192
 
211
193
  ```sh
@@ -1,5 +1,5 @@
1
1
  =====================
2
- USearch for C++
2
+ C++ SDK
3
3
  =====================
4
4
 
5
5
 
@@ -7,11 +7,11 @@ usearch/index.hpp
7
7
  .. doxygenfile:: index.hpp
8
8
 
9
9
  =================================
10
- usearch/index_punned_helpers.hpp
10
+ usearch/index_plugins.hpp
11
11
  =================================
12
- .. doxygenfile:: index_punned_helpers.hpp
12
+ .. doxygenfile:: index_plugins.hpp
13
13
 
14
14
  =================================
15
- usearch/index_punned_dense.hpp
15
+ usearch/index_dense.hpp
16
16
  =================================
17
- .. doxygenfile:: index_punned_dense.hpp
17
+ .. doxygenfile:: index_dense.hpp