usearch 2.8.7 → 2.8.9

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 (113) hide show
  1. package/CITATION.cff +1 -1
  2. package/CMakeLists.txt +3 -3
  3. package/CONTRIBUTING.md +26 -3
  4. package/Cargo.toml +1 -1
  5. package/Dockerfile +16 -0
  6. package/README.md +41 -38
  7. package/VERSION +1 -0
  8. package/binding.gyp +57 -8
  9. package/conanfile.py +1 -1
  10. package/include/usearch/index.hpp +1 -1
  11. package/include/usearch/index_plugins.hpp +28 -24
  12. package/javascript/README.md +64 -12
  13. package/javascript/lib.cpp +11 -3
  14. package/javascript/usearch.js +4 -2
  15. package/javascript/usearch.test.js +15 -0
  16. package/package.json +1 -2
  17. package/setup.py +76 -15
  18. package/simsimd/README.md +14 -13
  19. package/simsimd/include/simsimd/probability.h +2 -2
  20. package/simsimd/package.json +1 -1
  21. package/wasmer.toml +1 -1
  22. package/. npmignore +0 -14
  23. package/.gitignore +0 -95
  24. package/.vscode/launch.json +0 -181
  25. package/.vscode/settings.json +0 -180
  26. package/.vscode/tasks.json +0 -71
  27. package/Package.swift +0 -41
  28. package/csharp/.editorconfig +0 -361
  29. package/csharp/Cloud.Unum.USearch.sln +0 -34
  30. package/csharp/DEV_SETUP.md +0 -51
  31. package/csharp/Directory.Build.props +0 -29
  32. package/csharp/README.md +0 -74
  33. package/csharp/build_and_test.cmd +0 -31
  34. package/csharp/build_and_test.sh +0 -30
  35. package/csharp/nuget/nuget-package.props +0 -33
  36. package/csharp/pack.sh +0 -56
  37. package/csharp/src/Cloud.Unum.USearch.Tests/Cloud.Unum.USearch.Tests.csproj +0 -39
  38. package/csharp/src/Cloud.Unum.USearch.Tests/USearchIndexTests.cs +0 -1013
  39. package/csharp/src/Cloud.Unum.USearch.Tests/Usings.cs +0 -1
  40. package/docs/_static/custom.css +0 -26
  41. package/docs/_static/custom.js +0 -7
  42. package/docs/benchmarks.md +0 -245
  43. package/docs/benchmarks.rst +0 -5
  44. package/docs/c/index.rst +0 -11
  45. package/docs/c/reference.rst +0 -7
  46. package/docs/conf.dox +0 -2668
  47. package/docs/conf.py +0 -53
  48. package/docs/contributing.rst +0 -5
  49. package/docs/cpp/index.rst +0 -11
  50. package/docs/cpp/reference.rst +0 -17
  51. package/docs/csharp/index.rst +0 -6
  52. package/docs/format.md +0 -86
  53. package/docs/format.rst +0 -5
  54. package/docs/golang/index.rst +0 -6
  55. package/docs/index.rst +0 -33
  56. package/docs/java/index.rst +0 -11
  57. package/docs/java/reference.rst +0 -7
  58. package/docs/javascript/index.rst +0 -11
  59. package/docs/javascript/reference.rst +0 -12
  60. package/docs/python/index.rst +0 -11
  61. package/docs/python/reference.rst +0 -42
  62. package/docs/rust/index.rst +0 -6
  63. package/docs/swift/index.rst +0 -6
  64. package/docs/wolfram/index.rst +0 -6
  65. package/golang/README.md +0 -95
  66. package/golang/go.mod +0 -3
  67. package/golang/lib.go +0 -379
  68. package/golang/lib_test.go +0 -108
  69. package/java/README.md +0 -22
  70. package/java/cloud/unum/usearch/Index.java +0 -337
  71. package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +0 -197
  72. package/java/cloud/unum/usearch/cloud_unum_usearch_Index.h +0 -125
  73. package/java/test/IndexTest.java +0 -30
  74. package/objc/USearchObjective.mm +0 -299
  75. package/objc/include/USearchObjective.h +0 -154
  76. package/python/README.md +0 -292
  77. package/python/lib.cpp +0 -1216
  78. package/python/scripts/bench.ipynb +0 -193
  79. package/python/scripts/bench.py +0 -137
  80. package/python/scripts/bench_exact.py +0 -44
  81. package/python/scripts/cluster.ipynb +0 -160
  82. package/python/scripts/index_faiss.py +0 -100
  83. package/python/scripts/join.py +0 -155
  84. package/python/scripts/test_index.py +0 -247
  85. package/python/scripts/test_jit.py +0 -231
  86. package/python/scripts/test_sparse.py +0 -32
  87. package/python/scripts/test_tooling.py +0 -133
  88. package/python/usearch/__init__.py +0 -0
  89. package/python/usearch/client.py +0 -124
  90. package/python/usearch/eval.py +0 -470
  91. package/python/usearch/index.py +0 -1401
  92. package/python/usearch/io.py +0 -113
  93. package/python/usearch/numba.py +0 -121
  94. package/python/usearch/server.py +0 -137
  95. package/rust/README.md +0 -66
  96. package/rust/lib.cpp +0 -136
  97. package/rust/lib.hpp +0 -69
  98. package/rust/lib.rs +0 -610
  99. package/simsimd/CMakeLists.txt +0 -67
  100. package/simsimd/cpp/bench.cxx +0 -206
  101. package/simsimd/package-ci.json +0 -10
  102. package/simsimd/setup.py +0 -86
  103. package/swift/Index+Sugar.swift +0 -153
  104. package/swift/README.md +0 -48
  105. package/swift/Test.swift +0 -37
  106. package/swift/USearch.swift +0 -8
  107. package/wasm/CMakeLists.txt +0 -7
  108. package/wasm/README.md +0 -13
  109. package/wasm/lib.cpp +0 -5
  110. package/wolfram/CMakeLists.txt +0 -18
  111. package/wolfram/README.md +0 -13
  112. package/wolfram/lib.cpp +0 -160
  113. package/wolfram/test.wls +0 -27
@@ -1,113 +0,0 @@
1
- import os
2
- import struct
3
- import typing
4
-
5
- import numpy as np
6
-
7
-
8
- def numpy_scalar_size(dtype) -> int:
9
- return {
10
- np.float64: 8,
11
- np.int64: 8,
12
- np.uint64: 8,
13
- np.float32: 4,
14
- np.int32: 4,
15
- np.uint32: 4,
16
- np.float16: 2,
17
- np.int16: 2,
18
- np.uint16: 2,
19
- np.int8: 1,
20
- np.uint8: 1,
21
- }[dtype]
22
-
23
-
24
- def guess_numpy_dtype_from_filename(filename) -> typing.Optional[type]:
25
- if filename.endswith(".fbin"):
26
- return np.float32
27
- elif filename.endswith(".dbin"):
28
- return np.float64
29
- elif filename.endswith(".hbin"):
30
- return np.float16
31
- elif filename.endswith(".ibin"):
32
- return np.int32
33
- elif filename.endswith(".bbin"):
34
- return np.uint8
35
- else:
36
- return None
37
-
38
-
39
- def load_matrix(
40
- filename: str,
41
- start_row: int = 0,
42
- count_rows: int = None,
43
- view: bool = False,
44
- dtype: typing.Optional[type] = None,
45
- ) -> typing.Optional[np.ndarray]:
46
- """Read *.ibin, *.bbib, *.hbin, *.fbin, *.dbin files with matrices.
47
-
48
- :param filename: path to the matrix file
49
- :param start_row: start reading vectors from this index
50
- :param count_rows: number of vectors to read. If None, read all vectors
51
- :param view: set to `True` to memory-map the file instead of loading to RAM
52
-
53
- :return: parsed matrix
54
- :rtype: numpy.ndarray
55
- """
56
- if dtype is None:
57
- dtype = guess_numpy_dtype_from_filename(filename)
58
- if dtype is None:
59
- raise Exception("Unknown file type")
60
- scalar_size = numpy_scalar_size(dtype)
61
-
62
- if not os.path.exists(filename):
63
- return None
64
-
65
- with open(filename, "rb") as f:
66
- rows, cols = np.fromfile(f, count=2, dtype=np.int32)
67
- rows = (rows - start_row) if count_rows is None else count_rows
68
- row_offset = start_row * scalar_size * cols
69
-
70
- if view:
71
- return np.memmap(
72
- f,
73
- dtype=dtype,
74
- mode="r",
75
- offset=8 + row_offset,
76
- shape=(rows, cols),
77
- )
78
- else:
79
- return np.fromfile(
80
- f,
81
- count=rows * cols,
82
- dtype=dtype,
83
- offset=row_offset,
84
- ).reshape(rows, cols)
85
-
86
-
87
- def save_matrix(vectors: np.ndarray, filename: str):
88
- """Write *.ibin, *.bbib, *.hbin, *.fbin, *.dbin files with matrices.
89
-
90
- :param vectors: the matrix to serialize
91
- :type vectors: numpy.ndarray
92
- :param filename: path to the matrix file
93
- :type filename: str
94
- """
95
- if filename.endswith(".fbin"):
96
- dtype = np.float32
97
- elif filename.endswith(".dbin"):
98
- dtype = np.float64
99
- elif filename.endswith(".hbin"):
100
- dtype = np.float16
101
- elif filename.endswith(".ibin"):
102
- dtype = np.int32
103
- elif filename.endswith(".bbin"):
104
- dtype = np.uint8
105
- else:
106
- dtype = vectors.dtype
107
-
108
- assert len(vectors.shape) == 2, "Input array must have 2 dimensions"
109
- with open(filename, "wb") as f:
110
- count, dim = vectors.shape
111
- f.write(struct.pack("<i", count))
112
- f.write(struct.pack("<i", dim))
113
- vectors.astype(dtype).flatten().tofile(f)
@@ -1,121 +0,0 @@
1
- # The purpose of this file is to provide Pythonic wrapper on top
2
- # the native precompiled CPython module. It improves compatibility
3
- # Python tooling, linters, and static analyzers. It also embeds JIT
4
- # into the primary `Index` class, connecting USearch with Numba.
5
- from math import sqrt
6
-
7
- from usearch.index import MetricKind, ScalarKind, MetricSignature, CompiledMetric
8
-
9
-
10
- def jit(
11
- ndim: int,
12
- metric: MetricKind = MetricKind.Cos,
13
- dtype: ScalarKind = ScalarKind.F32,
14
- ) -> CompiledMetric:
15
- """JIT-compiles the metric for target hardware and number of dimensions.
16
-
17
- This can result in up-to 3x performance difference on very large vectors
18
- and very recent hardware, as the Python module is compiled with high
19
- compatibility in mind and avoids very fancy assembly instructions.
20
-
21
- Uses Numba `cfunc` functionality, annotating it with Numba `types` instead
22
- of `ctypes` to support half-precision.
23
- https://numba.readthedocs.io/en/stable/reference/jit-compilation.html#c-callbacks
24
- """
25
- assert isinstance(metric, MetricKind)
26
- assert isinstance(dtype, ScalarKind)
27
-
28
- from numba import cfunc, types, carray
29
-
30
- signature_i8args = types.float32(
31
- types.CPointer(types.int8), types.CPointer(types.int8)
32
- )
33
-
34
- signature_f16args = types.float32(
35
- types.CPointer(types.float16), types.CPointer(types.float16)
36
- )
37
-
38
- signature_f32args = types.float32(
39
- types.CPointer(types.float32), types.CPointer(types.float32)
40
- )
41
-
42
- signature_f64args = types.float32(
43
- types.CPointer(types.float64), types.CPointer(types.float64)
44
- )
45
-
46
- numba_supported_types = (
47
- ScalarKind.I8,
48
- # Half-precision is still unsupported
49
- # https://github.com/numba/numba/issues/4402
50
- # ScalarKind.F16: np.float16,
51
- ScalarKind.F32,
52
- ScalarKind.F64,
53
- )
54
- if dtype not in numba_supported_types:
55
- return metric
56
-
57
- scalar_kind_to_accumulator_type = {
58
- ScalarKind.I8: types.int32,
59
- ScalarKind.F16: types.float16,
60
- ScalarKind.F32: types.float32,
61
- ScalarKind.F64: types.float64,
62
- }
63
- accumulator = scalar_kind_to_accumulator_type[dtype]
64
-
65
- def numba_ip(a, b):
66
- a_array = carray(a, ndim)
67
- b_array = carray(b, ndim)
68
- ab = accumulator(0)
69
- for i in range(ndim):
70
- ab += a_array[i] * b_array[i]
71
- return types.float32(1 - ab)
72
-
73
- def numba_cos(a, b):
74
- a_array = carray(a, ndim)
75
- b_array = carray(b, ndim)
76
- ab = accumulator(0)
77
- a_sq = accumulator(0)
78
- b_sq = accumulator(0)
79
- for i in range(ndim):
80
- ab += a_array[i] * b_array[i]
81
- a_sq += a_array[i] * a_array[i]
82
- b_sq += b_array[i] * b_array[i]
83
- a_norm = sqrt(a_sq)
84
- b_norm = sqrt(b_sq)
85
- if a_norm == 0 and b_norm == 0:
86
- return types.float32(0)
87
- elif a_norm == 0 or b_norm == 0 or ab == 0:
88
- return types.float32(1)
89
- else:
90
- return types.float32(1 - ab / (a_norm * b_norm))
91
-
92
- def numba_l2sq(a, b):
93
- a_array = carray(a, ndim)
94
- b_array = carray(b, ndim)
95
- ab_delta_sq = accumulator(0)
96
- for i in range(ndim):
97
- ab_delta_sq += (a_array[i] - b_array[i]) * (a_array[i] - b_array[i])
98
- return types.float32(ab_delta_sq)
99
-
100
- scalar_kind_to_signature = {
101
- ScalarKind.I8: signature_i8args,
102
- ScalarKind.F16: signature_f16args,
103
- ScalarKind.F32: signature_f32args,
104
- ScalarKind.F64: signature_f64args,
105
- }
106
-
107
- metric_kind_to_function = {
108
- MetricKind.IP: numba_ip,
109
- MetricKind.Cos: numba_cos,
110
- MetricKind.L2sq: numba_l2sq,
111
- }
112
-
113
- if dtype == ScalarKind.I8 and metric == MetricKind.IP:
114
- metric = MetricKind.Cos
115
-
116
- pointer = cfunc(scalar_kind_to_signature[dtype])(metric_kind_to_function[metric])
117
- return CompiledMetric(
118
- pointer=pointer.address,
119
- kind=metric,
120
- signature=MetricSignature.ArrayArray,
121
- )
@@ -1,137 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
-
4
- import os
5
- import argparse
6
- import numpy as np
7
- from typing import List
8
-
9
- from ucall.rich_posix import Server
10
- from usearch.index import Index, Matches, Key
11
-
12
-
13
- def _ascii_to_vector(string: str) -> np.ndarray:
14
- """
15
- WARNING: A dirty performance hack!
16
- Assuming the `i8` vectors in our implementations are just integers,
17
- and generally contain scalars in the [0, 100] range, we can transmit
18
- them as JSON-embedded strings. The only symbols we must avoid are
19
- the double-quote '"' (code 22) and backslash '\' (code 60).
20
- Printable ASCII characters are in [20, 126].
21
- """
22
- vector = np.array(string, dtype=np.int8)
23
- vector[vector == 124] = 60
24
- vector -= 23
25
- return vector
26
-
27
-
28
- def serve(
29
- ndim_: int,
30
- metric: str = "ip",
31
- port: int = 8545,
32
- threads: int = 1,
33
- path: str = "index.usearch",
34
- immutable: bool = False,
35
- ):
36
- server = Server(port=port)
37
- index = Index(ndim=ndim_, metric=metric)
38
-
39
- if os.path.exists(path):
40
- if immutable:
41
- index.view(path)
42
- else:
43
- index.load(path)
44
-
45
- @server
46
- def size() -> int:
47
- return len(index)
48
-
49
- @server
50
- def ndim() -> int:
51
- return index.ndim
52
-
53
- @server
54
- def capacity() -> int:
55
- return index.capacity()
56
-
57
- @server
58
- def connectivity() -> int:
59
- return index.connectivity()
60
-
61
- @server
62
- def add_one(key: int, vector: np.ndarray):
63
- print("adding", key, vector)
64
- keys = np.array([key], dtype=Key)
65
- vectors = vector.flatten().reshape(vector.shape[0], 1)
66
- index.add(keys, vectors)
67
-
68
- @server
69
- def add_many(keys: np.ndarray, vectors: np.ndarray):
70
- index.add(keys, vectors, threads=threads)
71
-
72
- @server
73
- def search_one(vector: np.ndarray, count: int) -> List[dict]:
74
- print("search", vector, count)
75
- vectors = vector.reshape(vector.shape[0], 1)
76
- results: Matches = index.search(vectors, count)
77
- return results.to_list()
78
-
79
- @server
80
- def search_many(vectors: np.ndarray, count: int) -> List[List[dict]]:
81
- results: Matches = index.search(vectors, count)
82
- return results.to_list()
83
-
84
- @server
85
- def add_ascii(key: int, string: str):
86
- return add_one(key, _ascii_to_vector(string))
87
-
88
- @server
89
- def search_ascii(string: str, count: int):
90
- return search_one(_ascii_to_vector(string), count)
91
-
92
- try:
93
- server.run()
94
- except KeyboardInterrupt:
95
- if not immutable:
96
- index.save(path)
97
-
98
-
99
- if __name__ == "__main__":
100
- parser = argparse.ArgumentParser()
101
- parser.add_argument("-v", "--verbose", help="log server activity")
102
- parser.add_argument("--ndim", type=int, help="dimensionality of the vectors")
103
- parser.add_argument(
104
- "--immutable", type=bool, default=False, help="the index can not be updated"
105
- )
106
-
107
- parser.add_argument(
108
- "--metric",
109
- type=str,
110
- default="ip",
111
- choices=["ip", "cos", "l2sq", "haversine"],
112
- help="distance function to compare vectors",
113
- )
114
- parser.add_argument(
115
- "-p",
116
- "--port",
117
- type=int,
118
- default=8545,
119
- help="port to open for client connections",
120
- )
121
- parser.add_argument(
122
- "-j", "--threads", type=int, default=1, help="number of CPU threads to use"
123
- )
124
- parser.add_argument(
125
- "--path", type=str, default="index.usearch", help="where to store the index"
126
- )
127
-
128
- args = parser.parse_args()
129
- assert args.ndim is not None, "Define the number of dimensions!"
130
- serve(
131
- ndim_=args.ndim,
132
- metric=args.metric,
133
- threads=args.threads,
134
- port=args.port,
135
- path=args.path,
136
- immutable=args.immutable,
137
- )
package/rust/README.md DELETED
@@ -1,66 +0,0 @@
1
- # USearch for Rust
2
-
3
- ## Installation
4
-
5
- ```sh
6
- cargo add usearch
7
- ```
8
-
9
- You can find [interface documentation on docs.rs](https://docs.rs/usearch/2.3.0/usearch/ffi/struct.Index.html).
10
-
11
- ## Quickstart
12
-
13
- ```rust
14
-
15
- let options = IndexOptions {
16
- dimensions: 3,
17
- metric: MetricKind::IP,
18
- quantization: ScalarKind::F16,
19
- connectivity: 0,
20
- expansion_add: 0,
21
- expansion_search: 0
22
- };
23
-
24
- let index = new_index(&options).unwrap();
25
-
26
- assert!(index.reserve(10).is_ok());
27
- assert!(index.capacity() >= 10);
28
- assert!(index.connectivity() != 0);
29
- assert_eq!(index.dimensions(), 3);
30
- assert_eq!(index.size(), 0);
31
-
32
- let first: [f32; 3] = [0.2, 0.1, 0.2];
33
- let second: [f32; 3] = [0.2, 0.1, 0.2];
34
-
35
- assert!(index.add(42, &first).is_ok());
36
- assert!(index.add(43, &second).is_ok());
37
- assert_eq!(index.size(), 2);
38
-
39
- // Read back the tags
40
- let results = index.search(&first, 10).unwrap();
41
- assert_eq!(results.keys.len(), 2);
42
- ```
43
-
44
- ## Serialization
45
-
46
- ```rust
47
- assert!(index.save("index.usearch").is_ok());
48
- assert!(index.load("index.usearch").is_ok());
49
- assert!(index.view("index.usearch").is_ok());
50
- ```
51
-
52
- Similarly, serializing to/from buffers is supported.
53
-
54
- ```rust
55
- assert!(index.save_to_buffer(&mut serialization_buffer).is_ok());
56
- assert!(index.load_from_buffer(&serialization_buffer).is_ok());
57
- assert!(index.view_from_buffer(&serialization_buffer).is_ok());
58
- ```
59
-
60
- ## Metrics
61
-
62
- ```rust
63
- assert!(new_l2sq(3, &quant, 0, 0, 0).is_ok());
64
- assert!(new_cos(3, &quant, 0, 0, 0).is_ok());
65
- assert!(new_haversine(&quant, 0, 0, 0).is_ok());
66
- ```
package/rust/lib.cpp DELETED
@@ -1,136 +0,0 @@
1
- #include "lib.hpp"
2
- #include "usearch/rust/lib.rs.h"
3
-
4
- using namespace unum::usearch;
5
- using namespace unum;
6
-
7
- using index_t = index_dense_t;
8
- using add_result_t = typename index_t::add_result_t;
9
- using search_result_t = typename index_t::search_result_t;
10
- using labeling_result_t = typename index_t::labeling_result_t;
11
- using vector_key_t = typename index_dense_t::vector_key_t;
12
-
13
- template <typename scalar_at> Matches search_(index_dense_t& index, scalar_at const* vec, size_t count) {
14
- Matches matches;
15
- matches.keys.reserve(count);
16
- matches.distances.reserve(count);
17
- for (size_t i = 0; i != count; ++i)
18
- matches.keys.push_back(0), matches.distances.push_back(0);
19
- search_result_t result = index.search(vec, count);
20
- result.error.raise();
21
- count = result.dump_to(matches.keys.data(), matches.distances.data());
22
- matches.keys.truncate(count);
23
- matches.distances.truncate(count);
24
- return matches;
25
- }
26
-
27
- NativeIndex::NativeIndex(std::unique_ptr<index_t> index) : index_(std::move(index)) {}
28
-
29
- // clang-format off
30
- void NativeIndex::add_i8(vector_key_t key, rust::Slice<int8_t const> vec) const { index_->add(key, vec.data()).error.raise(); }
31
- void NativeIndex::add_f16(vector_key_t key, rust::Slice<uint16_t const> vec) const { index_->add(key, (f16_t const*)vec.data()).error.raise(); }
32
- void NativeIndex::add_f32(vector_key_t key, rust::Slice<float const> vec) const { index_->add(key, vec.data()).error.raise(); }
33
- void NativeIndex::add_f64(vector_key_t key, rust::Slice<double const> vec) const { index_->add(key, vec.data()).error.raise(); }
34
-
35
- Matches NativeIndex::search_i8(rust::Slice<int8_t const> vec, size_t count) const { return search_(*index_, vec.data(), count); }
36
- Matches NativeIndex::search_f16(rust::Slice<uint16_t const> vec, size_t count) const { return search_(*index_, (f16_t const*)vec.data(), count); }
37
- Matches NativeIndex::search_f32(rust::Slice<float const> vec, size_t count) const { return search_(*index_, vec.data(), count); }
38
- Matches NativeIndex::search_f64(rust::Slice<double const> vec, size_t count) const { return search_(*index_, vec.data(), count); }
39
-
40
- size_t NativeIndex::get_i8(vector_key_t key, rust::Slice<int8_t> vec) const { if (vec.size() % dimensions()) throw std::invalid_argument("Vector length must be a multiple of index dimensionality"); return index_->get(key, vec.data(), vec.size() / dimensions()); }
41
- size_t NativeIndex::get_f16(vector_key_t key, rust::Slice<uint16_t> vec) const { if (vec.size() % dimensions()) throw std::invalid_argument("Vector length must be a multiple of index dimensionality"); return index_->get(key, (f16_t*)vec.data(), vec.size() / dimensions()); }
42
- size_t NativeIndex::get_f32(vector_key_t key, rust::Slice<float> vec) const { if (vec.size() % dimensions()) throw std::invalid_argument("Vector length must be a multiple of index dimensionality"); return index_->get(key, vec.data(), vec.size() / dimensions()); }
43
- size_t NativeIndex::get_f64(vector_key_t key, rust::Slice<double> vec) const { if (vec.size() % dimensions()) throw std::invalid_argument("Vector length must be a multiple of index dimensionality"); return index_->get(key, vec.data(), vec.size() / dimensions()); }
44
- // clang-format on
45
-
46
- size_t NativeIndex::expansion_add() const { return index_->expansion_add(); }
47
- size_t NativeIndex::expansion_search() const { return index_->expansion_search(); }
48
- void NativeIndex::change_expansion_add(size_t n) const { index_->change_expansion_add(n); }
49
- void NativeIndex::change_expansion_search(size_t n) const { index_->change_expansion_search(n); }
50
-
51
- size_t NativeIndex::remove(vector_key_t key) const {
52
- labeling_result_t result = index_->remove(key);
53
- result.error.raise();
54
- return result.completed;
55
- }
56
-
57
- size_t NativeIndex::rename(vector_key_t from, vector_key_t to) const {
58
- labeling_result_t result = index_->rename(from, to);
59
- result.error.raise();
60
- return result.completed;
61
- }
62
-
63
- size_t NativeIndex::count(vector_key_t key) const { return index_->count(key); }
64
- bool NativeIndex::contains(vector_key_t key) const { return index_->contains(key); }
65
-
66
- void NativeIndex::reserve(size_t capacity) const { index_->reserve(capacity); }
67
-
68
- size_t NativeIndex::dimensions() const { return index_->dimensions(); }
69
- size_t NativeIndex::connectivity() const { return index_->connectivity(); }
70
- size_t NativeIndex::size() const { return index_->size(); }
71
- size_t NativeIndex::capacity() const { return index_->capacity(); }
72
- size_t NativeIndex::serialized_length() const { return index_->serialized_length(); }
73
-
74
- void NativeIndex::save(rust::Str path) const { index_->save(output_file_t(std::string(path).c_str())).error.raise(); }
75
- void NativeIndex::load(rust::Str path) const { index_->load(input_file_t(std::string(path).c_str())).error.raise(); }
76
- void NativeIndex::view(rust::Str path) const {
77
- index_->view(memory_mapped_file_t(std::string(path).c_str())).error.raise();
78
- }
79
-
80
- void NativeIndex::reset() const { index_->reset(); }
81
- size_t NativeIndex::memory_usage() const { return index_->memory_usage(); }
82
-
83
- void NativeIndex::save_to_buffer(rust::Slice<uint8_t> buffer) const {
84
- index_->save(memory_mapped_file_t((byte_t*)buffer.data(), buffer.size())).error.raise();
85
- }
86
-
87
- void NativeIndex::load_from_buffer(rust::Slice<uint8_t const> buffer) const {
88
- index_->load(memory_mapped_file_t((byte_t*)buffer.data(), buffer.size())).error.raise();
89
- }
90
-
91
- void NativeIndex::view_from_buffer(rust::Slice<uint8_t const> buffer) const {
92
- index_->view(memory_mapped_file_t((byte_t*)buffer.data(), buffer.size())).error.raise();
93
- }
94
-
95
- std::unique_ptr<NativeIndex> wrap(index_t&& index) {
96
- std::unique_ptr<index_t> punned_ptr;
97
- punned_ptr.reset(new index_t(std::move(index)));
98
- std::unique_ptr<NativeIndex> result;
99
- result.reset(new NativeIndex(std::move(punned_ptr)));
100
- return result;
101
- }
102
-
103
- metric_kind_t rust_to_cpp_metric(MetricKind value) {
104
- switch (value) {
105
- case MetricKind::IP: return metric_kind_t::ip_k;
106
- case MetricKind::L2sq: return metric_kind_t::l2sq_k;
107
- case MetricKind::Cos: return metric_kind_t::cos_k;
108
- case MetricKind::Pearson: return metric_kind_t::pearson_k;
109
- case MetricKind::Haversine: return metric_kind_t::haversine_k;
110
- case MetricKind::Divergence: return metric_kind_t::divergence_k;
111
- case MetricKind::Hamming: return metric_kind_t::hamming_k;
112
- case MetricKind::Tanimoto: return metric_kind_t::tanimoto_k;
113
- case MetricKind::Sorensen: return metric_kind_t::sorensen_k;
114
- default: return metric_kind_t::unknown_k;
115
- }
116
- }
117
-
118
- scalar_kind_t rust_to_cpp_scalar(ScalarKind value) {
119
- switch (value) {
120
- case ScalarKind::I8: return scalar_kind_t::i8_k;
121
- case ScalarKind::F16: return scalar_kind_t::f16_k;
122
- case ScalarKind::F32: return scalar_kind_t::f32_k;
123
- case ScalarKind::F64: return scalar_kind_t::f64_k;
124
- case ScalarKind::B1: return scalar_kind_t::b1x8_k;
125
- default: return scalar_kind_t::unknown_k;
126
- }
127
- }
128
-
129
- std::unique_ptr<NativeIndex> new_native_index(IndexOptions const& options) {
130
- metric_kind_t metric_kind = rust_to_cpp_metric(options.metric);
131
- scalar_kind_t scalar_kind = rust_to_cpp_scalar(options.quantization);
132
- metric_punned_t metric(options.dimensions, metric_kind, scalar_kind);
133
- index_dense_config_t config(options.connectivity, options.expansion_add, options.expansion_search);
134
- config.multi = options.multi;
135
- return wrap(index_t::make(metric, config));
136
- }
package/rust/lib.hpp DELETED
@@ -1,69 +0,0 @@
1
- #pragma once
2
- #include "rust/cxx.h"
3
-
4
- #include <memory> // `std::shared_ptr`
5
-
6
- #include <usearch/index_dense.hpp>
7
-
8
- struct Matches;
9
- struct IndexOptions;
10
-
11
- class NativeIndex {
12
- public:
13
- using metric_t = unum::usearch::metric_punned_t;
14
- using distance_t = unum::usearch::distance_punned_t;
15
- using index_dense_t = unum::usearch::index_dense_t;
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 vector_key_t = typename index_dense_t::vector_key_t;
19
-
20
- NativeIndex(std::unique_ptr<index_dense_t> index);
21
-
22
- void reserve(size_t) const;
23
-
24
- void add_i8(vector_key_t key, rust::Slice<int8_t const> vector) const;
25
- void add_f16(vector_key_t key, rust::Slice<uint16_t const> vector) const;
26
- void add_f32(vector_key_t key, rust::Slice<float const> vector) const;
27
- void add_f64(vector_key_t key, rust::Slice<double const> vector) const;
28
-
29
- Matches search_i8(rust::Slice<int8_t const> vector, size_t count) const;
30
- Matches search_f16(rust::Slice<uint16_t const> vector, size_t count) const;
31
- Matches search_f32(rust::Slice<float const> vector, size_t count) const;
32
- Matches search_f64(rust::Slice<double const> vector, size_t count) const;
33
-
34
- size_t get_i8(vector_key_t key, rust::Slice<int8_t> vector) const;
35
- size_t get_f16(vector_key_t key, rust::Slice<uint16_t> vector) const;
36
- size_t get_f32(vector_key_t key, rust::Slice<float> vector) const;
37
- size_t get_f64(vector_key_t key, rust::Slice<double> vector) const;
38
-
39
- size_t expansion_add() const;
40
- size_t expansion_search() const;
41
- void change_expansion_add(size_t n) const;
42
- void change_expansion_search(size_t n) const;
43
-
44
- size_t count(vector_key_t key) const;
45
- size_t remove(vector_key_t key) const;
46
- size_t rename(vector_key_t from, vector_key_t to) const;
47
- bool contains(vector_key_t key) const;
48
-
49
- size_t dimensions() const;
50
- size_t connectivity() const;
51
- size_t size() const;
52
- size_t capacity() const;
53
- size_t serialized_length() const;
54
-
55
- void save(rust::Str path) const;
56
- void load(rust::Str path) const;
57
- void view(rust::Str path) const;
58
- void reset() const;
59
- size_t memory_usage() const;
60
-
61
- void save_to_buffer(rust::Slice<uint8_t> buffer) const;
62
- void load_from_buffer(rust::Slice<uint8_t const> buffer) const;
63
- void view_from_buffer(rust::Slice<uint8_t const> buffer) const;
64
-
65
- private:
66
- std::unique_ptr<index_dense_t> index_;
67
- };
68
-
69
- std::unique_ptr<NativeIndex> new_native_index(IndexOptions const& options);