usearch 2.8.7 → 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 +1 -2
  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,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"