usearch 0.4.0 → 0.8.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 (44) hide show
  1. package/.clang-tidy +60 -0
  2. package/.github/workflows/release.yml +42 -16
  3. package/.github/workflows/update_version.sh +1 -0
  4. package/.vscode/launch.json +22 -0
  5. package/.vscode/settings.json +5 -0
  6. package/.vscode/tasks.json +4 -4
  7. package/CITATION.cff +11 -0
  8. package/CMakeLists.txt +108 -95
  9. package/Cargo.toml +1 -1
  10. package/Dockerfile +14 -0
  11. package/README.md +8 -7
  12. package/VERSION +1 -1
  13. package/binding.gyp +2 -2
  14. package/build.rs +2 -2
  15. package/cmake/config.cmake.in +15 -0
  16. package/cmake/pkg-config.pc.in +4 -0
  17. package/cmake/usearchConfigVersion.cmake.in +20 -0
  18. package/conanfile.py +1 -1
  19. package/docs/benchmarks.md +11 -2
  20. package/docs/{Compilation.md → compilation.md} +54 -27
  21. package/include/usearch/usearch.hpp +664 -390
  22. package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +17 -16
  23. package/javascript/lib.cpp +13 -13
  24. package/javascript/test.js +1 -1
  25. package/objc/USearchObjective.mm +46 -29
  26. package/objc/include/USearchObjective.h +18 -26
  27. package/package.json +1 -1
  28. package/pyproject.toml +3 -2
  29. package/python/lib.cpp +179 -120
  30. package/python/{bench.py → scripts/bench.py} +6 -1
  31. package/python/scripts/bench_params.py +112 -0
  32. package/python/{test.py → scripts/test.py} +32 -13
  33. package/python/usearch/client.py +100 -14
  34. package/python/usearch/server.py +104 -23
  35. package/rust/lib.cpp +15 -14
  36. package/rust/lib.hpp +5 -5
  37. package/rust/lib.rs +3 -3
  38. package/setup.py +7 -0
  39. package/src/CMakeLists.txt +107 -0
  40. package/src/bench.cpp +45 -15
  41. package/src/{advanced.hpp → punned.hpp} +227 -199
  42. package/src/test.cpp +62 -0
  43. package/swift/Test.swift +1 -1
  44. package/wolfram/lib.cpp +14 -14
@@ -4,14 +4,14 @@
4
4
 
5
5
  #include <thread>
6
6
 
7
- #include "advanced.hpp"
7
+ #include "punned.hpp"
8
8
 
9
9
  using namespace unum::usearch;
10
10
  using namespace unum;
11
11
 
12
12
  using label_t = jint;
13
13
  using distance_t = punned_distance_t;
14
- using native_index_t = auto_index_gt<label_t>;
14
+ using punned_t = punned_gt<label_t>;
15
15
  using span_t = span_gt<float>;
16
16
 
17
17
  JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1create( //
@@ -39,10 +39,10 @@ JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1create( //
39
39
  std::size_t accuracy_length = (*env).GetStringUTFLength(accuracy);
40
40
 
41
41
  accuracy_t accuracy = accuracy_from_name(accuracy_cstr, accuracy_length);
42
- native_index_t index = index_from_name<native_index_t>( //
42
+ punned_t index = index_from_name<punned_t>( //
43
43
  metric_cstr, metric_length, static_cast<std::size_t>(dimensions), accuracy, config);
44
44
 
45
- native_index_t* result_ptr = new native_index_t(std::move(index));
45
+ punned_t* result_ptr = new punned_t(std::move(index));
46
46
  std::memcpy(&result, &result_ptr, sizeof(jlong));
47
47
  } catch (...) {
48
48
  jclass jc = (*env).FindClass("java/lang/Error");
@@ -59,7 +59,7 @@ JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1save(JNIEnv* env, jclass
59
59
  char const* path_cstr{};
60
60
  try {
61
61
  path_cstr = (*env).GetStringUTFChars(path, 0);
62
- reinterpret_cast<native_index_t*>(c_ptr)->save(path_cstr);
62
+ reinterpret_cast<punned_t*>(c_ptr)->save(path_cstr);
63
63
  } catch (...) {
64
64
  jclass jc = (*env).FindClass("java/lang/Error");
65
65
  if (jc)
@@ -72,7 +72,7 @@ JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1load(JNIEnv* env, jclass
72
72
  char const* path_cstr{};
73
73
  try {
74
74
  path_cstr = (*env).GetStringUTFChars(path, 0);
75
- reinterpret_cast<native_index_t*>(c_ptr)->load(path_cstr);
75
+ reinterpret_cast<punned_t*>(c_ptr)->load(path_cstr);
76
76
  } catch (...) {
77
77
  jclass jc = (*env).FindClass("java/lang/Error");
78
78
  if (jc)
@@ -85,7 +85,7 @@ JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1view(JNIEnv* env, jclass
85
85
  char const* path_cstr{};
86
86
  try {
87
87
  path_cstr = (*env).GetStringUTFChars(path, 0);
88
- reinterpret_cast<native_index_t*>(c_ptr)->view(path_cstr);
88
+ reinterpret_cast<punned_t*>(c_ptr)->view(path_cstr);
89
89
  } catch (...) {
90
90
  jclass jc = (*env).FindClass("java/lang/Error");
91
91
  if (jc)
@@ -95,28 +95,28 @@ JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1view(JNIEnv* env, jclass
95
95
  }
96
96
 
97
97
  JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1destroy(JNIEnv*, jclass, jlong c_ptr) {
98
- delete reinterpret_cast<native_index_t*>(c_ptr);
98
+ delete reinterpret_cast<punned_t*>(c_ptr);
99
99
  }
100
100
 
101
101
  JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1size(JNIEnv*, jclass, jlong c_ptr) {
102
- return reinterpret_cast<native_index_t*>(c_ptr)->size();
102
+ return reinterpret_cast<punned_t*>(c_ptr)->size();
103
103
  }
104
104
 
105
105
  JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1connectivity(JNIEnv*, jclass, jlong c_ptr) {
106
- return reinterpret_cast<native_index_t*>(c_ptr)->connectivity();
106
+ return reinterpret_cast<punned_t*>(c_ptr)->connectivity();
107
107
  }
108
108
 
109
109
  JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1dimensions(JNIEnv*, jclass, jlong c_ptr) {
110
- return reinterpret_cast<native_index_t*>(c_ptr)->dimensions();
110
+ return reinterpret_cast<punned_t*>(c_ptr)->dimensions();
111
111
  }
112
112
 
113
113
  JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1capacity(JNIEnv*, jclass, jlong c_ptr) {
114
- return reinterpret_cast<native_index_t*>(c_ptr)->capacity();
114
+ return reinterpret_cast<punned_t*>(c_ptr)->capacity();
115
115
  }
116
116
 
117
117
  JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1reserve(JNIEnv* env, jclass, jlong c_ptr, jlong capacity) {
118
118
  try {
119
- return reinterpret_cast<native_index_t*>(c_ptr)->reserve(static_cast<std::size_t>(capacity));
119
+ return reinterpret_cast<punned_t*>(c_ptr)->reserve(static_cast<std::size_t>(capacity));
120
120
  } catch (...) {
121
121
  jclass jc = (*env).FindClass("java/lang/Error");
122
122
  if (jc)
@@ -132,7 +132,7 @@ JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1add( //
132
132
  vector_data = (*env).GetFloatArrayElements(vector, 0);
133
133
  jsize vector_dims = (*env).GetArrayLength(vector);
134
134
  span_t vector_span = span_t{vector_data, static_cast<std::size_t>(vector_dims)};
135
- reinterpret_cast<native_index_t*>(c_ptr)->add(label, vector_span);
135
+ reinterpret_cast<punned_t*>(c_ptr)->add(label, vector_span);
136
136
  } catch (...) {
137
137
  jclass jc = (*env).FindClass("java/lang/Error");
138
138
  if (jc)
@@ -159,8 +159,9 @@ JNIEXPORT jintArray JNICALL Java_cloud_unum_usearch_Index_c_1search( //
159
159
  vector_data = (*env).GetFloatArrayElements(vector, 0);
160
160
  jsize vector_dims = (*env).GetArrayLength(vector);
161
161
  span_t vector_span = span_t{vector_data, static_cast<std::size_t>(vector_dims)};
162
- found = reinterpret_cast<native_index_t*>(c_ptr)->search( //
163
- vector_span, static_cast<std::size_t>(wanted), matches_data, NULL);
162
+ found = reinterpret_cast<punned_t*>(c_ptr)
163
+ ->search(vector_span, static_cast<std::size_t>(wanted))
164
+ .dump_to(matches_data, NULL);
164
165
  (*env).SetIntArrayRegion(matches, 0, found, matches_data);
165
166
  } catch (...) {
166
167
  jclass jc = (*env).FindClass("java/lang/Error");
@@ -20,14 +20,14 @@
20
20
  #include <napi.h>
21
21
  #include <node_api.h>
22
22
 
23
- #include "advanced.hpp"
23
+ #include "punned.hpp"
24
24
 
25
25
  using namespace unum::usearch;
26
26
  using namespace unum;
27
27
 
28
28
  using label_t = std::uint32_t;
29
29
  using distance_t = punned_distance_t;
30
- using native_index_t = auto_index_gt<label_t>;
30
+ using punned_t = punned_gt<label_t>;
31
31
 
32
32
  class Index : public Napi::ObjectWrap<Index> {
33
33
  public:
@@ -47,7 +47,7 @@ class Index : public Napi::ObjectWrap<Index> {
47
47
  void Add(Napi::CallbackInfo const& ctx);
48
48
  Napi::Value Search(Napi::CallbackInfo const& ctx);
49
49
 
50
- std::unique_ptr<native_index_t> native_;
50
+ std::unique_ptr<punned_t> native_;
51
51
  };
52
52
 
53
53
  Napi::Object Index::Init(Napi::Env env, Napi::Object exports) {
@@ -79,7 +79,7 @@ Index::Index(Napi::CallbackInfo const& ctx) : Napi::ObjectWrap<Index>(ctx) {
79
79
  int length = ctx.Length();
80
80
  if (length == 0 || length >= 2 || !ctx[0].IsObject()) {
81
81
  Napi::TypeError::New(
82
- env, "Pass args as named objects: dimensions: uint, capacity: uint, metric: [ip, cos, l2_sq, haversine]")
82
+ env, "Pass args as named objects: dimensions: uint, capacity: uint, metric: [ip, cos, l2sq, haversine]")
83
83
  .ThrowAsJavaScriptException();
84
84
  return;
85
85
  }
@@ -105,7 +105,7 @@ Index::Index(Napi::CallbackInfo const& ctx) : Napi::ObjectWrap<Index>(ctx) {
105
105
  else if (accuracy_str == "f8")
106
106
  accuracy = accuracy_t::f8_k;
107
107
  else {
108
- Napi::TypeError::New(env, "Supported metrics are: [ip, cos, l2_sq, haversine]")
108
+ Napi::TypeError::New(env, "Supported metrics are: [ip, cos, l2sq, haversine]")
109
109
  .ThrowAsJavaScriptException();
110
110
  return;
111
111
  }
@@ -114,28 +114,28 @@ Index::Index(Napi::CallbackInfo const& ctx) : Napi::ObjectWrap<Index>(ctx) {
114
114
  // By default we use the Inner Product similarity
115
115
  if (params.Has("metric")) {
116
116
  std::string name = params.Get("metric").As<Napi::String>().Utf8Value();
117
- if (name == "l2_sq" || name == "euclidean_sq") {
117
+ if (name == "l2sq" || name == "euclidean_sq") {
118
118
  if (!dimensions) {
119
119
  Napi::TypeError::New(env, "Please define the number of dimensions").ThrowAsJavaScriptException();
120
120
  return;
121
121
  }
122
- native_.reset(new native_index_t(native_index_t::l2(dimensions, accuracy, config)));
122
+ native_.reset(new punned_t(punned_t::l2sq(dimensions, accuracy, config)));
123
123
  } else if (name == "ip" || name == "inner" || name == "dot") {
124
124
  if (!dimensions) {
125
125
  Napi::TypeError::New(env, "Please define the number of dimensions").ThrowAsJavaScriptException();
126
126
  return;
127
127
  }
128
- native_.reset(new native_index_t(native_index_t::ip(dimensions, accuracy, config)));
128
+ native_.reset(new punned_t(punned_t::ip(dimensions, accuracy, config)));
129
129
  } else if (name == "cos" || name == "angular") {
130
130
  if (!dimensions) {
131
131
  Napi::TypeError::New(env, "Please define the number of dimensions").ThrowAsJavaScriptException();
132
132
  return;
133
133
  }
134
- native_.reset(new native_index_t(native_index_t::cos(dimensions, accuracy, config)));
134
+ native_.reset(new punned_t(punned_t::cos(dimensions, accuracy, config)));
135
135
  } else if (name == "haversine") {
136
- native_.reset(new native_index_t(native_index_t::haversine(accuracy, config)));
136
+ native_.reset(new punned_t(punned_t::haversine(accuracy, config)));
137
137
  } else {
138
- Napi::TypeError::New(env, "Supported metrics are: [ip, cos, l2_sq, haversine]")
138
+ Napi::TypeError::New(env, "Supported metrics are: [ip, cos, l2sq, haversine]")
139
139
  .ThrowAsJavaScriptException();
140
140
  return;
141
141
  }
@@ -144,7 +144,7 @@ Index::Index(Napi::CallbackInfo const& ctx) : Napi::ObjectWrap<Index>(ctx) {
144
144
  Napi::TypeError::New(env, "Please define the number of dimensions").ThrowAsJavaScriptException();
145
145
  return;
146
146
  }
147
- native_.reset(new native_index_t(native_index_t::ip(dimensions, accuracy, config)));
147
+ native_.reset(new punned_t(punned_t::ip(dimensions, accuracy, config)));
148
148
  }
149
149
  }
150
150
 
@@ -258,7 +258,7 @@ Napi::Value Index::Search(Napi::CallbackInfo const& ctx) {
258
258
  Napi::Uint32Array matches_js = Napi::Uint32Array::New(env, wanted);
259
259
  Napi::Float32Array distances_js = Napi::Float32Array::New(env, wanted);
260
260
  try {
261
- std::size_t count = native_->search(vector, wanted, matches_js.Data(), distances_js.Data());
261
+ std::size_t count = native_->search(vector, wanted).dump_to(matches_js.Data(), distances_js.Data());
262
262
  Napi::Object result_js = Napi::Object::New(env);
263
263
  result_js.Set("labels", matches_js);
264
264
  result_js.Set("distances", distances_js);
@@ -1,7 +1,7 @@
1
1
  var assert = require('assert');
2
2
  var usearch = require('bindings')('usearch');
3
3
 
4
- var index = new usearch.Index({ metric: 'l2_sq', connectivity: 16, dimensions: 2 })
4
+ var index = new usearch.Index({ metric: 'l2sq', connectivity: 16, dimensions: 2 })
5
5
  assert.equal(index.connectivity(), 16)
6
6
  assert.equal(index.dimensions(), 2)
7
7
  assert.equal(index.size(), 0)
@@ -2,15 +2,15 @@
2
2
 
3
3
  #pragma clang diagnostic push
4
4
  #pragma clang diagnostic ignored "-Wdocumentation"
5
- #import "advanced.hpp"
5
+ #import "punned.hpp"
6
6
  #pragma clang diagnostic pop
7
7
 
8
8
  using namespace unum::usearch;
9
9
  using namespace unum;
10
10
 
11
11
  using distance_t = punned_distance_t;
12
- using native_index_t = auto_index_gt<UInt32>;
13
- using shared_index_t = std::shared_ptr<native_index_t>;
12
+ using punned_t = punned_gt<UInt32>;
13
+ using shared_index_t = std::shared_ptr<punned_t>;
14
14
 
15
15
  @interface Index ()
16
16
 
@@ -59,91 +59,108 @@ using shared_index_t = std::shared_ptr<native_index_t>;
59
59
  + (instancetype)indexIP:(UInt32)dimensions connectivity:(UInt32)connectivity {
60
60
  std::size_t dims = static_cast<std::size_t>(dimensions);
61
61
  config_t config;
62
+
62
63
  config.connectivity = static_cast<std::size_t>(connectivity);
63
- shared_index_t ptr = std::make_shared<native_index_t>(native_index_t::ip(dims, accuracy_t::f32_k, config));
64
+ shared_index_t ptr = std::make_shared<punned_t>(punned_t::ip(dims, accuracy_t::f32_k, config));
64
65
  return [[Index alloc] initWithIndex:ptr];
65
66
  }
66
67
 
67
- + (instancetype)indexL2:(UInt32)dimensions connectivity:(UInt32)connectivity {
68
+ + (instancetype)indexL2sq:(UInt32)dimensions connectivity:(UInt32)connectivity {
68
69
  std::size_t dims = static_cast<std::size_t>(dimensions);
69
70
  config_t config;
71
+
70
72
  config.connectivity = static_cast<std::size_t>(connectivity);
71
- shared_index_t ptr = std::make_shared<native_index_t>(native_index_t::l2(dims, accuracy_t::f32_k, config));
73
+ shared_index_t ptr = std::make_shared<punned_t>(punned_t::l2sq(dims, accuracy_t::f32_k, config));
72
74
  return [[Index alloc] initWithIndex:ptr];
73
75
  }
74
76
 
75
77
  + (instancetype)indexHaversine:(UInt32)connectivity {
76
78
  config_t config;
79
+
77
80
  config.connectivity = static_cast<std::size_t>(connectivity);
78
- shared_index_t ptr = std::make_shared<native_index_t>(native_index_t::haversine(accuracy_t::f32_k, config));
81
+ shared_index_t ptr = std::make_shared<punned_t>(punned_t::haversine(accuracy_t::f32_k, config));
79
82
  return [[Index alloc] initWithIndex:ptr];
80
83
  }
81
84
 
82
85
  - (void)addSingle:(UInt32)label
83
- vector:(Float32 const * _Nonnull)vector {
86
+ vector:(Float32 const *_Nonnull)vector {
84
87
  _native->add(label, vector);
85
88
  }
86
89
 
87
- - (UInt32)searchSingle:(Float32 const* _Nonnull)vector
90
+ - (UInt32)searchSingle:(Float32 const *_Nonnull)vector
88
91
  count:(UInt32)wanted
89
- labels:(UInt32* _Nullable)labels
90
- distances:(Float32* _Nullable)distances {
91
- std::size_t found = _native->search(vector, static_cast<std::size_t>(wanted), labels, distances);
92
+ labels:(UInt32 *_Nullable)labels
93
+ distances:(Float32 *_Nullable)distances {
94
+ std::size_t found = _native->search(vector, static_cast<std::size_t>(wanted)).dump_to(labels, distances);
95
+
92
96
  return static_cast<UInt32>(found);
93
97
  }
94
98
 
95
99
  - (void)addPrecise:(UInt32)label
96
- vector:(Float64 const * _Nonnull)vector {
100
+ vector:(Float64 const *_Nonnull)vector {
97
101
  _native->add(label, (f64_t const *)vector);
98
102
  }
99
103
 
100
- - (UInt32)searchPrecise:(Float64 const* _Nonnull)vector
104
+ - (UInt32)searchPrecise:(Float64 const *_Nonnull)vector
101
105
  count:(UInt32)wanted
102
- labels:(UInt32* _Nullable)labels
103
- distances:(Float32* _Nullable)distances {
104
- std::size_t found = _native->search((f64_t const *)vector, static_cast<std::size_t>(wanted), labels, distances);
106
+ labels:(UInt32 *_Nullable)labels
107
+ distances:(Float32 *_Nullable)distances {
108
+ std::size_t found = _native->search((f64_t const *)vector, static_cast<std::size_t>(wanted)).dump_to(labels, distances);
109
+
105
110
  return static_cast<UInt32>(found);
106
111
  }
107
112
 
108
113
  - (void)addImprecise:(UInt32)label
109
- vector:(void const * _Nonnull)vector {
114
+ vector:(void const *_Nonnull)vector {
110
115
  _native->add(label, (f16_bits_t const *)vector);
111
116
  }
112
117
 
113
- - (UInt32)searchImprecise:(void const* _Nonnull)vector
118
+ - (UInt32)searchImprecise:(void const *_Nonnull)vector
114
119
  count:(UInt32)wanted
115
- labels:(UInt32* _Nullable)labels
116
- distances:(Float32* _Nullable)distances {
117
- std::size_t found = _native->search((f16_bits_t const *)vector, static_cast<std::size_t>(wanted), labels, distances);
120
+ labels:(UInt32 *_Nullable)labels
121
+ distances:(Float32 *_Nullable)distances {
122
+ std::size_t found = _native->search((f16_bits_t const *)vector, static_cast<std::size_t>(wanted)).dump_to(labels, distances);
123
+
118
124
  return static_cast<UInt32>(found);
119
125
  }
120
126
 
121
- - (void)clear { _native->clear(); }
127
+ - (void)clear {
128
+ _native->clear();
129
+ }
122
130
 
123
- - (void)save:(NSString*)path {
131
+ - (void)save:(NSString *)path {
124
132
  char const *path_c = [path UTF8String];
125
- if (!path_c)
133
+
134
+ if (!path_c) {
126
135
  @throw [NSException exceptionWithName:@"Can't save to disk"
127
136
  reason:@"The path must be convertible to UTF8"
128
137
  userInfo:nil];
138
+ }
139
+
129
140
  _native->save(path_c);
130
141
  }
131
142
 
132
- - (void)load:(NSString*)path {
143
+ - (void)load:(NSString *)path {
133
144
  char const *path_c = [path UTF8String];
134
- if (!path_c)
145
+
146
+ if (!path_c) {
135
147
  @throw [NSException exceptionWithName:@"Can't load from disk"
136
148
  reason:@"The path must be convertible to UTF8"
137
149
  userInfo:nil];
150
+ }
151
+
138
152
  _native->load(path_c);
139
153
  }
140
154
 
141
- - (void)view:(NSString*)path {
155
+ - (void)view:(NSString *)path {
142
156
  char const *path_c = [path UTF8String];
143
- if (!path_c)
157
+
158
+ if (!path_c) {
144
159
  @throw [NSException exceptionWithName:@"Can't view from disk"
145
160
  reason:@"The path must be convertible to UTF8"
146
161
  userInfo:nil];
162
+ }
163
+
147
164
  _native->view(path_c);
148
165
  }
149
166
 
@@ -11,7 +11,7 @@ typedef NS_ENUM(NSUInteger, Quantization) {
11
11
  };
12
12
 
13
13
  API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0))
14
- @interface Index: NSObject
14
+ @interface Index : NSObject
15
15
 
16
16
  @property (readonly) UInt32 dimensions;
17
17
  @property (readonly) UInt32 connectivity;
@@ -22,47 +22,39 @@ API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0))
22
22
  @property (readonly) UInt32 capacity;
23
23
  @property (readonly) Boolean isEmpty;
24
24
 
25
- - (instancetype)init
26
- NS_UNAVAILABLE;
25
+ - (instancetype)init NS_UNAVAILABLE;
27
26
 
28
27
  + (instancetype)indexIP:(UInt32)dimensions connectivity:(UInt32)connectivity NS_SWIFT_NAME(indexIP(dimensions:connectivity:));
29
- + (instancetype)indexL2:(UInt32)dimensions connectivity:(UInt32)connectivity NS_SWIFT_NAME(l2(dimensions:connectivity:));
28
+ + (instancetype)indexL2sq:(UInt32)dimensions connectivity:(UInt32)connectivity NS_SWIFT_NAME(l2sq(dimensions:connectivity:));
30
29
  + (instancetype)indexHaversine:(UInt32)connectivity NS_SWIFT_NAME(indexHaversine(connectivity:));
31
30
 
32
31
  - (void)addSingle:(UInt32)label
33
- vector:(Float32 const* _Nonnull)vector
34
- NS_SWIFT_NAME(addSingle(label:vector:));
32
+ vector:(Float32 const *_Nonnull)vector NS_SWIFT_NAME(addSingle(label:vector:));
35
33
 
36
- - (UInt32)searchSingle:(Float32 const* _Nonnull)vector
34
+ - (UInt32)searchSingle:(Float32 const *_Nonnull)vector
37
35
  count:(UInt32)count
38
- labels:(UInt32* _Nullable)labels
39
- distances:(Float32* _Nullable)distances
40
- NS_SWIFT_NAME(searchSingle(vector:count:labels:distances:));
36
+ labels:(UInt32 *_Nullable)labels
37
+ distances:(Float32 *_Nullable)distances NS_SWIFT_NAME(searchSingle(vector:count:labels:distances:));
41
38
 
42
39
  - (void)addPrecise:(UInt32)label
43
- vector:(Float64 const* _Nonnull)vector
44
- NS_SWIFT_NAME(addPrecise(label:vector:));
40
+ vector:(Float64 const *_Nonnull)vector NS_SWIFT_NAME(addPrecise(label:vector:));
45
41
 
46
- - (UInt32)searchPrecise:(Float64 const* _Nonnull)vector
42
+ - (UInt32)searchPrecise:(Float64 const *_Nonnull)vector
47
43
  count:(UInt32)count
48
- labels:(UInt32* _Nullable)labels
49
- distances:(Float32* _Nullable)distances
50
- NS_SWIFT_NAME(searchPrecise(vector:count:labels:distances:));
44
+ labels:(UInt32 *_Nullable)labels
45
+ distances:(Float32 *_Nullable)distances NS_SWIFT_NAME(searchPrecise(vector:count:labels:distances:));
51
46
 
52
47
  - (void)addImprecise:(UInt32)label
53
- vector:(void const* _Nonnull)vector
54
- NS_SWIFT_NAME(addImprecise(label:vector:));
48
+ vector:(void const *_Nonnull)vector NS_SWIFT_NAME(addImprecise(label:vector:));
55
49
 
56
- - (UInt32)searchImprecise:(void const* _Nonnull)vector
50
+ - (UInt32)searchImprecise:(void const *_Nonnull)vector
57
51
  count:(UInt32)count
58
- labels:(UInt32* _Nullable)labels
59
- distances:(Float32* _Nullable)distances
60
- NS_SWIFT_NAME(searchImprecise(vector:count:labels:distances:));
52
+ labels:(UInt32 *_Nullable)labels
53
+ distances:(Float32 *_Nullable)distances NS_SWIFT_NAME(searchImprecise(vector:count:labels:distances:));
61
54
 
62
-
63
- - (void)save:(NSString*)path NS_SWIFT_NAME(dump(path:));
64
- - (void)load:(NSString*)path NS_SWIFT_NAME(load(path:));
65
- - (void)view:(NSString*)path NS_SWIFT_NAME(view(path:));
55
+ - (void)save:(NSString *)path NS_SWIFT_NAME(dump(path:));
56
+ - (void)load:(NSString *)path NS_SWIFT_NAME(load(path:));
57
+ - (void)view:(NSString *)path NS_SWIFT_NAME(view(path:));
66
58
  - (void)clear NS_SWIFT_NAME(clear());
67
59
 
68
60
  @end
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usearch",
3
- "version": "0.4.0",
3
+ "version": "0.8.0",
4
4
  "description": "Smaller & Faster Single-File Vector Search Engine from Unum",
5
5
  "author": "Ashot Vardanian",
6
6
  "license": "Apache 2.0",
package/pyproject.toml CHANGED
@@ -1,5 +1,5 @@
1
1
  [build-system]
2
- requires = ["setuptools>=42", "wheel", "cmake>=3.22", "pybind11"]
2
+ requires = ["setuptools>=42", "wheel", "cmake>=3.22", "pybind11", "numpy"]
3
3
  build-backend = "setuptools.build_meta"
4
4
 
5
5
  [tool.pytest.ini_options]
@@ -9,8 +9,9 @@ xfail_strict = true
9
9
  filterwarnings = ["error"]
10
10
 
11
11
  [tool.cibuildwheel]
12
+ test-requires = ["pytest", "numpy"]
13
+ test-command = "pytest {project}/python/test.py"
12
14
  build-verbosity = 0
13
-
14
15
  skip = ["*musllinux*", "*i686*", "pp*"]
15
16
 
16
17
  [tool.cibuildwheel.linux]