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,193 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "code",
5
- "execution_count": null,
6
- "metadata": {},
7
- "outputs": [],
8
- "source": [
9
- "!pip install faiss-cpu numba pandas plotly nbformat jinja2 kaleido tqdm scikit-learn scipy matplotlib"
10
- ]
11
- },
12
- {
13
- "cell_type": "code",
14
- "execution_count": 1,
15
- "metadata": {},
16
- "outputs": [],
17
- "source": [
18
- "from bench import *\n",
19
- "import plotly.graph_objects as go"
20
- ]
21
- },
22
- {
23
- "cell_type": "code",
24
- "execution_count": 6,
25
- "metadata": {},
26
- "outputs": [
27
- {
28
- "data": {
29
- "text/plain": [
30
- "('auto', 'auto', 'auto')"
31
- ]
32
- },
33
- "execution_count": 6,
34
- "metadata": {},
35
- "output_type": "execute_result"
36
- }
37
- ],
38
- "source": [
39
- "from usearch.index import Index\n",
40
- "\n",
41
- "Index(ndim=256, metric=\"cos\", dtype=\"f32\").hardware_acceleration, Index(ndim=256, metric=\"cos\", dtype=\"f16\").hardware_acceleration, Index(ndim=256, metric=\"cos\", dtype=\"i8\").hardware_acceleration"
42
- ]
43
- },
44
- {
45
- "cell_type": "code",
46
- "execution_count": null,
47
- "metadata": {},
48
- "outputs": [],
49
- "source": [
50
- "def speed_chart(df, title):\n",
51
- " subtitles = [\n",
52
- " f'{n}, recall@1 ~{r*100:.2f}%'\n",
53
- " for n, r in zip(df['names'], df['recall_at_one'])\n",
54
- " ]\n",
55
- " fig = go.Figure(\n",
56
- " data=[\n",
57
- " go.Bar(name='Add', x=subtitles, y=df['add_per_second']),\n",
58
- " go.Bar(name='Search', x=subtitles, y=df['search_per_second']),\n",
59
- " ])\n",
60
- " fig.update_layout(\n",
61
- " width=1000,\n",
62
- " height=1000,\n",
63
- " barmode='group',\n",
64
- " title=dict(\n",
65
- " text=title,\n",
66
- " ),\n",
67
- " legend=dict(\n",
68
- " orientation='h',\n",
69
- " entrywidth=70,\n",
70
- " yanchor='bottom',\n",
71
- " y=1.02,\n",
72
- " xanchor='right',\n",
73
- " x=1,\n",
74
- " ),\n",
75
- " )\n",
76
- " fig.write_image(title + '.png')\n",
77
- " return fig"
78
- ]
79
- },
80
- {
81
- "cell_type": "code",
82
- "execution_count": null,
83
- "metadata": {},
84
- "outputs": [],
85
- "source": [
86
- "from usearch.eval import Dataset\n",
87
- "data = Dataset.build(\n",
88
- " vectors='../../datasets/wiki_1M/base.1M.fbin',\n",
89
- " queries='../../datasets/wiki_1M/query.public.100K.fbin',\n",
90
- " neighbors='../../datasets/wiki_1M/groundtruth.public.100K.ibin',\n",
91
- ")"
92
- ]
93
- },
94
- {
95
- "cell_type": "code",
96
- "execution_count": null,
97
- "metadata": {},
98
- "outputs": [],
99
- "source": [
100
- "eval_default = Evaluation.for_dataset(data)\n",
101
- "results_default = bench_speed(eval_default, jit=True)\n",
102
- "results_default"
103
- ]
104
- },
105
- {
106
- "cell_type": "code",
107
- "execution_count": null,
108
- "metadata": {},
109
- "outputs": [],
110
- "source": [
111
- "speed_chart(results_default, 'USearch vs FAISS Speed')"
112
- ]
113
- },
114
- {
115
- "cell_type": "code",
116
- "execution_count": null,
117
- "metadata": {},
118
- "outputs": [],
119
- "source": [
120
- "eval_sliced = Evaluation.for_dataset(data, batch_size=256)\n",
121
- "results_sliced = bench_speed(eval_sliced, jit=True)\n",
122
- "results_sliced"
123
- ]
124
- },
125
- {
126
- "cell_type": "code",
127
- "execution_count": null,
128
- "metadata": {},
129
- "outputs": [],
130
- "source": [
131
- "speed_chart(results_sliced, 'USearch vs FAISS Speed with 256 Batch Size')"
132
- ]
133
- },
134
- {
135
- "cell_type": "code",
136
- "execution_count": null,
137
- "metadata": {},
138
- "outputs": [],
139
- "source": [
140
- "eval_clustered = Evaluation.for_dataset(data, clusters=10_000)\n",
141
- "len(eval_clustered.tasks)"
142
- ]
143
- },
144
- {
145
- "cell_type": "code",
146
- "execution_count": null,
147
- "metadata": {},
148
- "outputs": [],
149
- "source": [
150
- "results_clustered = bench_speed(eval_clustered)\n",
151
- "results_clustered"
152
- ]
153
- },
154
- {
155
- "cell_type": "code",
156
- "execution_count": null,
157
- "metadata": {},
158
- "outputs": [],
159
- "source": [
160
- "speed_chart(results_clustered, 'USearch vs FAISS Speed on Clustered Data')"
161
- ]
162
- },
163
- {
164
- "cell_type": "code",
165
- "execution_count": null,
166
- "metadata": {},
167
- "outputs": [],
168
- "source": []
169
- }
170
- ],
171
- "metadata": {
172
- "kernelspec": {
173
- "display_name": "usearch-test",
174
- "language": "python",
175
- "name": "python3"
176
- },
177
- "language_info": {
178
- "codemirror_mode": {
179
- "name": "ipython",
180
- "version": 3
181
- },
182
- "file_extension": ".py",
183
- "mimetype": "text/x-python",
184
- "name": "python",
185
- "nbconvert_exporter": "python",
186
- "pygments_lexer": "ipython3",
187
- "version": "3.11.5"
188
- },
189
- "orig_nbformat": 4
190
- },
191
- "nbformat": 4,
192
- "nbformat_minor": 2
193
- }
@@ -1,137 +0,0 @@
1
- import itertools
2
- from typing import List
3
- from dataclasses import asdict
4
-
5
- import numpy as np
6
- import pandas as pd
7
-
8
- from usearch.index import Index, Key, MetricKind, ScalarKind
9
- from usearch.numba import jit as njit
10
- from usearch.eval import Evaluation, AddTask
11
- from usearch.index import (
12
- DEFAULT_CONNECTIVITY,
13
- DEFAULT_EXPANSION_ADD,
14
- DEFAULT_EXPANSION_SEARCH,
15
- )
16
-
17
-
18
- def bench_speed(
19
- eval: Evaluation,
20
- connectivity: int = DEFAULT_CONNECTIVITY,
21
- expansion_add: int = DEFAULT_EXPANSION_ADD,
22
- expansion_search: int = DEFAULT_EXPANSION_SEARCH,
23
- jit: bool = False,
24
- train: bool = False,
25
- ) -> pd.DataFrame:
26
- # Build various indexes:
27
- indexes = []
28
- jit_options = [False, True] if jit else [False]
29
- dtype_options = [ScalarKind.F32, ScalarKind.F16, ScalarKind.I8]
30
- for jit, dtype in itertools.product(jit_options, dtype_options):
31
- metric = MetricKind.IP
32
- if jit:
33
- metric = njit(eval.ndim, metric, dtype)
34
- index = Index(
35
- ndim=eval.ndim,
36
- metric=metric,
37
- dtype=dtype,
38
- expansion_add=expansion_add,
39
- expansion_search=expansion_search,
40
- connectivity=connectivity,
41
- path="USearch" + ["", "+JIT"][jit] + ":" + str(dtype),
42
- )
43
-
44
- # Skip the cases, where JIT-ing is impossible
45
- if jit and not index.jit:
46
- continue
47
- indexes.append(index)
48
-
49
- # Add FAISS indexes to the mix:
50
- try:
51
- from index_faiss import IndexFAISS, IndexQuantizedFAISS
52
-
53
- indexes.append(
54
- IndexFAISS(
55
- ndim=eval.ndim,
56
- expansion_add=expansion_add,
57
- expansion_search=expansion_search,
58
- connectivity=connectivity,
59
- path="FAISS:f32",
60
- )
61
- )
62
- if train:
63
- indexes.append(
64
- IndexQuantizedFAISS(
65
- train=eval.tasks[0].vectors,
66
- expansion_add=expansion_add,
67
- expansion_search=expansion_search,
68
- connectivity=connectivity,
69
- path="FAISS+IVFPQ:f32",
70
- )
71
- )
72
- except (ImportError, ModuleNotFoundError):
73
- pass
74
-
75
- # Time to evaluate:
76
- results = [eval(index) for index in indexes]
77
- return pd.DataFrame(
78
- {
79
- "names": [i.path for i in indexes],
80
- "add_per_second": [x["add_per_second"] for x in results],
81
- "search_per_second": [x["search_per_second"] for x in results],
82
- "recall_at_one": [x["recall_at_one"] for x in results],
83
- }
84
- )
85
-
86
-
87
- def bench_params(
88
- count: int = 1_000_000,
89
- connectivities: int = range(10, 20),
90
- dimensions: List[int] = [
91
- 2,
92
- 3,
93
- 4,
94
- 8,
95
- 16,
96
- 32,
97
- 96,
98
- 100,
99
- 256,
100
- 384,
101
- 512,
102
- 768,
103
- 1024,
104
- 1536,
105
- ],
106
- expansion_add: int = DEFAULT_EXPANSION_ADD,
107
- expansion_search: int = DEFAULT_EXPANSION_SEARCH,
108
- ) -> pd.DataFrame:
109
- """Measures indexing speed for different dimensionality vectors.
110
-
111
- :param count: Number of vectors, defaults to 1_000_000
112
- :type count: int, optional
113
- """
114
-
115
- results = []
116
- for connectivity, ndim in itertools.product(connectivities, dimensions):
117
- task = AddTask(
118
- keys=np.arange(count, dtype=Key),
119
- vectors=np.random.rand(count, ndim).astype(np.float32),
120
- )
121
- index = Index(
122
- ndim=ndim,
123
- connectivity=connectivity,
124
- expansion_add=expansion_add,
125
- expansion_search=expansion_search,
126
- )
127
- result = asdict(task(index))
128
- result["ndim"] = dimensions
129
- result["connectivity"] = connectivity
130
- results.append(result)
131
-
132
- # return self._execute_tasks(
133
- # tasks,
134
- # title='HNSW Indexing Speed vs Vector Dimensions',
135
- # x='ndim', y='add_per_second', log_x=True,
136
- # )
137
- return pd.DataFrame(results)
@@ -1,44 +0,0 @@
1
- from time import time
2
-
3
- from usearch.index import search, MetricKind, ScalarKind
4
- from usearch.compiled import hardware_acceleration
5
- from faiss import knn, METRIC_L2
6
- import numpy as np
7
- import fire
8
-
9
-
10
- def run(
11
- n: int = 10**5,
12
- q: int = 10,
13
- k: int = 100,
14
- ndim: int = 256,
15
- half: bool = False,
16
- ):
17
- usearch_dtype = ScalarKind.F16 if half else ScalarKind.F32
18
- acceleration = hardware_acceleration(
19
- dtype=usearch_dtype,
20
- ndim=ndim,
21
- metric_kind=MetricKind.L2sq,
22
- )
23
- print("Hardware acceleration in USearch: ", acceleration)
24
-
25
- x = np.random.random((n, ndim))
26
- x = x.astype(np.float16) if half else x.astype(np.float32)
27
-
28
- start = time()
29
- _ = search(
30
- x,
31
- x[:q],
32
- k,
33
- MetricKind.L2sq,
34
- exact=True,
35
- ).keys
36
- print("USearch: ", time() - start)
37
-
38
- start = time()
39
- _ = knn(x[:q], x, k, metric=METRIC_L2)[1]
40
- print("FAISS: ", time() - start)
41
-
42
-
43
- if __name__ == "__main__":
44
- fire.Fire(run)
@@ -1,160 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "code",
5
- "execution_count": null,
6
- "metadata": {},
7
- "outputs": [],
8
- "source": [
9
- "from usearch.io import load_matrix\n",
10
- "import numpy as np"
11
- ]
12
- },
13
- {
14
- "cell_type": "code",
15
- "execution_count": null,
16
- "metadata": {},
17
- "outputs": [],
18
- "source": [
19
- "vectors = load_matrix(\"datasets/arxiv_2M/abstract.e5-base-v2.fbin\", view=True)"
20
- ]
21
- },
22
- {
23
- "cell_type": "code",
24
- "execution_count": null,
25
- "metadata": {},
26
- "outputs": [],
27
- "source": [
28
- "vectors.shape"
29
- ]
30
- },
31
- {
32
- "cell_type": "code",
33
- "execution_count": null,
34
- "metadata": {},
35
- "outputs": [],
36
- "source": [
37
- "from usearch.index import Index, USES_SIMSIMD, USES_NATIVE_F16\n",
38
- "\n",
39
- "index = Index(ndim=vectors.shape[1], metric=\"cos\", dtype=\"i8\")\n",
40
- "index.hardware_acceleration, USES_SIMSIMD, USES_NATIVE_F16"
41
- ]
42
- },
43
- {
44
- "cell_type": "code",
45
- "execution_count": null,
46
- "metadata": {},
47
- "outputs": [],
48
- "source": [
49
- "\n",
50
- "import os\n",
51
- "\n",
52
- "if os.path.exists(\"cluster.i8.usearch\"):\n",
53
- " index.load(\"cluster.i8.usearch\")\n",
54
- "\n",
55
- "if len(index) == 0:\n",
56
- " index.add(None, vectors, log=True)\n",
57
- " index.save(\"cluster.i8.usearch\")"
58
- ]
59
- },
60
- {
61
- "cell_type": "code",
62
- "execution_count": null,
63
- "metadata": {},
64
- "outputs": [],
65
- "source": [
66
- "index"
67
- ]
68
- },
69
- {
70
- "cell_type": "code",
71
- "execution_count": null,
72
- "metadata": {},
73
- "outputs": [],
74
- "source": [
75
- "clustering = index.cluster(min_count=10, max_count=15, threads=60)\n",
76
- "clustering"
77
- ]
78
- },
79
- {
80
- "cell_type": "code",
81
- "execution_count": null,
82
- "metadata": {},
83
- "outputs": [],
84
- "source": [
85
- "print(f\"{len(clustering.centroids_popularity[0])} unique clusters for {len(index)} members\")"
86
- ]
87
- },
88
- {
89
- "cell_type": "code",
90
- "execution_count": null,
91
- "metadata": {},
92
- "outputs": [],
93
- "source": [
94
- "clustering.plot_centroids_popularity()"
95
- ]
96
- },
97
- {
98
- "cell_type": "code",
99
- "execution_count": null,
100
- "metadata": {},
101
- "outputs": [],
102
- "source": [
103
- "nx.draw_networkx(g)"
104
- ]
105
- },
106
- {
107
- "cell_type": "code",
108
- "execution_count": null,
109
- "metadata": {},
110
- "outputs": [],
111
- "source": [
112
- "import matplotlib.pyplot as plt\n",
113
- "import networkx as nx\n",
114
- "\n",
115
- "G = g\n",
116
- "\n",
117
- "node_sizes = nx.get_node_attributes(G, \"size\").values()\n",
118
- "max_node_size = max(node_sizes)\n",
119
- "node_sizes = [size * 10 / max_node_size for size in node_sizes]\n",
120
- "\n",
121
- "edge_labels = nx.get_edge_attributes(G, \"distance\")\n",
122
- "edge_labels = {edge: f\"{label:.2}\" for edge, label in edge_labels.items()}\n",
123
- "\n",
124
- "pos = nx.spring_layout(G, seed=7)\n",
125
- "nx.draw_networkx_nodes(G, pos, node_size=node_sizes)\n",
126
- "nx.draw_networkx_edges(G, pos, edgelist=G.edges(data=False))\n",
127
- "nx.draw_networkx_labels(G, pos, font_size=10, font_family=\"sans-serif\")\n",
128
- "nx.draw_networkx_edge_labels(G, pos, edge_labels, font_size=5)\n",
129
- "\n",
130
- "ax = plt.gca()\n",
131
- "ax.margins(0.08)\n",
132
- "plt.axis(\"off\")\n",
133
- "plt.tight_layout()\n",
134
- "plt.show()"
135
- ]
136
- }
137
- ],
138
- "metadata": {
139
- "kernelspec": {
140
- "display_name": "base",
141
- "language": "python",
142
- "name": "python3"
143
- },
144
- "language_info": {
145
- "codemirror_mode": {
146
- "name": "ipython",
147
- "version": 3
148
- },
149
- "file_extension": ".py",
150
- "mimetype": "text/x-python",
151
- "name": "python",
152
- "nbconvert_exporter": "python",
153
- "pygments_lexer": "ipython3",
154
- "version": "3.10.11"
155
- },
156
- "orig_nbformat": 4
157
- },
158
- "nbformat": 4,
159
- "nbformat_minor": 2
160
- }
@@ -1,100 +0,0 @@
1
- import os
2
- from typing import Optional
3
-
4
- import numpy as np
5
- from faiss import IndexHNSWFlat, IndexIVFPQ, read_index
6
-
7
- from usearch.index import Matches, BatchMatches
8
- from usearch.index import (
9
- DEFAULT_CONNECTIVITY,
10
- DEFAULT_EXPANSION_ADD,
11
- DEFAULT_EXPANSION_SEARCH,
12
- )
13
-
14
-
15
- class IndexFAISS:
16
- def __init__(
17
- self,
18
- index: IndexHNSWFlat = None,
19
- ndim: int = 0,
20
- connectivity: int = DEFAULT_CONNECTIVITY,
21
- expansion_add: int = DEFAULT_EXPANSION_ADD,
22
- expansion_search: int = DEFAULT_EXPANSION_SEARCH,
23
- path: Optional[os.PathLike] = None,
24
- *args,
25
- **kwargs,
26
- ):
27
- if index is None:
28
- index = IndexHNSWFlat(ndim, connectivity)
29
- index.hnsw.efConstruction = expansion_add
30
- index.hnsw.efSearch = expansion_search
31
-
32
- self._faiss = index
33
- self._specs = {
34
- "Class": "usearch.IndexFAISS",
35
- "Dimensions": ndim,
36
- "Connectivity": connectivity,
37
- "Expansion@Add": expansion_add,
38
- "Expansion@Search": expansion_search,
39
- }
40
-
41
- self.path = path
42
-
43
- def add(self, keys, vectors):
44
- # Adding keys isn't supported for most index types
45
- # self._faiss.add_with_ids(vectors, keys)
46
- self._faiss.add(vectors)
47
-
48
- def search(self, queries, k: int) -> BatchMatches:
49
- distances, keys = self._faiss.search(queries, k)
50
- return BatchMatches(keys, distances, np.array([k] * queries.shape[0]))
51
-
52
- def __len__(self) -> int:
53
- return self._faiss.ntotal
54
-
55
- def clear(self):
56
- self._faiss.reset()
57
-
58
- @property
59
- def specs(self) -> dict:
60
- self._specs.update(
61
- {
62
- "Size": len(self),
63
- }
64
- )
65
- return self._specs
66
-
67
- def load(self, path: os.PathLike):
68
- self._faiss = read_index(path)
69
-
70
-
71
- class IndexQuantizedFAISS(IndexFAISS):
72
- def __init__(
73
- self,
74
- train: np.ndarray,
75
- connectivity: int = DEFAULT_CONNECTIVITY,
76
- expansion_add: int = DEFAULT_EXPANSION_ADD,
77
- expansion_search: int = DEFAULT_EXPANSION_SEARCH,
78
- *args,
79
- **kwargs,
80
- ):
81
- ndim = train.shape[1]
82
- super().__init__(
83
- ndim=ndim,
84
- connectivity=connectivity,
85
- expansion_add=expansion_add,
86
- expansion_search=expansion_search,
87
- *args,
88
- **kwargs,
89
- )
90
-
91
- nlist = 10000 # Number of inverted lists (number of partitions).
92
- nsegment = 16 # Number of segments for PQ (number of subquantizers).
93
- nbit = 8 # Number of bits to encode each segment.
94
-
95
- self._original_faiss = self._faiss
96
- self._faiss = IndexIVFPQ(self._faiss, ndim, nlist, nsegment, nbit)
97
-
98
- self._faiss.train(train)
99
- self._faiss.nprobe = 10
100
- self._specs["Class"] = "usearch.IndexQuantizedFAISS"