usearch 1.2.1 → 1.3.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.
- package/.github/workflows/prerelease.yml +26 -0
- package/.github/workflows/release.yml +1 -1
- package/CMakeLists.txt +1 -0
- package/Cargo.toml +1 -1
- package/README.md +16 -10
- package/c/lib.cpp +35 -1
- package/c/test.c +117 -114
- package/c/usearch.h +28 -1
- package/conanfile.py +1 -1
- package/cpp/test.cpp +2 -2
- package/docs/benchmarks.md +6 -6
- package/docs/compilation.md +1 -1
- package/include/usearch/index.hpp +173 -53
- package/include/usearch/index_dense.hpp +194 -57
- package/include/usearch/index_plugins.hpp +34 -20
- package/package.json +2 -2
- package/pyproject.toml +1 -1
- package/python/lib.cpp +93 -31
- package/python/scripts/test_index.py +38 -10
- package/python/usearch/index.py +87 -37
- package/rust/README.md +2 -2
- package/rust/lib.cpp +15 -4
- package/rust/lib.hpp +5 -0
- package/rust/lib.rs +75 -43
- package/wasmer.toml +1 -1
package/rust/lib.rs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#[cxx::bridge]
|
|
2
2
|
pub mod ffi {
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
// Shared structs with fields visible to both languages.
|
|
5
5
|
struct Matches {
|
|
6
6
|
keys: Vec<u64>,
|
|
@@ -43,20 +43,20 @@ pub mod ffi {
|
|
|
43
43
|
type Index;
|
|
44
44
|
|
|
45
45
|
/// Initializes a new instance of the index with the provided options.
|
|
46
|
-
///
|
|
46
|
+
///
|
|
47
47
|
/// # Arguments
|
|
48
|
-
///
|
|
48
|
+
///
|
|
49
49
|
/// * `options` - A reference to the `IndexOptions` structure containing initialization options.
|
|
50
|
-
///
|
|
50
|
+
///
|
|
51
51
|
/// # Returns
|
|
52
|
-
///
|
|
52
|
+
///
|
|
53
53
|
/// A `Result` which is `Ok` if the index is successfully initialized, or `Err` if an error occurs.
|
|
54
54
|
pub fn new_index(options: &IndexOptions) -> Result<UniquePtr<Index>>;
|
|
55
55
|
|
|
56
56
|
/// Reserves memory for a specified number of incoming vectors.
|
|
57
|
-
///
|
|
57
|
+
///
|
|
58
58
|
/// # Arguments
|
|
59
|
-
///
|
|
59
|
+
///
|
|
60
60
|
/// * `capacity` - The desired total capacity including the current size.
|
|
61
61
|
pub fn reserve(self: &Index, capacity: usize) -> Result<()>;
|
|
62
62
|
|
|
@@ -72,128 +72,150 @@ pub mod ffi {
|
|
|
72
72
|
/// Retrieves the total capacity of the index, including reserved space.
|
|
73
73
|
pub fn capacity(self: &Index) -> usize;
|
|
74
74
|
|
|
75
|
+
/// Reports expected file size after serialization.
|
|
76
|
+
pub fn serialized_length(self: &Index) -> usize;
|
|
77
|
+
|
|
75
78
|
/// Adds a vector with a specified key to the index.
|
|
76
|
-
///
|
|
79
|
+
///
|
|
77
80
|
/// # Arguments
|
|
78
|
-
///
|
|
81
|
+
///
|
|
79
82
|
/// * `key` - The key associated with the vector.
|
|
80
83
|
/// * `vector` - A slice containing the vector data.
|
|
81
84
|
pub fn add(self: &Index, key: u64, vector: &[f32]) -> Result<()>;
|
|
82
85
|
|
|
83
86
|
/// Performs k-Approximate Nearest Neighbors (kANN) Search for closest vectors to the provided query.
|
|
84
|
-
///
|
|
87
|
+
///
|
|
85
88
|
/// # Arguments
|
|
86
|
-
///
|
|
89
|
+
///
|
|
87
90
|
/// * `query` - A slice containing the query vector data.
|
|
88
91
|
/// * `count` - The maximum number of neighbors to search for.
|
|
89
|
-
///
|
|
92
|
+
///
|
|
90
93
|
/// # Returns
|
|
91
|
-
///
|
|
94
|
+
///
|
|
92
95
|
/// A `Result` containing the matches found.
|
|
93
96
|
pub fn search(self: &Index, query: &[f32], count: usize) -> Result<Matches>;
|
|
94
97
|
|
|
95
98
|
/// Removes the vector associated with the given key from the index.
|
|
96
|
-
///
|
|
99
|
+
///
|
|
97
100
|
/// # Arguments
|
|
98
|
-
///
|
|
101
|
+
///
|
|
99
102
|
/// * `key` - The key of the vector to be removed.
|
|
100
|
-
///
|
|
103
|
+
///
|
|
101
104
|
/// # Returns
|
|
102
|
-
///
|
|
105
|
+
///
|
|
103
106
|
/// `true` if the vector is successfully removed, `false` otherwise.
|
|
104
107
|
pub fn remove(self: &Index, key: u64) -> Result<bool>;
|
|
105
108
|
|
|
106
109
|
/// Renames the vector under a certain key.
|
|
107
|
-
///
|
|
110
|
+
///
|
|
108
111
|
/// # Arguments
|
|
109
|
-
///
|
|
112
|
+
///
|
|
110
113
|
/// * `from` - The key of the vector to be renamed.
|
|
111
114
|
/// * `to` - The new name.
|
|
112
|
-
///
|
|
115
|
+
///
|
|
113
116
|
/// # Returns
|
|
114
|
-
///
|
|
117
|
+
///
|
|
115
118
|
/// `true` if the vector is successfully renamed, `false` otherwise.
|
|
116
119
|
pub fn rename(self: &Index, from: u64, to: u64) -> Result<bool>;
|
|
117
120
|
|
|
118
121
|
/// Checks if the index contains a vector with a specified key.
|
|
119
|
-
///
|
|
122
|
+
///
|
|
120
123
|
/// # Arguments
|
|
121
|
-
///
|
|
124
|
+
///
|
|
122
125
|
/// * `key` - The key to be checked.
|
|
123
|
-
///
|
|
126
|
+
///
|
|
124
127
|
/// # Returns
|
|
125
|
-
///
|
|
128
|
+
///
|
|
126
129
|
/// `true` if the index contains the vector with the given key, `false` otherwise.
|
|
127
130
|
pub fn contains(self: &Index, key: u64) -> bool;
|
|
128
131
|
|
|
129
132
|
/// Saves the index to a specified file.
|
|
130
|
-
///
|
|
133
|
+
///
|
|
131
134
|
/// # Arguments
|
|
132
|
-
///
|
|
135
|
+
///
|
|
133
136
|
/// * `path` - The file path where the index will be saved.
|
|
134
137
|
pub fn save(self: &Index, path: &str) -> Result<()>;
|
|
135
138
|
|
|
136
139
|
/// Loads the index from a specified file.
|
|
137
|
-
///
|
|
140
|
+
///
|
|
138
141
|
/// # Arguments
|
|
139
|
-
///
|
|
142
|
+
///
|
|
140
143
|
/// * `path` - The file path from where the index will be loaded.
|
|
141
144
|
pub fn load(self: &Index, path: &str) -> Result<()>;
|
|
142
145
|
|
|
143
146
|
/// Creates a view of the index from a file without loading it into memory.
|
|
144
|
-
///
|
|
147
|
+
///
|
|
145
148
|
/// # Arguments
|
|
146
|
-
///
|
|
149
|
+
///
|
|
147
150
|
/// * `path` - The file path from where the view will be created.
|
|
148
151
|
pub fn view(self: &Index, path: &str) -> Result<()>;
|
|
149
152
|
|
|
153
|
+
/// Saves the index to a specified file.
|
|
154
|
+
///
|
|
155
|
+
/// # Arguments
|
|
156
|
+
///
|
|
157
|
+
/// * `path` - The file path where the index will be saved.
|
|
158
|
+
pub fn save_to_buffer(self: &Index, buffer: &mut [u8]) -> Result<()>;
|
|
159
|
+
|
|
160
|
+
/// Loads the index from a specified file.
|
|
161
|
+
///
|
|
162
|
+
/// # Arguments
|
|
163
|
+
///
|
|
164
|
+
/// * `path` - The file path from where the index will be loaded.
|
|
165
|
+
pub fn load_from_buffer(self: &Index, buffer: &[u8]) -> Result<()>;
|
|
166
|
+
|
|
167
|
+
/// Creates a view of the index from a file without loading it into memory.
|
|
168
|
+
///
|
|
169
|
+
/// # Arguments
|
|
170
|
+
///
|
|
171
|
+
/// * `path` - The file path from where the view will be created.
|
|
172
|
+
pub fn view_from_buffer(self: &Index, buffer: &[u8]) -> Result<()>;
|
|
173
|
+
|
|
150
174
|
}
|
|
151
175
|
}
|
|
152
176
|
|
|
153
|
-
|
|
154
177
|
#[cfg(test)]
|
|
155
178
|
mod tests {
|
|
179
|
+
use crate::ffi::new_index;
|
|
180
|
+
use crate::ffi::IndexOptions;
|
|
156
181
|
use crate::ffi::MetricKind;
|
|
157
182
|
use crate::ffi::ScalarKind;
|
|
158
|
-
use crate::ffi::IndexOptions;
|
|
159
|
-
use crate::ffi::new_index;
|
|
160
183
|
|
|
161
184
|
#[test]
|
|
162
185
|
fn integration() {
|
|
163
|
-
|
|
164
186
|
let mut options = IndexOptions {
|
|
165
187
|
dimensions: 5,
|
|
166
188
|
metric: MetricKind::IP,
|
|
167
189
|
quantization: ScalarKind::F16,
|
|
168
190
|
connectivity: 0,
|
|
169
191
|
expansion_add: 0,
|
|
170
|
-
expansion_search: 0
|
|
192
|
+
expansion_search: 0,
|
|
171
193
|
};
|
|
172
194
|
|
|
173
195
|
let index = new_index(&options).unwrap();
|
|
174
|
-
|
|
196
|
+
|
|
175
197
|
assert!(index.reserve(10).is_ok());
|
|
176
198
|
assert!(index.capacity() >= 10);
|
|
177
199
|
assert!(index.connectivity() != 0);
|
|
178
200
|
assert_eq!(index.dimensions(), 5);
|
|
179
201
|
assert_eq!(index.size(), 0);
|
|
180
|
-
|
|
202
|
+
|
|
181
203
|
let first: [f32; 5] = [0.2, 0.1, 0.2, 0.1, 0.3];
|
|
182
204
|
let second: [f32; 5] = [0.2, 0.1, 0.2, 0.1, 0.3];
|
|
183
|
-
|
|
205
|
+
|
|
184
206
|
assert!(index.add(42, &first).is_ok());
|
|
185
207
|
assert!(index.add(43, &second).is_ok());
|
|
186
208
|
assert_eq!(index.size(), 2);
|
|
187
|
-
|
|
209
|
+
|
|
188
210
|
// Read back the tags
|
|
189
211
|
let results = index.search(&first, 10).unwrap();
|
|
190
212
|
assert_eq!(results.keys.len(), 2);
|
|
191
|
-
|
|
213
|
+
|
|
192
214
|
// Validate serialization
|
|
193
215
|
assert!(index.save("index.rust.usearch").is_ok());
|
|
194
216
|
assert!(index.load("index.rust.usearch").is_ok());
|
|
195
217
|
assert!(index.view("index.rust.usearch").is_ok());
|
|
196
|
-
|
|
218
|
+
|
|
197
219
|
// Make sure every function is called at least once
|
|
198
220
|
assert!(new_index(&options).is_ok());
|
|
199
221
|
options.metric = MetricKind::L2sq;
|
|
@@ -202,5 +224,15 @@ mod tests {
|
|
|
202
224
|
assert!(new_index(&options).is_ok());
|
|
203
225
|
options.metric = MetricKind::Haversine;
|
|
204
226
|
assert!(new_index(&options).is_ok());
|
|
227
|
+
|
|
228
|
+
let mut serialization_buffer = Vec::new();
|
|
229
|
+
serialization_buffer.resize(index.serialized_length(), 0);
|
|
230
|
+
assert!(index.save_to_buffer(&mut serialization_buffer).is_ok());
|
|
231
|
+
|
|
232
|
+
let deserialized_index = new_index(&options).unwrap();
|
|
233
|
+
assert!(deserialized_index
|
|
234
|
+
.load_from_buffer(&serialization_buffer)
|
|
235
|
+
.is_ok());
|
|
236
|
+
assert_eq!(index.size(), deserialized_index.size());
|
|
205
237
|
}
|
|
206
|
-
}
|
|
238
|
+
}
|