usearch 2.8.7 → 2.8.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/CITATION.cff +1 -1
  2. package/CMakeLists.txt +3 -3
  3. package/CONTRIBUTING.md +26 -3
  4. package/Cargo.toml +1 -1
  5. package/Dockerfile +16 -0
  6. package/README.md +41 -38
  7. package/VERSION +1 -0
  8. package/binding.gyp +57 -8
  9. package/conanfile.py +1 -1
  10. package/include/usearch/index.hpp +1 -1
  11. package/include/usearch/index_plugins.hpp +28 -24
  12. package/javascript/README.md +64 -12
  13. package/javascript/lib.cpp +11 -3
  14. package/javascript/usearch.js +4 -2
  15. package/javascript/usearch.test.js +15 -0
  16. package/package.json +1 -2
  17. package/setup.py +76 -15
  18. package/simsimd/README.md +14 -13
  19. package/simsimd/include/simsimd/probability.h +2 -2
  20. package/simsimd/package.json +1 -1
  21. package/wasmer.toml +1 -1
  22. package/. npmignore +0 -14
  23. package/.gitignore +0 -95
  24. package/.vscode/launch.json +0 -181
  25. package/.vscode/settings.json +0 -180
  26. package/.vscode/tasks.json +0 -71
  27. package/Package.swift +0 -41
  28. package/csharp/.editorconfig +0 -361
  29. package/csharp/Cloud.Unum.USearch.sln +0 -34
  30. package/csharp/DEV_SETUP.md +0 -51
  31. package/csharp/Directory.Build.props +0 -29
  32. package/csharp/README.md +0 -74
  33. package/csharp/build_and_test.cmd +0 -31
  34. package/csharp/build_and_test.sh +0 -30
  35. package/csharp/nuget/nuget-package.props +0 -33
  36. package/csharp/pack.sh +0 -56
  37. package/csharp/src/Cloud.Unum.USearch.Tests/Cloud.Unum.USearch.Tests.csproj +0 -39
  38. package/csharp/src/Cloud.Unum.USearch.Tests/USearchIndexTests.cs +0 -1013
  39. package/csharp/src/Cloud.Unum.USearch.Tests/Usings.cs +0 -1
  40. package/docs/_static/custom.css +0 -26
  41. package/docs/_static/custom.js +0 -7
  42. package/docs/benchmarks.md +0 -245
  43. package/docs/benchmarks.rst +0 -5
  44. package/docs/c/index.rst +0 -11
  45. package/docs/c/reference.rst +0 -7
  46. package/docs/conf.dox +0 -2668
  47. package/docs/conf.py +0 -53
  48. package/docs/contributing.rst +0 -5
  49. package/docs/cpp/index.rst +0 -11
  50. package/docs/cpp/reference.rst +0 -17
  51. package/docs/csharp/index.rst +0 -6
  52. package/docs/format.md +0 -86
  53. package/docs/format.rst +0 -5
  54. package/docs/golang/index.rst +0 -6
  55. package/docs/index.rst +0 -33
  56. package/docs/java/index.rst +0 -11
  57. package/docs/java/reference.rst +0 -7
  58. package/docs/javascript/index.rst +0 -11
  59. package/docs/javascript/reference.rst +0 -12
  60. package/docs/python/index.rst +0 -11
  61. package/docs/python/reference.rst +0 -42
  62. package/docs/rust/index.rst +0 -6
  63. package/docs/swift/index.rst +0 -6
  64. package/docs/wolfram/index.rst +0 -6
  65. package/golang/README.md +0 -95
  66. package/golang/go.mod +0 -3
  67. package/golang/lib.go +0 -379
  68. package/golang/lib_test.go +0 -108
  69. package/java/README.md +0 -22
  70. package/java/cloud/unum/usearch/Index.java +0 -337
  71. package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +0 -197
  72. package/java/cloud/unum/usearch/cloud_unum_usearch_Index.h +0 -125
  73. package/java/test/IndexTest.java +0 -30
  74. package/objc/USearchObjective.mm +0 -299
  75. package/objc/include/USearchObjective.h +0 -154
  76. package/python/README.md +0 -292
  77. package/python/lib.cpp +0 -1216
  78. package/python/scripts/bench.ipynb +0 -193
  79. package/python/scripts/bench.py +0 -137
  80. package/python/scripts/bench_exact.py +0 -44
  81. package/python/scripts/cluster.ipynb +0 -160
  82. package/python/scripts/index_faiss.py +0 -100
  83. package/python/scripts/join.py +0 -155
  84. package/python/scripts/test_index.py +0 -247
  85. package/python/scripts/test_jit.py +0 -231
  86. package/python/scripts/test_sparse.py +0 -32
  87. package/python/scripts/test_tooling.py +0 -133
  88. package/python/usearch/__init__.py +0 -0
  89. package/python/usearch/client.py +0 -124
  90. package/python/usearch/eval.py +0 -470
  91. package/python/usearch/index.py +0 -1401
  92. package/python/usearch/io.py +0 -113
  93. package/python/usearch/numba.py +0 -121
  94. package/python/usearch/server.py +0 -137
  95. package/rust/README.md +0 -66
  96. package/rust/lib.cpp +0 -136
  97. package/rust/lib.hpp +0 -69
  98. package/rust/lib.rs +0 -610
  99. package/simsimd/CMakeLists.txt +0 -67
  100. package/simsimd/cpp/bench.cxx +0 -206
  101. package/simsimd/package-ci.json +0 -10
  102. package/simsimd/setup.py +0 -86
  103. package/swift/Index+Sugar.swift +0 -153
  104. package/swift/README.md +0 -48
  105. package/swift/Test.swift +0 -37
  106. package/swift/USearch.swift +0 -8
  107. package/wasm/CMakeLists.txt +0 -7
  108. package/wasm/README.md +0 -13
  109. package/wasm/lib.cpp +0 -5
  110. package/wolfram/CMakeLists.txt +0 -18
  111. package/wolfram/README.md +0 -13
  112. package/wolfram/lib.cpp +0 -160
  113. package/wolfram/test.wls +0 -27
@@ -1,133 +0,0 @@
1
- import os
2
-
3
- import pytest
4
- import numpy as np
5
-
6
- from usearch.io import load_matrix, save_matrix
7
- from usearch.index import search
8
- from usearch.eval import random_vectors
9
-
10
- from usearch.index import Match, Matches, BatchMatches, Index, Indexes
11
-
12
-
13
- dimensions = [3, 97, 256]
14
- batch_sizes = [1, 77, 100]
15
-
16
-
17
- @pytest.mark.parametrize("rows", batch_sizes)
18
- @pytest.mark.parametrize("cols", dimensions)
19
- def test_serializing_fbin_matrix(rows: int, cols: int):
20
- """
21
- Test the serialization of floating point binary matrix.
22
-
23
- :param int rows: The number of rows in the matrix.
24
- :param int cols: The number of columns in the matrix.
25
- """
26
- original = np.random.rand(rows, cols).astype(np.float32)
27
- save_matrix(original, "tmp.fbin")
28
- reconstructed = load_matrix("tmp.fbin")
29
- assert np.allclose(original, reconstructed)
30
- os.remove("tmp.fbin")
31
-
32
-
33
- @pytest.mark.parametrize("rows", batch_sizes)
34
- @pytest.mark.parametrize("cols", dimensions)
35
- def test_serializing_ibin_matrix(rows: int, cols: int):
36
- """
37
- Test the serialization of integer binary matrix.
38
-
39
- :param int rows: The number of rows in the matrix.
40
- :param int cols: The number of columns in the matrix.
41
- """
42
- original = np.random.randint(0, rows + 1, size=(rows, cols)).astype(np.int32)
43
- save_matrix(original, "tmp.ibin")
44
- reconstructed = load_matrix("tmp.ibin")
45
- assert np.allclose(original, reconstructed)
46
- os.remove("tmp.ibin")
47
-
48
-
49
- @pytest.mark.parametrize("rows", batch_sizes)
50
- @pytest.mark.parametrize("cols", dimensions)
51
- @pytest.mark.parametrize("k", [1, 5])
52
- @pytest.mark.parametrize("reordered", [False, True])
53
- def test_exact_search(rows: int, cols: int, k: int, reordered: bool):
54
- """
55
- Test exact search.
56
-
57
- :param int rows: The number of rows in the matrix.
58
- :param int cols: The number of columns in the matrix.
59
- """
60
- original = np.random.rand(rows, cols)
61
- keys = np.arange(rows)
62
- k = min(k, rows)
63
-
64
- if reordered:
65
- reordered_keys = np.arange(rows)
66
- np.random.shuffle(reordered_keys)
67
- else:
68
- reordered_keys = keys
69
-
70
- matches: BatchMatches = search(original, original[reordered_keys], k, exact=True)
71
- top_matches = (
72
- [int(m.keys[0]) for m in matches] if rows > 1 else [int(matches.keys[0])]
73
- )
74
- assert top_matches == list(reordered_keys)
75
-
76
- matches: Matches = search(original, original[-1], k, exact=True)
77
- top_match = int(matches.keys[0])
78
- assert top_match == keys[-1]
79
-
80
-
81
- def test_matches_creation_and_methods():
82
- matches = Matches(
83
- keys=np.array([1, 2]),
84
- distances=np.array([0.5, 0.6]),
85
- visited_members=2,
86
- computed_distances=2,
87
- )
88
- assert len(matches) == 2
89
- assert matches[0] == Match(key=1, distance=0.5)
90
- assert matches.to_list() == [(1, 0.5), (2, 0.6)]
91
-
92
-
93
- def test_batch_matches_creation_and_methods():
94
- keys = np.array([[1, 2], [3, 4]])
95
- distances = np.array([[0.5, 0.6], [0.7, 0.8]])
96
- counts = np.array([2, 2])
97
- batch_matches = BatchMatches(
98
- keys=keys,
99
- distances=distances,
100
- counts=counts,
101
- visited_members=2,
102
- computed_distances=2,
103
- )
104
-
105
- assert len(batch_matches) == 2
106
- assert batch_matches[0].keys.tolist() == [1, 2]
107
- assert batch_matches[0].distances.tolist() == [0.5, 0.6]
108
- assert batch_matches.to_list() == [(1, 0.5), (2, 0.6), (3, 0.7), (4, 0.8)]
109
-
110
-
111
- def test_multi_index():
112
- ndim = 10
113
- index_a = Index(ndim=ndim)
114
- index_b = Index(ndim=ndim)
115
-
116
- vectors = random_vectors(count=3, ndim=ndim)
117
- index_a.add(42, vectors[0])
118
- index_b.add(43, vectors[1])
119
-
120
- indexes = Indexes([index_a, index_b])
121
-
122
- # Search top 10 for 1
123
- matches = indexes.search(vectors[2], 10)
124
- assert len(matches) == 2
125
-
126
- # Search top 1 for 1
127
- matches = indexes.search(vectors[2], 1)
128
- assert len(matches) == 1
129
-
130
- # Search top 10 for 3
131
- matches = indexes.search(vectors, 10)
132
- assert len(matches) == 3
133
- assert len(matches[0].keys) == 2
File without changes
@@ -1,124 +0,0 @@
1
- from typing import Union, Optional, List
2
-
3
- import numpy as np
4
- from ucall.client import Client
5
-
6
- from usearch.index import Matches
7
-
8
-
9
- def _vector_to_ascii(vector: np.ndarray) -> Optional[str]:
10
- if vector.dtype != np.int8 and vector.dtype != np.uint8 and vector.dtype != np.byte:
11
- return None
12
- if not np.all((vector >= 0) | (vector <= 100)):
13
- return None
14
-
15
- # Let's map [0, 100] to the range from [23, 123],
16
- # poking 60 and replacing with the 124.
17
- vector += 23
18
- vector[vector == 60] = 124
19
- ascii = str(vector)
20
- return ascii
21
-
22
-
23
- class IndexClient:
24
- def __init__(
25
- self, uri: str = "127.0.0.1", port: int = 8545, use_http: bool = True
26
- ) -> None:
27
- self.client = Client(uri=uri, port=port, use_http=use_http)
28
-
29
- def add_one(self, key: int, vector: np.ndarray):
30
- assert isinstance(key, int)
31
- assert isinstance(vector, np.ndarray)
32
- vector = vector.flatten()
33
- ascii = _vector_to_ascii(vector)
34
- if ascii:
35
- self.client.add_ascii(key=key, string=ascii)
36
- else:
37
- self.client.add_one(key=key, vectors=vector)
38
-
39
- def add_many(self, keys: np.ndarray, vectors: np.ndarray):
40
- assert isinstance(keys, int)
41
- assert isinstance(vectors, np.ndarray)
42
- assert keys.ndim == 1 and vectors.ndim == 2
43
- assert keys.shape[0] == vectors.shape[0]
44
- self.client.add_many(keys=keys, vectors=vectors)
45
-
46
- def add(self, keys: Union[np.ndarray, int], vectors: np.ndarray):
47
- if isinstance(keys, int) or len(keys) == 1:
48
- return self.add_one(keys, vectors)
49
- else:
50
- return self.add_many(keys, vectors)
51
-
52
- def search_one(self, vector: np.ndarray, count: int) -> Matches:
53
- matches: List[dict] = []
54
- vector = vector.flatten()
55
- ascii = _vector_to_ascii(vector)
56
- if ascii:
57
- matches = self.client.search_ascii(string=ascii, count=count)
58
- else:
59
- matches = self.client.search_one(vector=vector, count=count)
60
-
61
- print(matches.data)
62
- matches = matches.json
63
-
64
- keys = np.array((1, count), dtype=np.uint32)
65
- distances = np.array((1, count), dtype=np.float32)
66
- counts = np.array((1), dtype=np.uint32)
67
- for col, result in enumerate(matches):
68
- keys[0, col] = result["key"]
69
- distances[0, col] = result["distance"]
70
- counts[0] = len(matches)
71
-
72
- return keys, distances, counts
73
-
74
- def search_many(self, vectors: np.ndarray, count: int) -> Matches:
75
- batch_size: int = vectors.shape[0]
76
- list_of_matches: List[List[dict]] = self.client.search_many(
77
- vectors=vectors, count=count
78
- )
79
-
80
- keys = np.array((batch_size, count), dtype=np.uint32)
81
- distances = np.array((batch_size, count), dtype=np.float32)
82
- counts = np.array((batch_size), dtype=np.uint32)
83
- for row, matches in enumerate(list_of_matches):
84
- for col, result in enumerate(matches):
85
- keys[row, col] = result["key"]
86
- distances[row, col] = result["distance"]
87
- counts[row] = len(results)
88
-
89
- return keys, distances, counts
90
-
91
- def search(self, vectors: np.ndarray, count: int) -> Matches:
92
- if vectors.ndim == 1 or (vectors.ndim == 2 and vectors.shape[0] == 1):
93
- return self.search_one(vectors, count)
94
- else:
95
- return self.search_many(vectors, count)
96
-
97
- def __len__(self):
98
- return self.client.size().json()
99
-
100
- @property
101
- def ndim(self):
102
- return self.client.ndim().json()
103
-
104
- def capacity(self):
105
- return self.client.capacity().json()
106
-
107
- def connectivity(self):
108
- return self.client.connectivity().json()
109
-
110
- def load(self, path: str):
111
- raise NotImplementedError()
112
-
113
- def view(self, path: str):
114
- raise NotImplementedError()
115
-
116
- def save(self, path: str):
117
- raise NotImplementedError()
118
-
119
-
120
- if __name__ == "__main__":
121
- index = IndexClient()
122
- index.add(42, np.array([0.4] * 256, dtype=np.float32))
123
- results = index.search(np.array([0.4] * 256, dtype=np.float32), 10)
124
- print(results)