usearch 2.8.16 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.yml +1 -1
  2. package/.github/workflows/prerelease.yml +33 -7
  3. package/.github/workflows/release.yml +25 -26
  4. package/.gitmodules +4 -1
  5. package/CITATION.cff +1 -1
  6. package/CMakeLists.txt +6 -8
  7. package/CONTRIBUTING.md +46 -1
  8. package/Cargo.toml +1 -1
  9. package/README.md +7 -6
  10. package/VERSION +1 -1
  11. package/c/lib.cpp +19 -17
  12. package/c/test.c +41 -7
  13. package/c/usearch.h +15 -15
  14. package/conanfile.py +1 -1
  15. package/cpp/test.cpp +9 -2
  16. package/include/usearch/index.hpp +15 -15
  17. package/include/usearch/index_dense.hpp +8 -4
  18. package/include/usearch/index_plugins.hpp +34 -23
  19. package/javascript/usearch.js +1 -1
  20. package/package.json +3 -2
  21. package/pyproject.toml +2 -2
  22. package/setup.py +10 -4
  23. package/simsimd/.releaserc +3 -2
  24. package/simsimd/Cargo.lock +708 -0
  25. package/simsimd/Cargo.toml +36 -0
  26. package/simsimd/README.md +37 -1
  27. package/simsimd/build.rs +20 -0
  28. package/simsimd/include/simsimd/simsimd.h +4 -4
  29. package/simsimd/include/simsimd/spatial.h +1 -1
  30. package/simsimd/include/simsimd/types.h +5 -1
  31. package/simsimd/package.json +1 -1
  32. package/simsimd/rust/benches/cosine.rs +27 -0
  33. package/simsimd/rust/benches/native.rs +27 -0
  34. package/simsimd/rust/benches/sqeuclidean.rs +27 -0
  35. package/simsimd/rust/lib.c +68 -0
  36. package/simsimd/rust/lib.rs +232 -0
  37. package/sqlite/README.md +178 -0
  38. package/sqlite/lib.cpp +325 -0
  39. package/stringzilla/CONTRIBUTING.md +429 -0
  40. package/stringzilla/Cargo.lock +25 -0
  41. package/stringzilla/Cargo.toml +26 -0
  42. package/stringzilla/LICENSE +201 -0
  43. package/stringzilla/README.md +1281 -0
  44. package/stringzilla/VERSION +1 -0
  45. package/stringzilla/assets/cover-strinzilla.jpeg +0 -0
  46. package/stringzilla/assets/meme-stringzilla-v2.jpeg +0 -0
  47. package/stringzilla/assets/meme-stringzilla-v3.jpeg +0 -0
  48. package/stringzilla/binding.gyp +16 -0
  49. package/stringzilla/build.rs +14 -0
  50. package/stringzilla/c/lib.c +304 -0
  51. package/stringzilla/cli/README.md +48 -0
  52. package/stringzilla/cli/split.py +72 -0
  53. package/stringzilla/cli/wc.py +37 -0
  54. package/stringzilla/include/stringzilla/experimental.h +724 -0
  55. package/stringzilla/include/stringzilla/module.modulemap +9 -0
  56. package/stringzilla/include/stringzilla/stringzilla.h +5240 -0
  57. package/stringzilla/include/stringzilla/stringzilla.hpp +3830 -0
  58. package/stringzilla/javascript/lib.c +125 -0
  59. package/stringzilla/javascript/stringzilla.js +22 -0
  60. package/stringzilla/package-ci.json +10 -0
  61. package/stringzilla/package.json +32 -0
  62. package/stringzilla/rust/lib.rs +362 -0
  63. package/stringzilla/swift/StringProtocol+StringZilla.swift +280 -0
  64. package/stringzilla/swift/Test.swift +60 -0
  65. package/wasmer.toml +1 -1
  66. package/simsimd/bench.js +0 -51
@@ -1,7 +1,7 @@
1
1
  name: Report a bug
2
2
  description: Something doesn't work as expected?
3
3
  title: "Bug: "
4
- labels: ["bug", "invalid"]
4
+ labels: ["bug"]
5
5
  assignees:
6
6
  - octocat
7
7
  body:
@@ -61,9 +61,9 @@ jobs:
61
61
  with:
62
62
  node-version: 20
63
63
  - name: Build JavaScript
64
- run: npm install
64
+ run: npm ci
65
65
  - name: Test JavaScript
66
- run: npm ci && npm test
66
+ run: npm test
67
67
 
68
68
  # Rust
69
69
  - name: Test Rust
@@ -154,7 +154,6 @@ jobs:
154
154
  node-version: 20
155
155
  - name: Build and test JavaScript
156
156
  run: |
157
- npm install
158
157
  npm ci
159
158
  npm test
160
159
 
@@ -212,9 +211,9 @@ jobs:
212
211
  with:
213
212
  node-version: 20
214
213
  - name: Build JavaScript
215
- run: npm install
214
+ run: npm ci
216
215
  - name: Test JavaScript
217
- run: npm ci && npm test
216
+ run: npm test
218
217
 
219
218
  # ObjC/Swift
220
219
  - name: Build ObjC/Swift
@@ -274,9 +273,9 @@ jobs:
274
273
  with:
275
274
  node-version: 20
276
275
  - name: Build JavaScript
277
- run: npm install
276
+ run: npm ci
278
277
  - name: Test JavaScript
279
- run: npm ci && npm test
278
+ run: npm test
280
279
 
281
280
  # C#
282
281
  - name: Setup .NET ${{ env.DOTNET_VERSION }}
@@ -303,3 +302,30 @@ jobs:
303
302
  context: .
304
303
  load: true
305
304
  push: false
305
+
306
+
307
+ build_wheels:
308
+ name: Build Python ${{ matrix.python-version }} for ${{ matrix.os }}
309
+ runs-on: ${{ matrix.os }}
310
+ needs: [test_ubuntu_gcc, test_ubuntu_clang, test_macos, test_windows]
311
+ strategy:
312
+ matrix:
313
+ os: [ubuntu-latest, macos-latest, windows-latest]
314
+ python-version: ["37", "38", "39", "310", "311", "312"]
315
+ steps:
316
+ - uses: actions/checkout@v4
317
+ - name: Set up Python
318
+ uses: actions/setup-python@v5
319
+ with:
320
+ python-version: 3.x
321
+
322
+ # We only need QEMU for Linux builds
323
+ - name: Setup QEMU
324
+ if: matrix.os == 'ubuntu-latest'
325
+ uses: docker/setup-qemu-action@v3
326
+ - name: Install cibuildwheel
327
+ run: python -m pip install cibuildwheel
328
+ - name: Build wheels
329
+ run: cibuildwheel --output-dir wheelhouse
330
+ env:
331
+ CIBW_BUILD: cp${{ matrix.python-version }}-*
@@ -349,39 +349,36 @@ jobs:
349
349
  * ${{ steps.hashes.outputs.asset_name_15 }} : `${{ steps.hashes.outputs.asset_hash_15 }}`
350
350
 
351
351
  build_wheels:
352
- name: Build Python
353
- needs: versioning
352
+ name: Build Python ${{ matrix.python-version }} for ${{ matrix.os }}
354
353
  runs-on: ${{ matrix.os }}
354
+ needs: versioning
355
355
  strategy:
356
- fail-fast: false
357
356
  matrix:
358
- os: [ubuntu-22.04, macOS-11, windows-2022]
359
-
357
+ os: [ubuntu-latest, macos-latest, windows-latest]
358
+ python-version: ["37", "38", "39", "310", "311", "312"]
360
359
  steps:
361
- - uses: actions/checkout@v3
360
+ - uses: actions/checkout@v4
362
361
  with:
363
362
  ref: "main"
364
- - uses: actions/setup-python@v3
365
-
366
- - name: Setup Docker
367
- if: matrix.os == 'ubuntu-22.04'
368
- uses: crazy-max/ghaction-setup-docker@v1.0.0
363
+ - name: Set up Python
364
+ uses: actions/setup-python@v5
369
365
  with:
370
- version: 23.0.1
371
-
366
+ python-version: 3.x
372
367
  - name: Setup QEMU
373
- if: matrix.os == 'ubuntu-22.04'
374
- uses: docker/setup-qemu-action@v2.1.0
375
-
376
- - name: Install CIBuildWheel
368
+ if: matrix.os == 'ubuntu-latest' # We only need QEMU for Linux builds
369
+ uses: docker/setup-qemu-action@v3
370
+ - name: Install cibuildwheel
377
371
  run: python -m pip install cibuildwheel
378
-
379
372
  - name: Build wheels
380
- run: python -m cibuildwheel
381
-
382
- - uses: actions/upload-artifact@v3
373
+ run: cibuildwheel --output-dir wheelhouse
374
+ env:
375
+ CIBW_BUILD: cp${{ matrix.python-version }}-*
376
+ - name: Upload wheels
377
+ uses: actions/upload-artifact@v4
383
378
  with:
379
+ name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
384
380
  path: ./wheelhouse/*.whl
381
+ overwrite: true
385
382
 
386
383
  publish_python:
387
384
  name: Publish Python
@@ -395,17 +392,20 @@ jobs:
395
392
 
396
393
  steps:
397
394
  - name: Download artifacts
398
- uses: actions/download-artifact@v3.0.2
395
+ uses: actions/download-artifact@v4
399
396
  with:
400
- path: ./dist/
397
+ # unpacks all CIBW artifacts into dist/
398
+ pattern: cibw-*
399
+ path: dist
400
+ merge-multiple: true
401
401
 
402
402
  - name: Publish to PyPi
403
403
  uses: pypa/gh-action-pypi-publish@release/v1
404
404
  with:
405
- packages-dir: ./dist/artifact
405
+ packages-dir: dist
406
406
  verbose: true
407
407
  print-hash: true
408
-
408
+
409
409
  publish_javascript:
410
410
  name: Publish JavaScript
411
411
  needs: versioning
@@ -432,7 +432,6 @@ jobs:
432
432
 
433
433
  - name: Build and Test
434
434
  run: |
435
- npm install
436
435
  npm ci
437
436
  npm test
438
437
  npm run typegen
package/.gitmodules CHANGED
@@ -3,4 +3,7 @@
3
3
  url = https://github.com/ashvardanian/simsimd
4
4
  [submodule "fp16"]
5
5
  path = fp16
6
- url = https://github.com/maratyszcza/fp16
6
+ url = https://github.com/maratyszcza/fp16
7
+ [submodule "stringzilla"]
8
+ path = stringzilla
9
+ url = https://github.com/ashvardanian/stringzilla
package/CITATION.cff CHANGED
@@ -5,7 +5,7 @@ authors:
5
5
  given-names: "Ash"
6
6
  orcid: "https://orcid.org/0000-0002-4882-1815"
7
7
  title: "USearch by Unum Cloud"
8
- version: 2.8.16
8
+ version: 2.9.1
9
9
  doi: 10.5281/zenodo.7949416
10
10
  date-released: 2023-10-22
11
11
  url: "https://github.com/unum-cloud/usearch"
package/CMakeLists.txt CHANGED
@@ -13,6 +13,11 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
13
13
  set(USEARCH_IS_MAIN_PROJECT ON)
14
14
  endif ()
15
15
 
16
+ # Allow CMake 3.13+ to override options when using FetchContent / add_subdirectory
17
+ if (POLICY CMP0077)
18
+ cmake_policy(SET CMP0077 NEW)
19
+ endif ()
20
+
16
21
  # Options
17
22
  option(USEARCH_INSTALL "Install CMake targets" OFF)
18
23
 
@@ -31,11 +36,6 @@ option(USEARCH_BUILD_WOLFRAM "Compile Wolfram Language bindings" OFF)
31
36
  set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
32
37
  include(ExternalProject)
33
38
 
34
- # Allow CMake 3.13+ to override options when using FetchContent / add_subdirectory
35
- if (POLICY CMP0077)
36
- cmake_policy(SET CMP0077 NEW)
37
- endif ()
38
-
39
39
  # Configuration
40
40
  include(GNUInstallDirs)
41
41
  set(USEARCH_TARGET_NAME ${PROJECT_NAME})
@@ -186,9 +186,7 @@ function (setup_target TARGET_NAME)
186
186
  target_link_libraries(${TARGET_NAME} PRIVATE OpenMP::OpenMP_CXX)
187
187
  endif ()
188
188
 
189
- if (CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin")
190
- target_link_libraries(${TARGET_NAME} PRIVATE Threads::Threads)
191
- endif ()
189
+ target_link_libraries(${TARGET_NAME} PRIVATE Threads::Threads)
192
190
 
193
191
  elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
194
192
  target_compile_options(
package/CONTRIBUTING.md CHANGED
@@ -130,7 +130,26 @@ Still, if you have Docker running on any desktop OS, you can use it to build and
130
130
 
131
131
  ```sh
132
132
  pip install cibuildwheel
133
- cibuildwheel --platform linux
133
+ cibuildwheel
134
+ cibuildwheel --platform linux # works on any OS and builds all Linux backends
135
+ cibuildwheel --platform linux --archs x86_64 # 64-bit x86, the most common on desktop and servers
136
+ cibuildwheel --platform linux --archs aarch64 # 64-bit Arm for mobile devices, Apple M-series, and AWS Graviton
137
+ cibuildwheel --platform linux --archs i686 # 32-bit Linux
138
+ cibuildwheel --platform linux --archs s390x # emulating big-endian IBM Z
139
+ cibuildwheel --platform macos # works only on MacOS
140
+ cibuildwheel --platform windows # works only on Windows
141
+ ```
142
+
143
+ You may need root previligies for multi-architecture builds:
144
+
145
+ ```sh
146
+ sudo $(which cibuildwheel) --platform linux
147
+ ```
148
+
149
+ On Windows and MacOS, to avoid frequent path resolution issues, you may want to use:
150
+
151
+ ```sh
152
+ python -m cibuildwheel --platform windows
134
153
  ```
135
154
 
136
155
  ## JavaScript
@@ -272,6 +291,32 @@ cp cloud/unum/usearch/libusearch.* .
272
291
  java -cp . -Djava.library.path="$(pwd)" cloud.unum.usearch.Index
273
292
  ```
274
293
 
294
+ ## C#
295
+
296
+ Setup the .NET environment:
297
+
298
+ ```sh
299
+ dotnet nuget add source https://api.nuget.org/v3/index.json -n nuget.org
300
+ ```
301
+
302
+ USearch provides CSharp bindings, that depend on the C library that must be installed beforehand.
303
+ So one should first compile the C library, link it with CSharp, and only then run tests.
304
+
305
+ ```sh
306
+ cmake -B ./build_artifacts -DUSEARCH_BUILD_LIB_C=1 -DUSEARCH_BUILD_TEST_C=1 -DUSEARCH_USE_OPENMP=1 -DUSEARCH_USE_SIMSIMD=1
307
+ cmake --build ./build_artifacts --config Release -j
308
+ ```
309
+
310
+ Then, on Windows, copy the library to the CSharp project and run the tests:
311
+
312
+ ```sh
313
+ mkdir -p ".\csharp\lib\runtimes\win-x64\native"
314
+ cp ".\build_artifacts\libusearch_c.dll" ".\csharp\lib\runtimes\win-x64\native"
315
+ cd csharp
316
+ dotnet test -c Debug --logger "console;verbosity=detailed"
317
+ dotnet test -c Release
318
+ ```
319
+
275
320
  ## Wolfram
276
321
 
277
322
  ```sh
package/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "usearch"
3
- version = "2.8.16"
3
+ version = "2.9.1"
4
4
  authors = ["Ash Vardanian <1983160+ashvardanian@users.noreply.github.com>"]
5
5
  description = "Smaller & Faster Single-File Vector Search Engine from Unum"
6
6
  edition = "2021"
package/README.md CHANGED
@@ -30,7 +30,8 @@ Spatial • Binary • Probabilistic • User-Defined Metrics
30
30
  <a href="https://unum-cloud.github.io/usearch/swift">Swift</a> •
31
31
  <a href="https://unum-cloud.github.io/usearch/csharp">C#</a> •
32
32
  <a href="https://unum-cloud.github.io/usearch/golang">GoLang</a> •
33
- <a href="https://unum-cloud.github.io/usearch/wolfram">Wolfram</a>
33
+ <a href="https://unum-cloud.github.io/usearch/wolfram">Wolfram</a> •
34
+ <a href="https://unum-cloud.github.io/usearch/sqlite">SQLite3</a>
34
35
  <br/>
35
36
  Linux • MacOS • Windows • iOS • WebAssembly
36
37
  </p>
@@ -47,10 +48,10 @@ Linux • MacOS • Windows • iOS • WebAssembly
47
48
 
48
49
  ---
49
50
 
50
- - ✅ [10x faster][faster-than-faiss] [HNSW][hnsw-algorithm] implementation than [FAISS][faiss].
51
- - ✅ Simple and extensible [single C++11 header][usearch-header] implementation.
51
+ - ✅ __[10x faster][faster-than-faiss]__ [HNSW][hnsw-algorithm] implementation than [FAISS][faiss].
52
+ - ✅ Simple and extensible [single C++11 header][usearch-header] __library__.
52
53
  - ✅ Compatible with a dozen programming languages out of the box.
53
- - ✅ [Trusted](#integrations) by some of the most loved Datalakes and Databases, like [ClickHouse][clickhouse-docs].
54
+ - ✅ [Trusted](#integrations) by giants like Google and databases like [ClickHouse][clickhouse-docs].
54
55
  - ✅ [SIMD][simd]-optimized and [user-defined metrics](#user-defined-functions) with JIT compilation.
55
56
  - ✅ Hardware-agnostic `f16` & `i8` - [half-precision & quarter-precision support](#memory-efficiency-downcasting-and-quantization).
56
57
  - ✅ [View large indexes from disk](#serving-index-from-disk) without loading into RAM.
@@ -60,7 +61,7 @@ Linux • MacOS • Windows • iOS • WebAssembly
60
61
  - ✅ Space-efficient point-clouds with `uint40_t`, accommodating 4B+ size.
61
62
  - ✅ Compatible with OpenMP and custom "executors" for fine-grained control over CPU utilization.
62
63
  - ✅ Near-real-time [clustering and sub-clustering](#clustering) for Tens or Millions of clusters.
63
- - ✅ [Semantic Search](#usearch--ai--multi-modal-semantic-search) and [Joins](#joins).
64
+ - ✅ [Semantic Search](#usearch--ai--multi-modal-semantic-search) and [Joins](#joins-one-to-one-one-to-many-and-many-to-many-mappings).
64
65
 
65
66
  [faiss]: https://github.com/facebookresearch/faiss
66
67
  [usearch-header]: https://github.com/unum-cloud/usearch/blob/main/include/usearch/index.hpp
@@ -433,7 +434,7 @@ doi = {10.5281/zenodo.7949416},
433
434
  author = {Vardanian, Ash},
434
435
  title = {{USearch by Unum Cloud}},
435
436
  url = {https://github.com/unum-cloud/usearch},
436
- version = {2.8.16},
437
+ version = {2.9.1},
437
438
  year = {2023},
438
439
  month = oct,
439
440
  }
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.8.16
1
+ 2.9.1
package/c/lib.cpp CHANGED
@@ -106,7 +106,7 @@ extern "C" {
106
106
 
107
107
  USEARCH_EXPORT usearch_index_t usearch_init(usearch_init_options_t* options, usearch_error_t* error) {
108
108
 
109
- assert(options && error);
109
+ assert(options && error && "Missing arguments");
110
110
 
111
111
  index_dense_config_t config(options->connectivity, options->expansion_add, options->expansion_search);
112
112
  config.multi = options->multi;
@@ -132,13 +132,13 @@ USEARCH_EXPORT void usearch_free(usearch_index_t index, usearch_error_t*) {
132
132
  }
133
133
 
134
134
  USEARCH_EXPORT size_t usearch_serialized_length(usearch_index_t index, usearch_error_t*) {
135
- assert(index);
135
+ assert(index && "Missing arguments");
136
136
  return reinterpret_cast<index_dense_t*>(index)->serialized_length();
137
137
  }
138
138
 
139
139
  USEARCH_EXPORT void usearch_save(usearch_index_t index, char const* path, usearch_error_t* error) {
140
140
 
141
- assert(index && path && error);
141
+ assert(index && path && error && "Missing arguments");
142
142
  serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->save(path);
143
143
  if (!result)
144
144
  *error = result.error.release();
@@ -146,7 +146,7 @@ USEARCH_EXPORT void usearch_save(usearch_index_t index, char const* path, usearc
146
146
 
147
147
  USEARCH_EXPORT void usearch_load(usearch_index_t index, char const* path, usearch_error_t* error) {
148
148
 
149
- assert(index && path && error);
149
+ assert(index && path && error && "Missing arguments");
150
150
  serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->load(path);
151
151
  if (!result)
152
152
  *error = result.error.release();
@@ -154,7 +154,7 @@ USEARCH_EXPORT void usearch_load(usearch_index_t index, char const* path, usearc
154
154
 
155
155
  USEARCH_EXPORT void usearch_view(usearch_index_t index, char const* path, usearch_error_t* error) {
156
156
 
157
- assert(index && path && error);
157
+ assert(index && path && error && "Missing arguments");
158
158
  serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->view(path);
159
159
  if (!result)
160
160
  *error = result.error.release();
@@ -162,7 +162,7 @@ USEARCH_EXPORT void usearch_view(usearch_index_t index, char const* path, usearc
162
162
 
163
163
  USEARCH_EXPORT void usearch_metadata(char const* path, usearch_init_options_t* options, usearch_error_t* error) {
164
164
 
165
- assert(path && options && error);
165
+ assert(path && options && error && "Missing arguments");
166
166
  index_dense_metadata_result_t result = index_dense_metadata_from_path(path);
167
167
  if (!result)
168
168
  *error = result.error.release();
@@ -180,7 +180,7 @@ USEARCH_EXPORT void usearch_metadata(char const* path, usearch_init_options_t* o
180
180
 
181
181
  USEARCH_EXPORT void usearch_save_buffer(usearch_index_t index, void* buffer, size_t length, usearch_error_t* error) {
182
182
 
183
- assert(index && buffer && length && error);
183
+ assert(index && buffer && length && error && "Missing arguments");
184
184
  memory_mapped_file_t memory_map((byte_t*)buffer, length);
185
185
  serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->save(std::move(memory_map));
186
186
  if (!result)
@@ -190,7 +190,7 @@ USEARCH_EXPORT void usearch_save_buffer(usearch_index_t index, void* buffer, siz
190
190
  USEARCH_EXPORT void usearch_load_buffer(usearch_index_t index, void const* buffer, size_t length,
191
191
  usearch_error_t* error) {
192
192
 
193
- assert(index && buffer && length && error);
193
+ assert(index && buffer && length && error && "Missing arguments");
194
194
  memory_mapped_file_t memory_map((byte_t*)buffer, length);
195
195
  serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->load(std::move(memory_map));
196
196
  if (!result)
@@ -200,7 +200,7 @@ USEARCH_EXPORT void usearch_load_buffer(usearch_index_t index, void const* buffe
200
200
  USEARCH_EXPORT void usearch_view_buffer(usearch_index_t index, void const* buffer, size_t length,
201
201
  usearch_error_t* error) {
202
202
 
203
- assert(index && buffer && length && error);
203
+ assert(index && buffer && length && error && "Missing arguments");
204
204
  memory_mapped_file_t memory_map((byte_t*)buffer, length);
205
205
  serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->view(std::move(memory_map));
206
206
  if (!result)
@@ -210,7 +210,7 @@ USEARCH_EXPORT void usearch_view_buffer(usearch_index_t index, void const* buffe
210
210
  USEARCH_EXPORT void usearch_metadata_buffer(void const* buffer, size_t length, usearch_init_options_t* options,
211
211
  usearch_error_t* error) {
212
212
 
213
- assert(buffer && length && options && error);
213
+ assert(buffer && length && options && error && "Missing arguments");
214
214
  index_dense_metadata_result_t result =
215
215
  index_dense_metadata_from_buffer(memory_mapped_file_t((byte_t*)(buffer), length));
216
216
  if (!result)
@@ -244,7 +244,7 @@ USEARCH_EXPORT size_t usearch_connectivity(usearch_index_t index, usearch_error_
244
244
  }
245
245
 
246
246
  USEARCH_EXPORT void usearch_reserve(usearch_index_t index, size_t capacity, usearch_error_t* error) {
247
- assert(index && error);
247
+ assert(index && error && "Missing arguments");
248
248
  if (!reinterpret_cast<index_dense_t*>(index)->reserve(capacity))
249
249
  *error = "Out of memory!";
250
250
  }
@@ -253,19 +253,19 @@ USEARCH_EXPORT void usearch_add(
253
253
  usearch_index_t index, usearch_key_t key, void const* vector, usearch_scalar_kind_t kind, //
254
254
  usearch_error_t* error) {
255
255
 
256
- assert(index && vector && error);
256
+ assert(index && vector && error && "Missing arguments");
257
257
  add_result_t result = add_(reinterpret_cast<index_dense_t*>(index), key, vector, scalar_kind_to_cpp(kind));
258
258
  if (!result)
259
259
  *error = result.error.release();
260
260
  }
261
261
 
262
262
  USEARCH_EXPORT bool usearch_contains(usearch_index_t index, usearch_key_t key, usearch_error_t*) {
263
- assert(index);
263
+ assert(index && "Missing arguments");
264
264
  return reinterpret_cast<index_dense_t*>(index)->contains(key);
265
265
  }
266
266
 
267
267
  USEARCH_EXPORT size_t usearch_count(usearch_index_t index, usearch_key_t key, usearch_error_t*) {
268
- assert(index);
268
+ assert(index && "Missing arguments");
269
269
  return reinterpret_cast<index_dense_t*>(index)->count(key);
270
270
  }
271
271
 
@@ -273,7 +273,7 @@ USEARCH_EXPORT size_t usearch_search(
273
273
  usearch_index_t index, void const* vector, usearch_scalar_kind_t kind, size_t results_limit, //
274
274
  usearch_key_t* found_keys, usearch_distance_t* found_distances, usearch_error_t* error) {
275
275
 
276
- assert(index && vector && error);
276
+ assert(index && vector && error && "Missing arguments");
277
277
  search_result_t result =
278
278
  search_(reinterpret_cast<index_dense_t*>(index), vector, scalar_kind_to_cpp(kind), results_limit);
279
279
  if (!result) {
@@ -294,7 +294,7 @@ USEARCH_EXPORT size_t usearch_get( //
294
294
 
295
295
  USEARCH_EXPORT size_t usearch_remove(usearch_index_t index, usearch_key_t key, usearch_error_t* error) {
296
296
 
297
- assert(index && error);
297
+ assert(index && error && "Missing arguments");
298
298
  labeling_result_t result = reinterpret_cast<index_dense_t*>(index)->remove(key);
299
299
  if (!result)
300
300
  *error = result.error.release();
@@ -304,7 +304,7 @@ USEARCH_EXPORT size_t usearch_remove(usearch_index_t index, usearch_key_t key, u
304
304
  USEARCH_EXPORT size_t usearch_rename( //
305
305
  usearch_index_t index, usearch_key_t from, usearch_key_t to, usearch_error_t* error) {
306
306
 
307
- assert(index && error);
307
+ assert(index && error && "Missing arguments");
308
308
  labeling_result_t result = reinterpret_cast<index_dense_t*>(index)->rename(from, to);
309
309
  if (!result)
310
310
  *error = result.error.release();
@@ -330,6 +330,8 @@ USEARCH_EXPORT void usearch_exact_search( //
330
330
  usearch_distance_t* distances, size_t distances_stride, //
331
331
  usearch_error_t* error) {
332
332
 
333
+ assert(dataset && queries && keys && distances && error && "Missing arguments");
334
+
333
335
  metric_punned_t metric(dimensions, metric_kind_to_cpp(metric_kind), scalar_kind_to_cpp(scalar_kind));
334
336
  executor_default_t executor(threads);
335
337
  static exact_search_t search;
package/c/test.c CHANGED
@@ -1,5 +1,5 @@
1
1
  #include <errno.h>
2
- #include <stdio.h>
2
+ #include <stdio.h> // `remove`
3
3
  #include <stdlib.h>
4
4
  #include <sys/stat.h>
5
5
 
@@ -236,7 +236,13 @@ void test_save_load(size_t const collection_size, size_t const dimensions) {
236
236
 
237
237
  usearch_error_t error = NULL;
238
238
  usearch_init_options_t opts = create_options(dimensions);
239
- usearch_index_t index = usearch_init(&opts, &error);
239
+ usearch_init_options_t weird_ops = opts;
240
+ weird_ops.connectivity = 11;
241
+ weird_ops.expansion_add = 15;
242
+ weird_ops.expansion_search = 19;
243
+ weird_ops.metric_kind = usearch_metric_pearson_k;
244
+ weird_ops.quantization = usearch_scalar_f64_k;
245
+ usearch_index_t index = usearch_init(&weird_ops, &error);
240
246
  usearch_reserve(index, collection_size, &error);
241
247
 
242
248
  // Add vectors
@@ -248,23 +254,32 @@ void test_save_load(size_t const collection_size, size_t const dimensions) {
248
254
  }
249
255
 
250
256
  // Save and free the index
251
- usearch_save(index, "usearch_index.bin", &error);
257
+ usearch_save(index, "tmp.usearch", &error);
252
258
  ASSERT(!error, error);
253
259
  usearch_free(index, &error);
254
260
  ASSERT(!error, error);
255
261
 
262
+ // Reset the options
263
+ opts.connectivity = 0;
264
+ opts.dimensions = 0;
265
+ opts.expansion_add = 0;
266
+ opts.expansion_search = 0;
267
+ opts.metric = NULL;
268
+ opts.quantization = usearch_scalar_unknown_k;
269
+ opts.metric_kind = usearch_metric_unknown_k;
270
+
256
271
  // Reinit
257
272
  index = usearch_init(&opts, &error);
258
273
  ASSERT(!error, error);
259
274
  ASSERT(usearch_size(index, &error) == 0, error);
260
275
 
261
276
  // Load
262
- usearch_load(index, "usearch_index.bin", &error);
277
+ usearch_load(index, "tmp.usearch", &error);
263
278
  ASSERT(!error, error);
264
279
  ASSERT(usearch_size(index, &error) == collection_size, error);
265
280
  ASSERT(usearch_capacity(index, &error) == collection_size, error);
266
281
  ASSERT(usearch_dimensions(index, &error) == dimensions, error);
267
- ASSERT(usearch_connectivity(index, &error) == opts.connectivity, error);
282
+ ASSERT(usearch_connectivity(index, &error) == weird_ops.connectivity, error);
268
283
 
269
284
  // Check vectors in the index
270
285
  for (size_t i = 0; i < collection_size; ++i) {
@@ -272,8 +287,27 @@ void test_save_load(size_t const collection_size, size_t const dimensions) {
272
287
  ASSERT(usearch_contains(index, key, &error), error);
273
288
  }
274
289
 
290
+ // Create result buffers
291
+ usearch_key_t* keys = (usearch_key_t*)malloc(collection_size * sizeof(usearch_key_t));
292
+ float* distances = (float*)malloc(collection_size * sizeof(float));
293
+ ASSERT(keys && distances, "Failed to allocate memory");
294
+
295
+ // Find the vectors
296
+ for (size_t i = 0; i < collection_size; i++) {
297
+ size_t found_count = usearch_search(index, data + i * dimensions, usearch_scalar_f32_k, collection_size, keys,
298
+ distances, &error);
299
+ ASSERT(!error, error);
300
+ ASSERT(found_count >= 1 && found_count <= collection_size, "Vector is missing");
301
+ }
302
+
275
303
  free(data);
304
+ free(keys);
305
+ free(distances);
276
306
  usearch_free(index, &error);
307
+
308
+ // Remove the file from disk
309
+ remove("tmp.usearch");
310
+
277
311
  printf("Test: Save/Load - PASSED\n");
278
312
  }
279
313
 
@@ -300,7 +334,7 @@ void test_view(size_t const collection_size, size_t const dimensions) {
300
334
  }
301
335
 
302
336
  // Save and free the index
303
- usearch_save(index, "usearch_index.bin", &error);
337
+ usearch_save(index, "tmp.usearch", &error);
304
338
  ASSERT(!error, error);
305
339
  usearch_free(index, &error);
306
340
  ASSERT(!error, error);
@@ -310,7 +344,7 @@ void test_view(size_t const collection_size, size_t const dimensions) {
310
344
  ASSERT(!error, error);
311
345
 
312
346
  // View
313
- usearch_view(index, "usearch_index.bin", &error);
347
+ usearch_view(index, "tmp.usearch", &error);
314
348
  ASSERT(!error, error);
315
349
 
316
350
  free(data);
package/c/usearch.h CHANGED
@@ -39,25 +39,25 @@ USEARCH_EXPORT typedef usearch_distance_t (*usearch_metric_t)(void const*, void
39
39
  */
40
40
  USEARCH_EXPORT typedef enum usearch_metric_kind_t {
41
41
  usearch_metric_unknown_k = 0,
42
- usearch_metric_cos_k,
43
- usearch_metric_ip_k,
44
- usearch_metric_l2sq_k,
45
- usearch_metric_haversine_k,
46
- usearch_metric_divergence_k,
47
- usearch_metric_pearson_k,
48
- usearch_metric_jaccard_k,
49
- usearch_metric_hamming_k,
50
- usearch_metric_tanimoto_k,
51
- usearch_metric_sorensen_k,
42
+ usearch_metric_cos_k = 1,
43
+ usearch_metric_ip_k = 2,
44
+ usearch_metric_l2sq_k = 3,
45
+ usearch_metric_haversine_k = 4,
46
+ usearch_metric_divergence_k = 5,
47
+ usearch_metric_pearson_k = 6,
48
+ usearch_metric_jaccard_k = 7,
49
+ usearch_metric_hamming_k = 8,
50
+ usearch_metric_tanimoto_k = 9,
51
+ usearch_metric_sorensen_k = 10,
52
52
  } usearch_metric_kind_t;
53
53
 
54
54
  USEARCH_EXPORT typedef enum usearch_scalar_kind_t {
55
55
  usearch_scalar_unknown_k = 0,
56
- usearch_scalar_f32_k,
57
- usearch_scalar_f64_k,
58
- usearch_scalar_f16_k,
59
- usearch_scalar_i8_k,
60
- usearch_scalar_b1_k,
56
+ usearch_scalar_f32_k = 1,
57
+ usearch_scalar_f64_k = 2,
58
+ usearch_scalar_f16_k = 3,
59
+ usearch_scalar_i8_k = 4,
60
+ usearch_scalar_b1_k = 5,
61
61
  } usearch_scalar_kind_t;
62
62
 
63
63
  USEARCH_EXPORT typedef struct usearch_init_options_t {
package/conanfile.py CHANGED
@@ -7,7 +7,7 @@ required_conan_version = ">=1.53.0"
7
7
  class USearchConan(ConanFile):
8
8
 
9
9
  name = "usearch"
10
- version = '2.8.16'
10
+ version = '2.9.1'
11
11
  license = "Apache-2.0"
12
12
  description = "Smaller & Faster Single-File Vector Search Engine from Unum"
13
13
  homepage = "https://github.com/unum-cloud/usearch"