usearch 2.8.6 → 2.8.8

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 (102) hide show
  1. package/CITATION.cff +1 -1
  2. package/CMakeLists.txt +3 -3
  3. package/CONTRIBUTING.md +3 -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 +27 -23
  12. package/package.json +4 -3
  13. package/setup.py +76 -15
  14. package/wasmer.toml +1 -1
  15. package/. npmignore +0 -14
  16. package/.gitignore +0 -95
  17. package/.vscode/launch.json +0 -181
  18. package/.vscode/settings.json +0 -180
  19. package/.vscode/tasks.json +0 -71
  20. package/Package.swift +0 -41
  21. package/csharp/.editorconfig +0 -361
  22. package/csharp/Cloud.Unum.USearch.sln +0 -34
  23. package/csharp/DEV_SETUP.md +0 -51
  24. package/csharp/Directory.Build.props +0 -29
  25. package/csharp/README.md +0 -74
  26. package/csharp/build_and_test.cmd +0 -31
  27. package/csharp/build_and_test.sh +0 -30
  28. package/csharp/nuget/nuget-package.props +0 -33
  29. package/csharp/pack.sh +0 -56
  30. package/csharp/src/Cloud.Unum.USearch.Tests/Cloud.Unum.USearch.Tests.csproj +0 -39
  31. package/csharp/src/Cloud.Unum.USearch.Tests/USearchIndexTests.cs +0 -1013
  32. package/csharp/src/Cloud.Unum.USearch.Tests/Usings.cs +0 -1
  33. package/docs/_static/custom.css +0 -26
  34. package/docs/_static/custom.js +0 -7
  35. package/docs/benchmarks.md +0 -245
  36. package/docs/benchmarks.rst +0 -5
  37. package/docs/c/index.rst +0 -11
  38. package/docs/c/reference.rst +0 -7
  39. package/docs/conf.dox +0 -2668
  40. package/docs/conf.py +0 -53
  41. package/docs/contributing.rst +0 -5
  42. package/docs/cpp/index.rst +0 -11
  43. package/docs/cpp/reference.rst +0 -17
  44. package/docs/csharp/index.rst +0 -6
  45. package/docs/format.md +0 -86
  46. package/docs/format.rst +0 -5
  47. package/docs/golang/index.rst +0 -6
  48. package/docs/index.rst +0 -33
  49. package/docs/java/index.rst +0 -11
  50. package/docs/java/reference.rst +0 -7
  51. package/docs/javascript/index.rst +0 -11
  52. package/docs/javascript/reference.rst +0 -12
  53. package/docs/python/index.rst +0 -11
  54. package/docs/python/reference.rst +0 -42
  55. package/docs/rust/index.rst +0 -6
  56. package/docs/swift/index.rst +0 -6
  57. package/docs/wolfram/index.rst +0 -6
  58. package/golang/README.md +0 -95
  59. package/golang/go.mod +0 -3
  60. package/golang/lib.go +0 -379
  61. package/golang/lib_test.go +0 -108
  62. package/java/README.md +0 -22
  63. package/java/cloud/unum/usearch/Index.java +0 -337
  64. package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +0 -197
  65. package/java/cloud/unum/usearch/cloud_unum_usearch_Index.h +0 -125
  66. package/java/test/IndexTest.java +0 -30
  67. package/objc/USearchObjective.mm +0 -299
  68. package/objc/include/USearchObjective.h +0 -154
  69. package/python/README.md +0 -292
  70. package/python/lib.cpp +0 -1216
  71. package/python/scripts/bench.ipynb +0 -193
  72. package/python/scripts/bench.py +0 -137
  73. package/python/scripts/bench_exact.py +0 -44
  74. package/python/scripts/cluster.ipynb +0 -160
  75. package/python/scripts/index_faiss.py +0 -100
  76. package/python/scripts/join.py +0 -155
  77. package/python/scripts/test_index.py +0 -247
  78. package/python/scripts/test_jit.py +0 -231
  79. package/python/scripts/test_sparse.py +0 -32
  80. package/python/scripts/test_tooling.py +0 -133
  81. package/python/usearch/__init__.py +0 -0
  82. package/python/usearch/client.py +0 -124
  83. package/python/usearch/eval.py +0 -470
  84. package/python/usearch/index.py +0 -1401
  85. package/python/usearch/io.py +0 -113
  86. package/python/usearch/numba.py +0 -121
  87. package/python/usearch/server.py +0 -137
  88. package/rust/README.md +0 -66
  89. package/rust/lib.cpp +0 -136
  90. package/rust/lib.hpp +0 -69
  91. package/rust/lib.rs +0 -610
  92. package/swift/Index+Sugar.swift +0 -153
  93. package/swift/README.md +0 -48
  94. package/swift/Test.swift +0 -37
  95. package/swift/USearch.swift +0 -8
  96. package/wasm/CMakeLists.txt +0 -7
  97. package/wasm/README.md +0 -13
  98. package/wasm/lib.cpp +0 -5
  99. package/wolfram/CMakeLists.txt +0 -18
  100. package/wolfram/README.md +0 -13
  101. package/wolfram/lib.cpp +0 -160
  102. package/wolfram/test.wls +0 -27
@@ -1,1013 +0,0 @@
1
- using System.Numerics;
2
- using System.Runtime.InteropServices;
3
- using Cloud.Unum.USearch;
4
-
5
- namespace Cloud.Unum.USearch.Tests;
6
-
7
- public class UsearchIndexTests
8
- {
9
- // Epsilon for real values comparisons
10
- private const float EqualTolerance = 1e-6f;
11
- private static readonly RealEqualityComparer<float> s_floatComparer;
12
- private static readonly RealEqualityComparer<double> s_doubleComparer;
13
-
14
- static UsearchIndexTests()
15
- {
16
- s_floatComparer = new RealEqualityComparer<float>(EqualTolerance);
17
- s_doubleComparer = new RealEqualityComparer<double>(EqualTolerance);
18
- }
19
-
20
- [Fact]
21
- public void IndexOptions_InitializesEmptyArguments_ConstructedWithMinimalOrUnknownValues()
22
- {
23
- // Arrange
24
- var controlIndexOptions = new IndexOptions(
25
- metricKind: MetricKind.Unknown,
26
- metric: default,
27
- quantization: ScalarKind.Unknown,
28
- dimensions: 0,
29
- connectivity: 0,
30
- expansionAdd: 0,
31
- expansionSearch: 0,
32
- multi: false
33
- );
34
-
35
- // Act
36
- var indexOptions = new IndexOptions();
37
-
38
- // Assert
39
- Assert.Equal(controlIndexOptions, indexOptions);
40
- }
41
-
42
- [Fact]
43
- public void USearch_InitializesWithRequiredArgumentsSetToMinimalOrUnknownValue_UpdatesIndexOptions()
44
- {
45
- // Arrange
46
- const uint ExpectedDimensions = 0;
47
- const uint ExpectedConnectivity = 16;
48
- const uint ExpectedCapacity = 0;
49
- const uint ExpectedSize = 0;
50
-
51
- var initMetricKind = MetricKind.Unknown;
52
- ulong initDimensions = 0;
53
- var initQuantization = ScalarKind.Unknown;
54
-
55
- // Act
56
- using (var index = new USearchIndex(initMetricKind, initQuantization, initDimensions))
57
- {
58
- // Assert
59
- Assert.Equal(ExpectedDimensions, index.Dimensions());
60
- Assert.Equal(ExpectedConnectivity, index.Connectivity());
61
- Assert.Equal(ExpectedCapacity, index.Capacity());
62
- Assert.Equal(ExpectedSize, index.Size());
63
- }
64
- }
65
-
66
- [Fact]
67
- public void USearch_InitializesWithIndexOptionsWithMinimalOrUnknownValue_UpdatesIndexOptions()
68
- {
69
- // Arrange
70
- const uint ExpectedDimensions = 0;
71
- const uint ExpectedConnectivity = 16;
72
- const uint ExpectedCapacity = 0;
73
- const uint ExpectedSize = 0;
74
-
75
- var indexOptions = new IndexOptions(
76
- metricKind: MetricKind.Unknown,
77
- metric: default,
78
- quantization: ScalarKind.Unknown,
79
- dimensions: 0,
80
- connectivity: 0,
81
- expansionAdd: 0,
82
- expansionSearch: 0,
83
- multi: false
84
- );
85
-
86
- // Act
87
- using (var index = new USearchIndex(indexOptions))
88
- {
89
- // Assert
90
- Assert.Equal(ExpectedDimensions, index.Dimensions());
91
- Assert.Equal(ExpectedConnectivity, index.Connectivity());
92
- Assert.Equal(ExpectedCapacity, index.Capacity());
93
- Assert.Equal(ExpectedSize, index.Size());
94
- }
95
- }
96
-
97
- [Fact]
98
- public void Add_FloatVector_UpdatesIndexOptions()
99
- {
100
- // Arrange
101
- const uint Dimensions = 10;
102
- const uint AddKey = 1;
103
- const uint NonExistentKey = 2;
104
- const uint ExpectedSize = 1;
105
- const uint ExpectedCapacity = 1;
106
-
107
- var indexOptions = new IndexOptions(
108
- metricKind: MetricKind.Cos,
109
- quantization: ScalarKind.Float32,
110
- dimensions: Dimensions
111
- );
112
-
113
- var inputVector = GenerateFloatVector((int)Dimensions);
114
-
115
- using (var index = new USearchIndex(indexOptions))
116
- {
117
- // Act
118
- index.Add(AddKey, inputVector);
119
-
120
- // Assert
121
- Assert.True(index.Contains(AddKey));
122
- Assert.False(index.Contains(NonExistentKey));
123
- Assert.Equal(ExpectedSize, index.Size());
124
- Assert.Equal(ExpectedCapacity, index.Capacity());
125
- }
126
- }
127
-
128
- [Fact]
129
- public void Add_DoubleVector_UpdatesIndexOptions()
130
- {
131
- // Arrange
132
- const uint Dimensions = 10;
133
- const uint AddKey = 1;
134
- const uint NonExistentKey = 2;
135
- const uint ExpectedSize = 1;
136
- const uint ExpectedCapacity = 1;
137
-
138
- var indexOptions = new IndexOptions(
139
- metricKind: MetricKind.Cos,
140
- quantization: ScalarKind.Float64,
141
- dimensions: Dimensions
142
- );
143
-
144
- var inputVector = GenerateDoubleVector((int)Dimensions);
145
-
146
- using (var index = new USearchIndex(indexOptions))
147
- {
148
- // Act
149
- index.Add(AddKey, inputVector);
150
-
151
- // Assert
152
- Assert.True(index.Contains(AddKey));
153
- Assert.False(index.Contains(NonExistentKey));
154
- Assert.Equal(ExpectedSize, index.Size());
155
- Assert.Equal(ExpectedCapacity, index.Capacity());
156
- }
157
- }
158
-
159
- [Fact]
160
- public void Add_ManyFloatVectorsUnderSameKeySeparatelyInMultiKeyIndex_UpdatesIndexOptions()
161
- {
162
- // Arrange
163
- const uint Dimensions = 10;
164
- const ulong AddKey = 1;
165
- const int AddFactor = 5;
166
-
167
- var indexOptions = new IndexOptions(
168
- metricKind: MetricKind.Cos,
169
- quantization: ScalarKind.Float32,
170
- dimensions: Dimensions,
171
- multi: true
172
- );
173
-
174
- var inputVector = GenerateFloatVector((int)Dimensions);
175
-
176
- using (var index = new USearchIndex(indexOptions))
177
- {
178
- // Act
179
- for (int i = 0; i < AddFactor; i++)
180
- {
181
- index.Add(AddKey, inputVector);
182
- }
183
-
184
- // Assert
185
- Assert.True(index.Contains(AddKey));
186
- Assert.Equal((uint)AddFactor, index.Size());
187
- Assert.Equal((uint)AddFactor, index.Capacity());
188
- }
189
- }
190
-
191
- [Fact]
192
- public void Add_ManyDoubleVectorsUnderSameKeySeparatelyInMultiKeyIndex_UpdatesIndexOptions()
193
- {
194
- // Arrange
195
- const uint Dimensions = 10;
196
- const ulong AddKey = 1;
197
- const int AddFactor = 5;
198
-
199
- var indexOptions = new IndexOptions(
200
- metricKind: MetricKind.Cos,
201
- quantization: ScalarKind.Float64,
202
- dimensions: Dimensions,
203
- multi: true
204
- );
205
-
206
- var inputVector = GenerateDoubleVector((int)Dimensions);
207
-
208
- using (var index = new USearchIndex(indexOptions))
209
- {
210
- // Act
211
- for (int i = 0; i < AddFactor; i++)
212
- {
213
- index.Add(AddKey, inputVector);
214
- }
215
-
216
- // Assert
217
- Assert.True(index.Contains(AddKey));
218
- Assert.Equal((uint)AddFactor, index.Size());
219
- Assert.Equal((uint)AddFactor, index.Capacity());
220
- }
221
- }
222
-
223
- [Fact]
224
- public void Add_ManyFloatVectorsUnderSameKeyInBatchInMultiKeyIndex_UpdatesIndexOptions()
225
- {
226
- // Arrange
227
- const uint Dimensions = 10;
228
- const ulong AddKey = 1;
229
- const uint BatchSize = 5;
230
-
231
- var indexOptions = new IndexOptions(
232
- metricKind: MetricKind.Cos,
233
- quantization: ScalarKind.Float32,
234
- dimensions: Dimensions,
235
- multi: true
236
- );
237
-
238
- (var inputKeys, var inputVectors) = (
239
- Enumerable.Repeat(AddKey, (int)BatchSize).ToArray(),
240
- GenerateManyFloatVectors((int)BatchSize, (int)Dimensions)
241
- );
242
-
243
- using (var index = new USearchIndex(indexOptions))
244
- {
245
- // Act
246
- index.Add(inputKeys, inputVectors);
247
-
248
- // Assert
249
- Assert.True(index.Contains(AddKey));
250
- Assert.Equal(BatchSize, index.Size());
251
- Assert.Equal(BatchSize, index.Capacity());
252
- Assert.Equal((int)BatchSize, index.Count(AddKey));
253
- }
254
- }
255
-
256
- [Fact]
257
- public void Add_ManyDoubleVectorsUnderSameKeyInBatchInMultiKeyIndex_UpdatesIndexOptions()
258
- {
259
- // Arrange
260
- const uint Dimensions = 10;
261
- const ulong AddKey = 1;
262
- const uint BatchSize = 5;
263
-
264
- var indexOptions = new IndexOptions(
265
- metricKind: MetricKind.Cos,
266
- quantization: ScalarKind.Float64,
267
- dimensions: Dimensions,
268
- multi: true
269
- );
270
-
271
- (var inputKeys, var inputVectors) = (
272
- Enumerable.Repeat(AddKey, (int)BatchSize).ToArray(),
273
- GenerateManyDoubleVectors((int)BatchSize, (int)Dimensions)
274
- );
275
-
276
- using (var index = new USearchIndex(indexOptions))
277
- {
278
- // Act
279
- index.Add(inputKeys, inputVectors);
280
-
281
- // Assert
282
- Assert.True(index.Contains(AddKey));
283
- Assert.Equal(BatchSize, index.Size());
284
- Assert.Equal(BatchSize, index.Capacity());
285
- Assert.Equal((int)BatchSize, index.Count(AddKey));
286
- }
287
- }
288
-
289
- [Fact]
290
- public void Get_ManyFloatVectorsUnderSameKeyInMultiKeyIndex_ReturnsCorrectValue()
291
- {
292
- // Arrange
293
- const uint Dimensions = 10;
294
- const ulong AddKey = 1;
295
- const int RetrieveCount = 5;
296
- const int BatchSize = 10;
297
-
298
- var indexOptions = new IndexOptions(
299
- metricKind: MetricKind.Cos,
300
- quantization: ScalarKind.Float32,
301
- dimensions: Dimensions,
302
- multi: true
303
- );
304
-
305
- (var inputKeys, var inputVectors) = (
306
- Enumerable.Repeat(AddKey, BatchSize).ToArray(),
307
- GenerateManyFloatVectors(BatchSize, (int)Dimensions)
308
- );
309
-
310
- using (var index = new USearchIndex(indexOptions))
311
- {
312
- index.Add(inputKeys, inputVectors);
313
-
314
- // Act
315
- int foundVectorsCount = index.Get(AddKey, RetrieveCount, out float[][] retrievedVectors);
316
-
317
- // Assert
318
- Assert.Equal(RetrieveCount, foundVectorsCount);
319
- }
320
- }
321
-
322
- [Fact]
323
- public void Get_ManyDoubleVectorsUnderSameKeyInMultiKeyIndex_ReturnsCorrectCountValue()
324
- {
325
- // Arrange
326
- const uint Dimensions = 10;
327
- const ulong AddKey = 1;
328
- const int RetrieveCount = 5;
329
- const int BatchSize = 10;
330
-
331
- var indexOptions = new IndexOptions(
332
- metricKind: MetricKind.Cos,
333
- quantization: ScalarKind.Float64,
334
- dimensions: Dimensions,
335
- multi: true
336
- );
337
-
338
- (var inputKeys, var inputVectors) = (
339
- Enumerable.Repeat(AddKey, BatchSize).ToArray(),
340
- GenerateManyDoubleVectors(BatchSize, (int)Dimensions)
341
- );
342
-
343
- using (var index = new USearchIndex(indexOptions))
344
- {
345
- index.Add(inputKeys, inputVectors);
346
-
347
- // Act
348
- int foundVectorsCount = index.Get(AddKey, RetrieveCount, out double[][] retrievedVectors);
349
-
350
- // Assert
351
- Assert.Equal(RetrieveCount, foundVectorsCount);
352
- }
353
- }
354
-
355
- [Fact]
356
- public void Get_AfterAddingFloatVector_ReturnsEqualVector()
357
- {
358
- // Arrange
359
- const uint Dimensions = 10;
360
- const ulong AddKey = 1;
361
-
362
- var indexOptions = new IndexOptions(
363
- metricKind: MetricKind.Cos,
364
- quantization: ScalarKind.Float32,
365
- dimensions: Dimensions
366
- );
367
-
368
- (var inputKey, var inputVector) = (AddKey, GenerateFloatVector((int)Dimensions));
369
-
370
- using (var index = new USearchIndex(indexOptions))
371
- {
372
- index.Add(inputKey, inputVector);
373
-
374
- // Act
375
- index.Get(inputKey, out float[] retrievedVector);
376
-
377
- // Assert
378
- Assert.Equal(inputVector, retrievedVector, s_floatComparer);
379
- }
380
- }
381
-
382
- [Fact]
383
- public void Get_AfterAddingDoubleVector_ReturnsEqualVector()
384
- {
385
- // Arrange
386
- const uint Dimensions = 10;
387
- const ulong AddKey = 1;
388
-
389
- var indexOptions = new IndexOptions(
390
- metricKind: MetricKind.Cos,
391
- quantization: ScalarKind.Float64,
392
- dimensions: Dimensions
393
- );
394
-
395
- (var inputKey, var inputVector) = (AddKey, GenerateDoubleVector((int)Dimensions));
396
-
397
- using (var index = new USearchIndex(indexOptions))
398
- {
399
- index.Add(inputKey, inputVector);
400
-
401
- // Act
402
- index.Get(inputKey, out double[] retrievedVector);
403
-
404
- // Assert
405
- Assert.Equal(inputVector, retrievedVector, s_doubleComparer);
406
- }
407
- }
408
-
409
- [Fact]
410
- public void Add_AddingTwoFloatVectorsUnderSameKey_ThrowsException()
411
- {
412
- // Arrange
413
- const uint Dimensions = 10;
414
- const ulong AddKey = 1;
415
-
416
- var indexOptions = new IndexOptions(
417
- metricKind: MetricKind.Cos,
418
- quantization: ScalarKind.Float32,
419
- dimensions: Dimensions
420
- );
421
-
422
- (var inputKey, var inputVector) = (AddKey, GenerateFloatVector((int)Dimensions));
423
-
424
- using (var index = new USearchIndex(indexOptions))
425
- {
426
- index.Add(inputKey, inputVector);
427
-
428
- // Act
429
- Action actual = () => index.Add(inputKey, inputVector);
430
-
431
- // Assert
432
- Assert.Throws<USearchException>(actual);
433
- }
434
- }
435
-
436
- [Fact]
437
- public void Add_AddingTwoDoubleVectorsUnderSameKey_ThrowsException()
438
- {
439
- // Arrange
440
- const uint Dimensions = 10;
441
- const ulong AddKey = 1;
442
-
443
- var indexOptions = new IndexOptions(
444
- metricKind: MetricKind.Cos,
445
- quantization: ScalarKind.Float64,
446
- dimensions: Dimensions
447
- );
448
-
449
- (var inputKey, var inputVector) = (AddKey, GenerateDoubleVector((int)Dimensions));
450
-
451
- using (var index = new USearchIndex(indexOptions))
452
- {
453
- index.Add(inputKey, inputVector);
454
-
455
- // Act
456
- Action actual = () => index.Add(inputKey, inputVector);
457
-
458
- // Assert
459
- Assert.Throws<USearchException>(actual);
460
- }
461
- }
462
-
463
- [Fact]
464
- public void Remove_InsertedFloatVector_ReturnsInsertedVectorsCount()
465
- {
466
- // Arrange
467
- const uint Dimensions = 10;
468
- const ulong AddKey = 1;
469
- const int ExpectedRemoveReturn = 1;
470
-
471
- var indexOptions = new IndexOptions(
472
- metricKind: MetricKind.Cos,
473
- quantization: ScalarKind.Float32,
474
- dimensions: Dimensions
475
- );
476
-
477
- (var inputKey, var inputVector) = (AddKey, GenerateFloatVector((int)Dimensions));
478
-
479
-
480
- using (var index = new USearchIndex(indexOptions))
481
- {
482
- index.Add(inputKey, inputVector);
483
-
484
- // Act
485
- var removedCount = index.Remove(AddKey);
486
-
487
- // Assert
488
- Assert.Equal(ExpectedRemoveReturn, removedCount);
489
- }
490
- }
491
-
492
- [Fact]
493
- public void Remove_InsertedDoubleVector_ReturnsInsertedVectorsCount()
494
- {
495
- // Arrange
496
- const uint Dimensions = 10;
497
- const ulong TestAddKey = 1;
498
- const int ExpectedRemoveReturn = 1;
499
-
500
- var indexOptions = new IndexOptions(
501
- metricKind: MetricKind.Cos,
502
- quantization: ScalarKind.Float64,
503
- dimensions: Dimensions
504
- );
505
-
506
- (var inputKey, var inputVector) = (TestAddKey, GenerateDoubleVector((int)Dimensions));
507
-
508
- using (var index = new USearchIndex(indexOptions))
509
- {
510
- index.Add(inputKey, inputVector);
511
-
512
- // Act
513
- var removedCount = index.Remove(TestAddKey);
514
-
515
- // Assert
516
- Assert.Equal(ExpectedRemoveReturn, removedCount);
517
- }
518
- }
519
-
520
- [Fact]
521
- public void Remove_InsertedManyFloatVectorsUnderSameKeyInMultiKeyIndex_ReturnsInsertedVectorsCount()
522
- {
523
- // Arrange
524
- const uint Dimensions = 10;
525
- const ulong AddKey = 1;
526
- const int BatchSize = 2;
527
-
528
- var indexOptions = new IndexOptions(
529
- metricKind: MetricKind.Cos,
530
- quantization: ScalarKind.Float32,
531
- dimensions: Dimensions,
532
- multi: true
533
- );
534
-
535
- (var inputKeys, var inputVectors) = (
536
- Enumerable.Repeat(AddKey, BatchSize).ToArray(),
537
- GenerateManyFloatVectors(BatchSize, (int)Dimensions)
538
- );
539
-
540
- using (var index = new USearchIndex(indexOptions))
541
- {
542
- index.Add(inputKeys, inputVectors);
543
-
544
- // Act
545
- var removedCount = index.Remove(AddKey);
546
-
547
- // Assert
548
- Assert.Equal(BatchSize, removedCount);
549
- }
550
- }
551
-
552
- [Fact]
553
- public void Remove_InsertedManyDoubleVectorUnderSameKeyInMultiKeyIndex_ReturnsInsertedVectorsCount()
554
- {
555
- // Arrange
556
- const uint Dimensions = 10;
557
- const ulong AddKey = 1;
558
- const int BatchSize = 2;
559
-
560
- var indexOptions = new IndexOptions(
561
- metricKind: MetricKind.Cos,
562
- quantization: ScalarKind.Float64,
563
- dimensions: Dimensions,
564
- multi: true
565
- );
566
-
567
- (var inputKeys, var inputVectors) = (
568
- Enumerable.Repeat(AddKey, BatchSize).ToArray(),
569
- GenerateManyDoubleVectors(BatchSize, (int)Dimensions)
570
- );
571
-
572
- using (var index = new USearchIndex(indexOptions))
573
- {
574
- index.Add(inputKeys, inputVectors);
575
-
576
- // Act
577
- var removedCount = index.Remove(AddKey);
578
-
579
- // Assert
580
- Assert.Equal(BatchSize, removedCount);
581
- }
582
- }
583
-
584
- [Fact]
585
- public void Get_NonExistentKey_ReturnsZeroCountAndEmptyVector()
586
- {
587
- // Arrange
588
- const uint Dimensions = 10;
589
- const ulong NonExistentKey = 1;
590
-
591
- var indexOptions = new IndexOptions(
592
- metricKind: MetricKind.Cos,
593
- quantization: ScalarKind.Float32,
594
- dimensions: Dimensions
595
- );
596
-
597
- using (var index = new USearchIndex(indexOptions))
598
- {
599
- // Act
600
- var retrievedCount = index.Get(NonExistentKey, out float[] retrievedVector);
601
-
602
- // Assert
603
- Assert.True(retrievedCount == 0);
604
- Assert.Null(retrievedVector);
605
- }
606
- }
607
-
608
- [Fact]
609
- public void Rename_ExistingKey_ReturnsInsertedVectorsCount()
610
- {
611
- // Arrange
612
- const uint Dimensions = 10;
613
- const ulong TestAddKey = 1;
614
- const ulong TestRenameKey = 2;
615
- const int ExpectedRenamedCount = 1;
616
-
617
- var indexOptions = new IndexOptions(
618
- metricKind: MetricKind.Cos,
619
- quantization: ScalarKind.Float32,
620
- dimensions: Dimensions,
621
- multi: false
622
- );
623
-
624
- var inputVector = GenerateFloatVector((int)Dimensions);
625
-
626
- using (var index = new USearchIndex(indexOptions))
627
- {
628
- index.Add(TestAddKey, inputVector);
629
-
630
- // Act
631
- var renamedCount = index.Rename(TestAddKey, TestRenameKey);
632
-
633
- // Assert
634
- Assert.Equal(ExpectedRenamedCount, renamedCount);
635
- }
636
- }
637
-
638
- [Fact]
639
- public void Rename_ExistingKey_UpdatesOptionsProperly()
640
- {
641
- // Arrange
642
- const uint Dimensions = 10;
643
- const ulong AddKey = 1;
644
- const ulong RenameToKey = 2;
645
- const ulong ExpectedSize = 1;
646
-
647
- var indexOptions = new IndexOptions(
648
- metricKind: MetricKind.Cos,
649
- quantization: ScalarKind.Float32,
650
- dimensions: Dimensions,
651
- multi: false
652
- );
653
-
654
- var inputVector = GenerateFloatVector((int)Dimensions);
655
-
656
- using (var index = new USearchIndex(indexOptions))
657
- {
658
- index.Add(AddKey, inputVector);
659
-
660
- // Act
661
- index.Rename(AddKey, RenameToKey);
662
-
663
- // Assert
664
- Assert.False(index.Contains(AddKey));
665
- Assert.True(index.Contains(RenameToKey));
666
- Assert.Equal(ExpectedSize, index.Size());
667
- }
668
- }
669
-
670
- [Fact]
671
- public void Rename_ExistingKeyInMultiKeyIndex_ReturnsInsertedVectorsCount()
672
- {
673
- // Arrange
674
- const uint Dimensions = 10;
675
- const ulong AddKey = 1;
676
- const ulong RenameKey = 2;
677
- const int BatchSize = 10;
678
-
679
- var indexOptions = new IndexOptions(
680
- metricKind: MetricKind.Cos,
681
- quantization: ScalarKind.Float32,
682
- dimensions: Dimensions,
683
- multi: true
684
- );
685
-
686
- var inputKeys = Enumerable.Repeat((int)AddKey, BatchSize).Select(x => (ulong)x).ToArray();
687
- var inputVectors = GenerateManyFloatVectors(BatchSize, (int)Dimensions);
688
-
689
- using (var index = new USearchIndex(indexOptions))
690
- {
691
- index.Add(inputKeys, inputVectors);
692
-
693
- // Act
694
- var vectorsCount = index.Rename(AddKey, RenameKey);
695
-
696
- // Assert
697
- Assert.Equal(BatchSize, vectorsCount);
698
- }
699
- }
700
-
701
- [Fact]
702
- public void Rename_ExistingKeyInMultiKeyIndex_UpdatesOptionsProperly()
703
- {
704
- // Arrange
705
- const uint Dimensions = 10;
706
- const ulong AddKey = 1;
707
- const ulong RenameToKey = 2;
708
- const int BatchSize = 2;
709
- const ulong ExpectedSize = 2;
710
-
711
- var indexOptions = new IndexOptions(
712
- metricKind: MetricKind.Cos,
713
- quantization: ScalarKind.Float32,
714
- dimensions: Dimensions,
715
- multi: true
716
- );
717
-
718
- (var inputKeys, var inputVectors) = (
719
- Enumerable.Range((int)AddKey, BatchSize).Select(x => (ulong)x).ToArray(),
720
- GenerateManyFloatVectors(BatchSize, (int)Dimensions)
721
- );
722
-
723
- using (var index = new USearchIndex(indexOptions))
724
- {
725
- index.Add(
726
- inputKeys,
727
- inputVectors
728
- );
729
-
730
- // Act
731
- var vectorsCount = index.Rename(AddKey, RenameToKey);
732
-
733
- // Assert
734
- Assert.False(index.Contains(AddKey));
735
- Assert.True(index.Contains(RenameToKey));
736
- Assert.Equal(ExpectedSize, index.Size());
737
- }
738
- }
739
-
740
- [Fact]
741
- public void Rename_ExistingKeyToExistingKeyInMultiKeyIndex_ReturnsInsertedVectorsCount()
742
- {
743
- // Arrange
744
- const uint Dimensions = 10;
745
-
746
- var indexOptions = new IndexOptions(
747
- metricKind: MetricKind.Cos,
748
- quantization: ScalarKind.Float32,
749
- dimensions: Dimensions,
750
- multi: true
751
- );
752
-
753
- var inputKeys = new ulong[] { 1, 1, 1, 2, 2 };
754
- var inputVectors = GenerateManyFloatVectors(5, (int)Dimensions);
755
-
756
- using (var index = new USearchIndex(indexOptions))
757
- {
758
- index.Add(inputKeys, inputVectors);
759
-
760
- // Act
761
- var renamedCount = index.Rename(1, 2);
762
-
763
- // Assert
764
- Assert.Equal(3, renamedCount);
765
- }
766
- }
767
-
768
- [Fact]
769
- public void Rename_ExistingKeyToExistingKeyInMultiKeyIndex_UpdatesOptionsProperly()
770
- {
771
- // Arrange
772
- const uint Dimensions = 10;
773
-
774
- var indexOptions = new IndexOptions(
775
- metricKind: MetricKind.Cos,
776
- quantization: ScalarKind.Float32,
777
- dimensions: Dimensions,
778
- multi: true
779
- );
780
-
781
- var inputKeys = new ulong[] { 1, 1, 1, 2, 2 };
782
- var inputVectors = GenerateManyFloatVectors(5, (int)Dimensions);
783
-
784
- using (var index = new USearchIndex(indexOptions))
785
- {
786
- index.Add(inputKeys, inputVectors);
787
-
788
- // Act
789
- var renamedCount = index.Rename(1, 2);
790
-
791
- // Assert
792
- Assert.False(index.Contains(1));
793
- Assert.True(index.Contains(2));
794
- Assert.Equal(5UL, index.Size());
795
- }
796
- }
797
-
798
- [Fact]
799
- public void Search_UsingL2sq_ReturnsCorrectDistances()
800
- {
801
- // Arrange
802
- const uint Dimensions = 2;
803
- const int StartKey = 1;
804
- const int VectorsCount = 5;
805
- const int MaxSearchCount = 2;
806
-
807
- var indexOptions = new IndexOptions(
808
- metricKind: MetricKind.Cos,
809
- quantization: ScalarKind.Float32,
810
- dimensions: Dimensions,
811
- multi: true
812
- );
813
-
814
- var inputKeys = Enumerable.Range(StartKey, VectorsCount).Select(i => (ulong)i).ToArray();
815
- var inputVectors = new float[][]
816
- {
817
- new float[] { -0.5f, -0.6f },
818
- new float[] { -0.1f, -0.1f },
819
- new float[] { 0.2f, 0.2f },
820
- new float[] { 0.7f, 0.8f },
821
- new float[] { 0.9f, 1.0f }
822
- };
823
- var queryVector = new float[] { 0.0f, 0.0f };
824
-
825
- using (var index = new USearchIndex(MetricKind.L2sq, ScalarKind.Float32, 2))
826
- {
827
- index.Add(inputKeys, inputVectors);
828
-
829
- // Act
830
- var matchCount = index.Search(queryVector, MaxSearchCount, out ulong[] returnedKeys, out float[] returnedDistances);
831
- _ = index.Get(returnedKeys[0], out float[] firstVector);
832
- _ = index.Get(returnedKeys[1], out float[] secondVector);
833
-
834
- // Assert
835
- Assert.Equal(MaxSearchCount, matchCount);
836
- Assert.Equal(new ulong[] { 2UL, 3UL }, returnedKeys);
837
- Assert.Equal(L2sqDistance.L2sq<float>(queryVector, firstVector), returnedDistances[0], EqualTolerance);
838
- Assert.Equal(L2sqDistance.L2sq<float>(queryVector, secondVector), returnedDistances[1], EqualTolerance);
839
- }
840
- }
841
-
842
- [Fact]
843
- public void Search_AfterRemovingKey_ReturnsCorrectMatches()
844
- {
845
- // Arrange
846
- const uint Dimensions = 2;
847
- const ulong StartKey = 1;
848
- const int VectorsCount = 10;
849
- const ulong RemoveKey = 3;
850
- const int MaxSearchCount = 9;
851
-
852
- var indexOptions = new IndexOptions(
853
- metricKind: MetricKind.Cos,
854
- quantization: ScalarKind.Float32,
855
- dimensions: Dimensions,
856
- multi: true
857
- );
858
-
859
- var inputKeys = Enumerable.Range((int)StartKey, VectorsCount).Select(x => (ulong)x).ToArray();
860
- var inputVectors = GenerateManyFloatVectors(VectorsCount, (int)Dimensions);
861
- var queryVector = GenerateFloatVector((int)Dimensions);
862
-
863
- using (var index = new USearchIndex(indexOptions))
864
- {
865
- index.Add(inputKeys, inputVectors);
866
- index.Remove(RemoveKey);
867
-
868
- // Act
869
- var matchCount = index.Search(queryVector, MaxSearchCount, out ulong[] returnedKeys, out float[] returnedDistances);
870
-
871
- // Assert
872
- Assert.Equal(VectorsCount - 1, matchCount);
873
- Assert.Equivalent(inputKeys.Where(x => x != RemoveKey).ToArray(), returnedKeys);
874
- }
875
- }
876
-
877
- [Fact]
878
- public void Search_CountExceedsIndexSize_ReturnsAllMatches()
879
- {
880
- // Arrange
881
- const uint Dimensions = 2;
882
- const ulong StartKey = 1;
883
- const int VectorsCount = 2;
884
- const int MaxSearchCount = 10;
885
-
886
- var indexOptions = new IndexOptions(
887
- metricKind: MetricKind.Cos,
888
- quantization: ScalarKind.Float32,
889
- dimensions: Dimensions,
890
- multi: true
891
- );
892
-
893
- var inputKeys = Enumerable.Range((int)StartKey, VectorsCount).Select(x => (ulong)x).ToArray();
894
- var inputVectors = GenerateManyFloatVectors(VectorsCount, (int)Dimensions);
895
- var queryVector = GenerateFloatVector((int)Dimensions);
896
-
897
- using (var index = new USearchIndex(indexOptions))
898
- {
899
- index.Add(inputKeys, inputVectors);
900
-
901
- // Act
902
- var matchCount = index.Search(queryVector, MaxSearchCount, out ulong[] returnedKeys, out float[] returnedDistances);
903
-
904
- // Assert
905
- Assert.Equal(VectorsCount, matchCount);
906
- Assert.Equivalent(inputKeys, returnedKeys);
907
- }
908
- }
909
-
910
- #region private ================================================================================
911
-
912
- private static float[] GenerateFloatVector(int vectorLength)
913
- {
914
- return Enumerable.Range(0, vectorLength).Select(i => (float)i).ToArray();
915
- }
916
-
917
- private static float[][] GenerateManyFloatVectors(int n, int vectorLength)
918
- {
919
- var result = new float[n][];
920
- for (int i = 0; i < n; i++)
921
- {
922
- result[i] = Enumerable.Range(0, vectorLength).Select(i => (float)i).ToArray();
923
- }
924
- return result;
925
- }
926
-
927
- private static double[] GenerateDoubleVector(int n)
928
- {
929
- return Enumerable.Range(0, n).Select(i => (double)i).ToArray();
930
- }
931
-
932
- private static float[][] GenerateManyDoubleVectors(int n, int vectorLength)
933
- {
934
- var result = new float[n][];
935
- for (int i = 0; i < n; i++)
936
- {
937
- result[i] = Enumerable.Range(0, vectorLength).Select(i => (float)i).ToArray();
938
- }
939
- return result;
940
- }
941
-
942
- #endregion
943
- }
944
-
945
- internal class RealEqualityComparer<T> : IEqualityComparer<T> where T : unmanaged
946
- {
947
- private readonly T _threshold;
948
-
949
- public RealEqualityComparer(T threshold) => this._threshold = threshold;
950
-
951
- public bool Equals(T a, T b)
952
- {
953
- return Math.Abs((dynamic)a - (dynamic)b) < this._threshold;
954
- }
955
-
956
- public int GetHashCode(T obj)
957
- {
958
- return obj.GetHashCode();
959
- }
960
- }
961
-
962
- internal static class L2sqDistance
963
- {
964
- public static double L2sq<TNumber>(ReadOnlySpan<TNumber> x, ReadOnlySpan<TNumber> y) where TNumber : unmanaged
965
- {
966
- if (typeof(TNumber) == typeof(float))
967
- {
968
- ReadOnlySpan<float> floatSpanX = MemoryMarshal.Cast<TNumber, float>(x);
969
- ReadOnlySpan<float> floatSpanY = MemoryMarshal.Cast<TNumber, float>(y);
970
- return L2sqImplementation(floatSpanX, floatSpanY);
971
- }
972
- else if (typeof(TNumber) == typeof(double))
973
- {
974
- ReadOnlySpan<double> doubleSpanX = MemoryMarshal.Cast<TNumber, double>(x);
975
- ReadOnlySpan<double> doubleSpanY = MemoryMarshal.Cast<TNumber, double>(y);
976
- return L2sqImplementation(doubleSpanX, doubleSpanY);
977
- }
978
- else
979
- {
980
- throw new NotSupportedException();
981
- }
982
- }
983
-
984
- public static double L2sq<TNumber>(TNumber[] x, TNumber[] y)
985
- where TNumber : unmanaged
986
- {
987
- return L2sq(new ReadOnlySpan<TNumber>(x), new ReadOnlySpan<TNumber>(y));
988
- }
989
-
990
- #region private ================================================================================
991
-
992
- private static double L2sqImplementation(ReadOnlySpan<double> x, ReadOnlySpan<double> y)
993
- {
994
- double distanceSum = 0;
995
- for (int i = 0; i < x.Length; i++)
996
- {
997
- distanceSum += (x[i] - y[i]) * (x[i] - y[i]);
998
- }
999
- return distanceSum;
1000
- }
1001
-
1002
- private static double L2sqImplementation(ReadOnlySpan<float> x, ReadOnlySpan<float> y)
1003
- {
1004
- double distanceSum = 0;
1005
- for (int i = 0; i < x.Length; i++)
1006
- {
1007
- distanceSum += (x[i] - y[i]) * (x[i] - y[i]);
1008
- }
1009
- return distanceSum;
1010
- }
1011
-
1012
- #endregion
1013
- }