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
package/rust/lib.rs DELETED
@@ -1,610 +0,0 @@
1
- #[cxx::bridge]
2
- pub mod ffi {
3
- // Shared structs with fields visible to both languages.
4
- #[derive(Debug)]
5
- struct Matches {
6
- keys: Vec<u64>,
7
- distances: Vec<f32>,
8
- }
9
-
10
- #[derive(Debug)]
11
- enum MetricKind {
12
- IP,
13
- L2sq,
14
- Cos,
15
- Pearson,
16
- Haversine,
17
- Divergence,
18
- Hamming,
19
- Tanimoto,
20
- Sorensen,
21
- }
22
-
23
- #[derive(Debug)]
24
- enum ScalarKind {
25
- F64,
26
- F32,
27
- F16,
28
- I8,
29
- B1,
30
- }
31
-
32
- #[derive(Debug, PartialEq)]
33
- struct IndexOptions {
34
- dimensions: usize,
35
- metric: MetricKind,
36
- quantization: ScalarKind,
37
- connectivity: usize,
38
- expansion_add: usize,
39
- expansion_search: usize,
40
- multi: bool,
41
- }
42
-
43
- // C++ types and signatures exposed to Rust.
44
- unsafe extern "C++" {
45
- include!("lib.hpp");
46
-
47
- /// Low-level C++ interface that is further wrapped into the high-level `Index`
48
- type NativeIndex;
49
-
50
- pub fn expansion_add(self: &NativeIndex) -> usize;
51
- pub fn expansion_search(self: &NativeIndex) -> usize;
52
- pub fn change_expansion_add(self: &NativeIndex, n: usize) -> Result<()>;
53
- pub fn change_expansion_search(self: &NativeIndex, n: usize) -> Result<()>;
54
-
55
- pub fn new_native_index(options: &IndexOptions) -> Result<UniquePtr<NativeIndex>>;
56
- pub fn reserve(self: &NativeIndex, capacity: usize) -> Result<()>;
57
- pub fn dimensions(self: &NativeIndex) -> usize;
58
- pub fn connectivity(self: &NativeIndex) -> usize;
59
- pub fn size(self: &NativeIndex) -> usize;
60
- pub fn capacity(self: &NativeIndex) -> usize;
61
- pub fn serialized_length(self: &NativeIndex) -> usize;
62
-
63
- pub fn add_i8(self: &NativeIndex, key: u64, vector: &[i8]) -> Result<()>;
64
- pub fn add_f16(self: &NativeIndex, key: u64, vector: &[u16]) -> Result<()>;
65
- pub fn add_f32(self: &NativeIndex, key: u64, vector: &[f32]) -> Result<()>;
66
- pub fn add_f64(self: &NativeIndex, key: u64, vector: &[f64]) -> Result<()>;
67
-
68
- pub fn search_i8(self: &NativeIndex, query: &[i8], count: usize) -> Result<Matches>;
69
- pub fn search_f16(self: &NativeIndex, query: &[u16], count: usize) -> Result<Matches>;
70
- pub fn search_f32(self: &NativeIndex, query: &[f32], count: usize) -> Result<Matches>;
71
- pub fn search_f64(self: &NativeIndex, query: &[f64], count: usize) -> Result<Matches>;
72
-
73
- pub fn get_i8(self: &NativeIndex, key: u64, buffer: &mut [i8]) -> Result<usize>;
74
- pub fn get_f16(self: &NativeIndex, key: u64, buffer: &mut [u16]) -> Result<usize>;
75
- pub fn get_f32(self: &NativeIndex, key: u64, buffer: &mut [f32]) -> Result<usize>;
76
- pub fn get_f64(self: &NativeIndex, key: u64, buffer: &mut [f64]) -> Result<usize>;
77
-
78
- pub fn remove(self: &NativeIndex, key: u64) -> Result<usize>;
79
- pub fn rename(self: &NativeIndex, from: u64, to: u64) -> Result<usize>;
80
- pub fn contains(self: &NativeIndex, key: u64) -> bool;
81
- pub fn count(self: &NativeIndex, key: u64) -> usize;
82
-
83
- pub fn save(self: &NativeIndex, path: &str) -> Result<()>;
84
- pub fn load(self: &NativeIndex, path: &str) -> Result<()>;
85
- pub fn view(self: &NativeIndex, path: &str) -> Result<()>;
86
- pub fn reset(self: &NativeIndex) -> Result<()>;
87
- pub fn memory_usage(self: &NativeIndex) -> usize;
88
-
89
- pub fn save_to_buffer(self: &NativeIndex, buffer: &mut [u8]) -> Result<()>;
90
- pub fn load_from_buffer(self: &NativeIndex, buffer: &[u8]) -> Result<()>;
91
- pub fn view_from_buffer(self: &NativeIndex, buffer: &[u8]) -> Result<()>;
92
- }
93
- }
94
-
95
- pub struct Index {
96
- inner: cxx::UniquePtr<ffi::NativeIndex>,
97
- }
98
-
99
- impl Default for ffi::IndexOptions {
100
- fn default() -> Self {
101
- use crate::ffi::MetricKind;
102
- use crate::ffi::ScalarKind;
103
- Self {
104
- dimensions: 128,
105
- metric: MetricKind::IP,
106
- quantization: ScalarKind::F32,
107
- connectivity: 32,
108
- expansion_add: 2,
109
- expansion_search: 3,
110
- multi: false,
111
- }
112
- }
113
- }
114
-
115
- impl Clone for ffi::IndexOptions {
116
- fn clone(&self) -> Self {
117
- ffi::IndexOptions {
118
- dimensions: (self.dimensions),
119
- metric: (self.metric),
120
- quantization: (self.quantization),
121
- connectivity: (self.connectivity),
122
- expansion_add: (self.expansion_add),
123
- expansion_search: (self.expansion_search),
124
- multi: (self.multi),
125
- }
126
- }
127
- }
128
-
129
- pub trait VectorType {
130
- fn add(index: &Index, key: u64, vector: &[Self]) -> Result<(), cxx::Exception>
131
- where
132
- Self: Sized;
133
- fn get(index: &Index, key: u64, buffer: &mut [Self]) -> Result<usize, cxx::Exception>
134
- where
135
- Self: Sized;
136
- fn search(index: &Index, query: &[Self], count: usize) -> Result<ffi::Matches, cxx::Exception>
137
- where
138
- Self: Sized;
139
- }
140
-
141
- impl VectorType for i8 {
142
- fn search(index: &Index, query: &[Self], count: usize) -> Result<ffi::Matches, cxx::Exception> {
143
- index.inner.search_i8(query, count)
144
- }
145
- fn get(index: &Index, key: u64, vector: &mut [Self]) -> Result<usize, cxx::Exception> {
146
- index.inner.get_i8(key, vector)
147
- }
148
- fn add(index: &Index, key: u64, vector: &[Self]) -> Result<(), cxx::Exception> {
149
- index.inner.add_i8(key, vector)
150
- }
151
- }
152
-
153
- impl VectorType for f32 {
154
- fn search(index: &Index, query: &[Self], count: usize) -> Result<ffi::Matches, cxx::Exception> {
155
- index.inner.search_f32(query, count)
156
- }
157
- fn get(index: &Index, key: u64, vector: &mut [Self]) -> Result<usize, cxx::Exception> {
158
- index.inner.get_f32(key, vector)
159
- }
160
- fn add(index: &Index, key: u64, vector: &[Self]) -> Result<(), cxx::Exception> {
161
- index.inner.add_f32(key, vector)
162
- }
163
- }
164
-
165
- impl VectorType for f64 {
166
- fn search(index: &Index, query: &[Self], count: usize) -> Result<ffi::Matches, cxx::Exception> {
167
- index.inner.search_f64(query, count)
168
- }
169
- fn get(index: &Index, key: u64, vector: &mut [Self]) -> Result<usize, cxx::Exception> {
170
- index.inner.get_f64(key, vector)
171
- }
172
- fn add(index: &Index, key: u64, vector: &[Self]) -> Result<(), cxx::Exception> {
173
- index.inner.add_f64(key, vector)
174
- }
175
- }
176
-
177
- impl Index {
178
- pub fn new(options: &ffi::IndexOptions) -> Result<Self, cxx::Exception> {
179
- match ffi::new_native_index(options) {
180
- Ok(inner) => Result::Ok(Self { inner }),
181
- Err(err) => Err(err),
182
- }
183
- }
184
-
185
- /// Retrieves the expansion value used during index creation.
186
- pub fn expansion_add(self: &Index) -> usize {
187
- self.inner.expansion_add()
188
- }
189
-
190
- /// Retrieves the expansion value used during search.
191
- pub fn expansion_search(self: &Index) -> usize {
192
- self.inner.expansion_search()
193
- }
194
-
195
- /// Updates the expansion value used during index creation. Rarely used.
196
- pub fn change_expansion_add(self: &Index, n: usize) -> Result<(), cxx::Exception> {
197
- self.inner.change_expansion_add(n)
198
- }
199
-
200
- /// Updates the expansion value used during search operations.
201
- pub fn change_expansion_search(self: &Index, n: usize) -> Result<(), cxx::Exception> {
202
- self.inner.change_expansion_search(n)
203
- }
204
-
205
- /// Performs k-Approximate Nearest Neighbors (kANN) Search for closest vectors to the provided query.
206
- ///
207
- /// # Arguments
208
- ///
209
- /// * `query` - A slice containing the query vector data.
210
- /// * `count` - The maximum number of neighbors to search for.
211
- ///
212
- /// # Returns
213
- ///
214
- /// A `Result` containing the matches found.
215
- pub fn search<T: VectorType>(
216
- self: &Index,
217
- query: &[T],
218
- count: usize,
219
- ) -> Result<ffi::Matches, cxx::Exception> {
220
- T::search(self, query, count)
221
- }
222
-
223
- /// Adds a vector with a specified key to the index.
224
- ///
225
- /// # Arguments
226
- ///
227
- /// * `key` - The key associated with the vector.
228
- /// * `vector` - A slice containing the vector data.
229
- pub fn add<T: VectorType>(self: &Index, key: u64, vector: &[T]) -> Result<(), cxx::Exception> {
230
- T::add(self, key, vector)
231
- }
232
-
233
- /// Extracts one or more vectors matching the specified key.
234
- /// The `vector` slice must be a multiple of the number of dimensions in the index.
235
- /// After the execution, return the number `X` of vectors found.
236
- /// The vector slice's first `X * dimensions` elements will be filled.
237
- ///
238
- /// If you are a novice user, consider `export`.
239
- ///
240
- /// # Arguments
241
- ///
242
- /// * `key` - The key associated with the vector.
243
- /// * `vector` - A slice containing the vector data.
244
- pub fn get<T: VectorType>(
245
- self: &Index,
246
- key: u64,
247
- vector: &mut [T],
248
- ) -> Result<usize, cxx::Exception> {
249
- T::get(self, key, vector)
250
- }
251
-
252
- /// Extracts one or more vectors matching specified key into supplied resizable vector.
253
- /// The `vector` is resized to a multiple of the number of dimensions in the index.
254
- ///
255
- /// # Arguments
256
- ///
257
- /// * `key` - The key associated with the vector.
258
- /// * `vector` - A mutable vector containing the vector data.
259
- pub fn export<T: VectorType + Default + Clone>(
260
- self: &Index,
261
- key: u64,
262
- vector: &mut Vec<T>,
263
- ) -> Result<usize, cxx::Exception> {
264
- let dim = self.dimensions();
265
- let max_matches = self.count(key);
266
- vector.resize(dim * max_matches, T::default());
267
- let matches = T::get(self, key, &mut vector[..]);
268
- if matches.is_err() {
269
- return matches;
270
- }
271
- vector.resize(dim * matches.as_ref().unwrap(), T::default());
272
- return matches;
273
- }
274
-
275
- /// Reserves memory for a specified number of incoming vectors.
276
- ///
277
- /// # Arguments
278
- ///
279
- /// * `capacity` - The desired total capacity, including the current size.
280
- pub fn reserve(self: &Index, capacity: usize) -> Result<(), cxx::Exception> {
281
- self.inner.reserve(capacity)
282
- }
283
-
284
- /// Retrieves the number of dimensions in the vectors indexed.
285
- pub fn dimensions(self: &Index) -> usize {
286
- self.inner.dimensions()
287
- }
288
-
289
- /// Retrieves the connectivity parameter that limits connections-per-node in the graph.
290
- pub fn connectivity(self: &Index) -> usize {
291
- self.inner.connectivity()
292
- }
293
-
294
- /// Retrieves the current number of vectors in the index.
295
- pub fn size(self: &Index) -> usize {
296
- self.inner.size()
297
- }
298
-
299
- /// Retrieves the total capacity of the index, including reserved space.
300
- pub fn capacity(self: &Index) -> usize {
301
- self.inner.capacity()
302
- }
303
-
304
- /// Reports expected file size after serialization.
305
- pub fn serialized_length(self: &Index) -> usize {
306
- self.inner.serialized_length()
307
- }
308
-
309
- /// Removes the vector associated with the given key from the index.
310
- ///
311
- /// # Arguments
312
- ///
313
- /// * `key` - The key of the vector to be removed.
314
- ///
315
- /// # Returns
316
- ///
317
- /// `true` if the vector is successfully removed, `false` otherwise.
318
- pub fn remove(self: &Index, key: u64) -> Result<usize, cxx::Exception> {
319
- self.inner.remove(key)
320
- }
321
-
322
- /// Renames the vector under a specific key.
323
- ///
324
- /// # Arguments
325
- ///
326
- /// * `from` - The key of the vector to be renamed.
327
- /// * `to` - The new name.
328
- ///
329
- /// # Returns
330
- ///
331
- /// `true` if the vector is renamed, `false` otherwise.
332
- pub fn rename(self: &Index, from: u64, to: u64) -> Result<usize, cxx::Exception> {
333
- self.inner.rename(from, to)
334
- }
335
-
336
- /// Checks if the index contains a vector with a specified key.
337
- ///
338
- /// # Arguments
339
- ///
340
- /// * `key` - The key to be checked.
341
- ///
342
- /// # Returns
343
- ///
344
- /// `true` if the index contains the vector with the given key, `false` otherwise.
345
- pub fn contains(self: &Index, key: u64) -> bool {
346
- self.inner.contains(key)
347
- }
348
-
349
- /// Count the count of vectors with the same specified key.
350
- ///
351
- /// # Arguments
352
- ///
353
- /// * `key` - The key to be checked.
354
- ///
355
- /// # Returns
356
- ///
357
- /// Number of vectors found.
358
- pub fn count(self: &Index, key: u64) -> usize {
359
- self.inner.count(key)
360
- }
361
-
362
- /// Saves the index to a specified file.
363
- ///
364
- /// # Arguments
365
- ///
366
- /// * `path` - The file path where the index will be saved.
367
- pub fn save(self: &Index, path: &str) -> Result<(), cxx::Exception> {
368
- self.inner.save(path)
369
- }
370
-
371
- /// Loads the index from a specified file.
372
- ///
373
- /// # Arguments
374
- ///
375
- /// * `path` - The file path from where the index will be loaded.
376
- pub fn load(self: &Index, path: &str) -> Result<(), cxx::Exception> {
377
- self.inner.load(path)
378
- }
379
-
380
- /// Creates a view of the index from a file without loading it into memory.
381
- ///
382
- /// # Arguments
383
- ///
384
- /// * `path` - The file path from where the view will be created.
385
- pub fn view(self: &Index, path: &str) -> Result<(), cxx::Exception> {
386
- self.inner.view(path)
387
- }
388
-
389
- /// Erases all members from the index, closes files, and returns RAM to OS.
390
- pub fn reset(self: &Index) -> Result<(), cxx::Exception> {
391
- self.inner.reset()
392
- }
393
-
394
- /// A relatively accurate lower bound on the amount of memory consumed by the system.
395
- /// In practice, its error will be below 10%.
396
- pub fn memory_usage(self: &Index) -> usize {
397
- self.inner.memory_usage()
398
- }
399
-
400
- /// Saves the index to a specified file.
401
- ///
402
- /// # Arguments
403
- ///
404
- /// * `path` - The file path where the index will be saved.
405
- pub fn save_to_buffer(self: &Index, buffer: &mut [u8]) -> Result<(), cxx::Exception> {
406
- self.inner.save_to_buffer(buffer)
407
- }
408
-
409
- /// Loads the index from a specified file.
410
- ///
411
- /// # Arguments
412
- ///
413
- /// * `path` - The file path from where the index will be loaded.
414
- pub fn load_from_buffer(self: &Index, buffer: &[u8]) -> Result<(), cxx::Exception> {
415
- self.inner.load_from_buffer(buffer)
416
- }
417
-
418
- /// Creates a view of the index from a file without loading it into memory.
419
- ///
420
- /// # Arguments
421
- ///
422
- /// * `path` - The file path from where the view will be created.
423
- pub fn view_from_buffer(self: &Index, buffer: &[u8]) -> Result<(), cxx::Exception> {
424
- self.inner.view_from_buffer(buffer)
425
- }
426
- }
427
-
428
- pub fn new_index(options: &ffi::IndexOptions) -> Result<Index, cxx::Exception> {
429
- Index::new(options)
430
- }
431
-
432
- #[cfg(test)]
433
- mod tests {
434
- use crate::ffi::IndexOptions;
435
- use crate::ffi::MetricKind;
436
- use crate::ffi::ScalarKind;
437
-
438
- use crate::new_index;
439
- use crate::Index;
440
-
441
- #[test]
442
- fn test_add_get_vector() {
443
- let mut options = IndexOptions::default();
444
- options.dimensions = 5;
445
- let index = Index::new(&options).unwrap();
446
- assert!(index.reserve(10).is_ok());
447
-
448
- let first: [f32; 5] = [0.2, 0.1, 0.2, 0.1, 0.3];
449
- let second: [f32; 5] = [0.3, 0.2, 0.4, 0.0, 0.1];
450
- assert!(index.add(1, &first).is_ok());
451
- assert!(index.add(2, &second).is_ok());
452
- assert_eq!(index.size(), 2);
453
-
454
- // Test using Vec<T>
455
- let mut found_vec: Vec<f32> = Vec::new();
456
- assert_eq!(index.export(1, &mut found_vec).unwrap(), 1);
457
- assert_eq!(found_vec.len(), 5);
458
- assert_eq!(found_vec, first.to_vec());
459
-
460
- // Test using slice
461
- let mut found_slice = [0.0 as f32; 5];
462
- assert_eq!(index.get(1, &mut found_slice).unwrap(), 1);
463
- assert_eq!(found_slice, first);
464
-
465
- // Create a slice with incorrect size
466
- let mut found = [0.0 as f32; 6]; // This isn't a multiple of the index's dimensions.
467
- let result = index.get(1, &mut found);
468
- assert!(result.is_err());
469
- }
470
-
471
- #[test]
472
- fn test_add_remove_vector() {
473
- let mut options = IndexOptions::default();
474
- options.dimensions = 4;
475
- options.metric = MetricKind::IP;
476
- options.quantization = ScalarKind::F64;
477
- options.connectivity = 10;
478
- options.expansion_add = 128;
479
- options.expansion_search = 3;
480
- let index = Index::new(&options).unwrap();
481
- assert!(index.reserve(10).is_ok());
482
- assert_eq!(index.capacity(), 10);
483
-
484
- let first: [f32; 4] = [0.2, 0.1, 0.2, 0.1];
485
- let second: [f32; 4] = [0.3, 0.2, 0.4, 0.0];
486
-
487
- // IDs until 18446744073709551615 should be fine:
488
- let id1 = 483367403120493160;
489
- let id2 = 483367403120558696;
490
- let id3 = 483367403120624232;
491
- let id4 = 483367403120624233;
492
-
493
- assert!(index.add(id1, &first).is_ok());
494
- let mut found_slice = [0.0 as f32; 4];
495
- assert_eq!(index.get(id1, &mut found_slice).unwrap(), 1);
496
- assert!(index.remove(id1).is_ok());
497
-
498
- assert!(index.add(id2, &second).is_ok());
499
- let mut found_slice = [0.0 as f32; 4];
500
- assert_eq!(index.get(id2, &mut found_slice).unwrap(), 1);
501
- assert!(index.remove(id2).is_ok());
502
-
503
- assert!(index.add(id3, &second).is_ok());
504
- let mut found_slice = [0.0 as f32; 4];
505
- assert_eq!(index.get(id3, &mut found_slice).unwrap(), 1);
506
- assert!(index.remove(id3).is_ok());
507
-
508
- assert!(index.add(id4, &second).is_ok());
509
- let mut found_slice = [0.0 as f32; 4];
510
- assert_eq!(index.get(id4, &mut found_slice).unwrap(), 1);
511
- assert!(index.remove(id4).is_ok());
512
-
513
- assert_eq!(index.size(), 0);
514
- }
515
-
516
- #[test]
517
- fn integration() {
518
- let mut options = IndexOptions::default();
519
- options.dimensions = 5;
520
-
521
- let index = Index::new(&options).unwrap();
522
-
523
- assert!(index.expansion_add() > 0);
524
- assert!(index.expansion_search() > 0);
525
-
526
- assert!(index.reserve(10).is_ok());
527
- assert!(index.capacity() >= 10);
528
- assert!(index.connectivity() != 0);
529
- assert_eq!(index.dimensions(), 5);
530
- assert_eq!(index.size(), 0);
531
-
532
- let first: [f32; 5] = [0.2, 0.1, 0.2, 0.1, 0.3];
533
- let second: [f32; 5] = [0.3, 0.2, 0.4, 0.0, 0.1];
534
-
535
- println!(
536
- "before add, memory_usage: {} \
537
- cap: {} \
538
- ",
539
- index.memory_usage(),
540
- index.capacity(),
541
- );
542
- assert!(index.change_expansion_add(10).is_ok());
543
- assert_eq!(index.expansion_add(), 10);
544
- assert!(index.add(42, &first).is_ok());
545
- assert!(index.change_expansion_add(12).is_ok());
546
- assert_eq!(index.expansion_add(), 12);
547
- assert!(index.add(43, &second).is_ok());
548
- assert_eq!(index.size(), 2);
549
- println!(
550
- "after add, memory_usage: {} \
551
- cap: {} \
552
- ",
553
- index.memory_usage(),
554
- index.capacity(),
555
- );
556
-
557
- assert!(index.change_expansion_search(10).is_ok());
558
- assert_eq!(index.expansion_search(), 10);
559
- // Read back the tags
560
- let results = index.search(&first, 10).unwrap();
561
- println!("{:?}", results);
562
- assert_eq!(results.keys.len(), 2);
563
-
564
- assert!(index.change_expansion_search(12).is_ok());
565
- assert_eq!(index.expansion_search(), 12);
566
- let results = index.search(&first, 10).unwrap();
567
- println!("{:?}", results);
568
- assert_eq!(results.keys.len(), 2);
569
-
570
- // Validate serialization
571
- assert!(index.save("index.rust.usearch").is_ok());
572
- assert!(index.load("index.rust.usearch").is_ok());
573
- assert!(index.view("index.rust.usearch").is_ok());
574
-
575
- // Make sure every function is called at least once
576
- assert!(new_index(&options).is_ok());
577
- options.metric = MetricKind::L2sq;
578
- assert!(new_index(&options).is_ok());
579
- options.metric = MetricKind::Cos;
580
- assert!(new_index(&options).is_ok());
581
- options.metric = MetricKind::Haversine;
582
- assert!(new_index(&options).is_ok());
583
-
584
- let mut serialization_buffer = Vec::new();
585
- serialization_buffer.resize(index.serialized_length(), 0);
586
- assert!(index.save_to_buffer(&mut serialization_buffer).is_ok());
587
-
588
- let deserialized_index = new_index(&options).unwrap();
589
- assert!(deserialized_index
590
- .load_from_buffer(&serialization_buffer)
591
- .is_ok());
592
- assert_eq!(index.size(), deserialized_index.size());
593
-
594
- // reset
595
- assert_ne!(index.memory_usage(), 0);
596
- assert!(index.reset().is_ok());
597
- assert_eq!(index.size(), 0);
598
- assert_eq!(index.memory_usage(), 0);
599
-
600
- // clone
601
- options.metric = MetricKind::Haversine;
602
- let mut opts = options.clone();
603
- assert_eq!(opts.metric, options.metric);
604
- assert_eq!(opts.quantization, options.quantization);
605
- assert_eq!(opts, options);
606
- opts.metric = MetricKind::Cos;
607
- assert_ne!(opts.metric, options.metric);
608
- assert!(new_index(&opts).is_ok());
609
- }
610
- }
@@ -1,67 +0,0 @@
1
- # SimSIMD library CMakeLists.txt
2
- cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
3
- project(simsimd LANGUAGES C CXX)
4
-
5
- set(CMAKE_C_STANDARD 11)
6
- set(CMAKE_C_STANDARD_REQUIRED YES)
7
- set(CMAKE_C_EXTENSIONS NO)
8
-
9
- set(CMAKE_CXX_STANDARD 17)
10
- set(CMAKE_CXX_STANDARD_REQUIRED YES)
11
- set(CMAKE_CXX_EXTENSIONS NO)
12
-
13
- option(SIMSIMD_BUILD_BENCHMARKS "Compile a micro-benchmark for current ISA" OFF)
14
-
15
- # Fetch external dependencies
16
- include(FetchContent)
17
-
18
- # Suppress building tests of Google Benchmark
19
- set(BENCHMARK_ENABLE_TESTING OFF)
20
- set(BENCHMARK_ENABLE_INSTALL OFF)
21
- set(BENCHMARK_ENABLE_DOXYGEN OFF)
22
- set(BENCHMARK_INSTALL_DOCS OFF)
23
- set(BENCHMARK_DOWNLOAD_DEPENDENCIES ON)
24
- set(BENCHMARK_ENABLE_GTEST_TESTS OFF)
25
- set(BENCHMARK_USE_BUNDLED_GTEST ON)
26
-
27
- FetchContent_Declare(
28
- benchmark
29
- GIT_REPOSITORY https://github.com/google/benchmark.git
30
- GIT_TAG v1.7.0)
31
- FetchContent_MakeAvailable(benchmark)
32
-
33
- # Default to Release build type if not set
34
- if(NOT CMAKE_BUILD_TYPE)
35
- set(CMAKE_BUILD_TYPE Release)
36
- endif()
37
-
38
- # Global compiler flags for debug and release
39
- set(CMAKE_CXX_FLAGS_DEBUG "-g -fsanitize=address")
40
- set(CMAKE_CXX_FLAGS_RELEASE "-O3")
41
- set(CMAKE_C_FLAGS_DEBUG "-g -fsanitize=address")
42
- set(CMAKE_C_FLAGS_RELEASE "-O3")
43
-
44
- # Compiler-specific flags
45
- if(CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?Clang$")
46
- if(NOT APPLE)
47
- add_compile_options(-march=native)
48
- endif()
49
- add_compile_options(-pedantic -ferror-limit=1)
50
- elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
51
- add_compile_options(-march=native -pedantic -fmax-errors=1 -Wno-tautological-constant-compare)
52
- elseif(CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
53
- add_compile_options(-w -ferror-limit=1)
54
- endif()
55
-
56
- # Define the header-only library
57
- file(GLOB SIMSIMD_SOURCES include/simsimd/*.h)
58
- add_library(simsimd INTERFACE)
59
- target_sources(simsimd INTERFACE ${SIMSIMD_SOURCES})
60
- target_include_directories(simsimd INTERFACE "${PROJECT_SOURCE_DIR}/include")
61
-
62
- # Build benchmarks if required
63
- if(SIMSIMD_BUILD_BENCHMARKS)
64
- find_package(Threads REQUIRED)
65
- add_executable(simsimd_bench cpp/bench.cxx)
66
- target_link_libraries(simsimd_bench simsimd Threads::Threads benchmark)
67
- endif()