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.
- package/CITATION.cff +1 -1
- package/CMakeLists.txt +3 -3
- package/CONTRIBUTING.md +26 -3
- package/Cargo.toml +1 -1
- package/Dockerfile +16 -0
- package/README.md +41 -38
- package/VERSION +1 -0
- package/binding.gyp +57 -8
- package/conanfile.py +1 -1
- package/include/usearch/index.hpp +1 -1
- package/include/usearch/index_plugins.hpp +28 -24
- package/javascript/README.md +64 -12
- package/javascript/lib.cpp +11 -3
- package/javascript/usearch.js +4 -2
- package/javascript/usearch.test.js +15 -0
- package/package.json +1 -2
- package/setup.py +76 -15
- package/simsimd/README.md +14 -13
- package/simsimd/include/simsimd/probability.h +2 -2
- package/simsimd/package.json +1 -1
- package/wasmer.toml +1 -1
- package/. npmignore +0 -14
- package/.gitignore +0 -95
- package/.vscode/launch.json +0 -181
- package/.vscode/settings.json +0 -180
- package/.vscode/tasks.json +0 -71
- package/Package.swift +0 -41
- package/csharp/.editorconfig +0 -361
- package/csharp/Cloud.Unum.USearch.sln +0 -34
- package/csharp/DEV_SETUP.md +0 -51
- package/csharp/Directory.Build.props +0 -29
- package/csharp/README.md +0 -74
- package/csharp/build_and_test.cmd +0 -31
- package/csharp/build_and_test.sh +0 -30
- package/csharp/nuget/nuget-package.props +0 -33
- package/csharp/pack.sh +0 -56
- package/csharp/src/Cloud.Unum.USearch.Tests/Cloud.Unum.USearch.Tests.csproj +0 -39
- package/csharp/src/Cloud.Unum.USearch.Tests/USearchIndexTests.cs +0 -1013
- package/csharp/src/Cloud.Unum.USearch.Tests/Usings.cs +0 -1
- package/docs/_static/custom.css +0 -26
- package/docs/_static/custom.js +0 -7
- package/docs/benchmarks.md +0 -245
- package/docs/benchmarks.rst +0 -5
- package/docs/c/index.rst +0 -11
- package/docs/c/reference.rst +0 -7
- package/docs/conf.dox +0 -2668
- package/docs/conf.py +0 -53
- package/docs/contributing.rst +0 -5
- package/docs/cpp/index.rst +0 -11
- package/docs/cpp/reference.rst +0 -17
- package/docs/csharp/index.rst +0 -6
- package/docs/format.md +0 -86
- package/docs/format.rst +0 -5
- package/docs/golang/index.rst +0 -6
- package/docs/index.rst +0 -33
- package/docs/java/index.rst +0 -11
- package/docs/java/reference.rst +0 -7
- package/docs/javascript/index.rst +0 -11
- package/docs/javascript/reference.rst +0 -12
- package/docs/python/index.rst +0 -11
- package/docs/python/reference.rst +0 -42
- package/docs/rust/index.rst +0 -6
- package/docs/swift/index.rst +0 -6
- package/docs/wolfram/index.rst +0 -6
- package/golang/README.md +0 -95
- package/golang/go.mod +0 -3
- package/golang/lib.go +0 -379
- package/golang/lib_test.go +0 -108
- package/java/README.md +0 -22
- package/java/cloud/unum/usearch/Index.java +0 -337
- package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +0 -197
- package/java/cloud/unum/usearch/cloud_unum_usearch_Index.h +0 -125
- package/java/test/IndexTest.java +0 -30
- package/objc/USearchObjective.mm +0 -299
- package/objc/include/USearchObjective.h +0 -154
- package/python/README.md +0 -292
- package/python/lib.cpp +0 -1216
- package/python/scripts/bench.ipynb +0 -193
- package/python/scripts/bench.py +0 -137
- package/python/scripts/bench_exact.py +0 -44
- package/python/scripts/cluster.ipynb +0 -160
- package/python/scripts/index_faiss.py +0 -100
- package/python/scripts/join.py +0 -155
- package/python/scripts/test_index.py +0 -247
- package/python/scripts/test_jit.py +0 -231
- package/python/scripts/test_sparse.py +0 -32
- package/python/scripts/test_tooling.py +0 -133
- package/python/usearch/__init__.py +0 -0
- package/python/usearch/client.py +0 -124
- package/python/usearch/eval.py +0 -470
- package/python/usearch/index.py +0 -1401
- package/python/usearch/io.py +0 -113
- package/python/usearch/numba.py +0 -121
- package/python/usearch/server.py +0 -137
- package/rust/README.md +0 -66
- package/rust/lib.cpp +0 -136
- package/rust/lib.hpp +0 -69
- package/rust/lib.rs +0 -610
- package/simsimd/CMakeLists.txt +0 -67
- package/simsimd/cpp/bench.cxx +0 -206
- package/simsimd/package-ci.json +0 -10
- package/simsimd/setup.py +0 -86
- package/swift/Index+Sugar.swift +0 -153
- package/swift/README.md +0 -48
- package/swift/Test.swift +0 -37
- package/swift/USearch.swift +0 -8
- package/wasm/CMakeLists.txt +0 -7
- package/wasm/README.md +0 -13
- package/wasm/lib.cpp +0 -5
- package/wolfram/CMakeLists.txt +0 -18
- package/wolfram/README.md +0 -13
- package/wolfram/lib.cpp +0 -160
- 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
|
-
}
|