usearch 0.8.0 → 0.8.1

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/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "usearch"
3
- version = "0.8.0"
3
+ version = "0.8.1"
4
4
  authors = ["Ashot Vardanian <1983160+ashvardanian@users.noreply.github.com>"]
5
5
  description = "Smaller & Faster Single-File Vector Search Engine from Unum"
6
6
  edition = "2021"
package/VERSION CHANGED
@@ -1 +1 @@
1
- 0.8.0
1
+ 0.8.1
package/conanfile.py CHANGED
@@ -4,7 +4,7 @@ from conans import ConanFile
4
4
  class USearchConan(ConanFile):
5
5
 
6
6
  name = 'USearch'
7
- version = '0.8.0'
7
+ version = '0.8.1'
8
8
  license = 'Apache 2.0'
9
9
  url = 'https://github.com/unum-cloud/usearch'
10
10
  description = 'Smaller & Faster Single-File Vector Search Engine from Unum'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usearch",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Smaller & Faster Single-File Vector Search Engine from Unum",
5
5
  "author": "Ashot Vardanian",
6
6
  "license": "Apache 2.0",
package/pyproject.toml CHANGED
@@ -10,7 +10,7 @@ filterwarnings = ["error"]
10
10
 
11
11
  [tool.cibuildwheel]
12
12
  test-requires = ["pytest", "numpy"]
13
- test-command = "pytest {project}/python/test.py"
13
+ test-command = "pytest {project}/python/scripts/test.py"
14
14
  build-verbosity = 0
15
15
  skip = ["*musllinux*", "*i686*", "pp*"]
16
16
 
@@ -1,9 +1,8 @@
1
1
  import time
2
2
  import numpy as np
3
- import fire
3
+ import math
4
4
 
5
- import numpy as np
6
- from numba import cfunc, types, carray
5
+ import fire
7
6
 
8
7
  from usearch.index import Index
9
8
  from usearch.io import load_matrix
@@ -51,25 +50,6 @@ def bench_usearch(index, vectors: np.array, queries: np.array, neighbors: np.arr
51
50
  recall_at_one /= queries.shape[0]
52
51
  print(f'- Recall@1: {recall_at_one * 100:.2f} %')
53
52
 
54
- # Showcases how to use Numba to JIT-compile similarity measures for USearch.
55
- # https://numba.readthedocs.io/en/stable/reference/jit-compilation.html#c-callbacks
56
-
57
-
58
- signature_f32 = types.float32(
59
- types.CPointer(types.float32),
60
- types.CPointer(types.float32),
61
- types.size_t, types.size_t)
62
-
63
-
64
- @cfunc(signature_f32)
65
- def inner_product_f32(a, b, n, m):
66
- a_array = carray(a, n)
67
- b_array = carray(b, n)
68
- c = types.float32(0)
69
- for i in range(n):
70
- c += a_array[i] * b_array[i]
71
- return types.float32(1 - c)
72
-
73
53
 
74
54
  def main(
75
55
  vectors: str,
@@ -94,16 +74,6 @@ def main(
94
74
  )
95
75
  bench_usearch(index, vectors_mat, queries_mat, neighbors_mat)
96
76
 
97
- print('USearch: HNSW + Numba JIT')
98
- index = Index(
99
- ndim=dim,
100
- expansion_add=expansion_add,
101
- expansion_search=expansion_search,
102
- connectivity=connectivity,
103
- metric_pointer=inner_product_f32.address,
104
- )
105
- bench_usearch(index, vectors_mat, queries_mat, neighbors_mat)
106
-
107
77
  print('USearch: HNSW + Half Precision')
108
78
  index = Index(
109
79
  ndim=dim,
@@ -124,27 +94,94 @@ def main(
124
94
  )
125
95
  bench_usearch(index, vectors_mat, queries_mat, neighbors_mat)
126
96
 
97
+ # Showcases how to use Numba to JIT-compile similarity measures for USearch.
98
+ # https://numba.readthedocs.io/en/stable/reference/jit-compilation.html#c-callbacks
99
+ try:
100
+ from numba import cfunc, types, carray
101
+
102
+ signature_f32 = types.float32(
103
+ types.CPointer(types.float32),
104
+ types.CPointer(types.float32),
105
+ types.size_t, types.size_t)
106
+
107
+ @cfunc(signature_f32)
108
+ def inner_product_f32(a, b, n, m):
109
+ a_array = carray(a, n)
110
+ b_array = carray(b, n)
111
+ c = types.float32(0)
112
+ for i in range(n):
113
+ c += a_array[i] * b_array[i]
114
+ return types.float32(1 - c)
115
+
116
+ signature_f8 = types.float32(
117
+ types.CPointer(types.int8),
118
+ types.CPointer(types.int8),
119
+ types.size_t, types.size_t)
120
+
121
+ @cfunc(signature_f8)
122
+ def cos_f8(a, b, n, m):
123
+ a_array = carray(a, n)
124
+ b_array = carray(b, n)
125
+ c = types.int32(0)
126
+ a_sq = types.int32(0)
127
+ b_sq = types.int32(0)
128
+ for i in range(n):
129
+ ai = types.int16(a_array[i])
130
+ bi = types.int16(b_array[i])
131
+ c += ai * bi
132
+ a_sq += ai * ai
133
+ b_sq += bi * bi
134
+ a_norm = math.sqrt(types.float32(a_sq))
135
+ b_norm = math.sqrt(types.float32(b_sq))
136
+ c_norm = types.float32(c) / (a_norm * b_norm)
137
+ return types.float32(1 - c_norm)
138
+
139
+ print('USearch: HNSW + Numba JIT')
140
+ index = Index(
141
+ ndim=dim,
142
+ expansion_add=expansion_add,
143
+ expansion_search=expansion_search,
144
+ connectivity=connectivity,
145
+ metric_pointer=inner_product_f32.address,
146
+ )
147
+ bench_usearch(index, vectors_mat, queries_mat, neighbors_mat)
148
+
149
+ print('USearch: HNSW + Quarter Precision + Numba JIT')
150
+ index = Index(
151
+ ndim=dim,
152
+ dtype='f8',
153
+ expansion_add=expansion_add,
154
+ expansion_search=expansion_search,
155
+ connectivity=connectivity,
156
+ metric_pointer=cos_f8.address,
157
+ )
158
+ bench_usearch(index, vectors_mat, queries_mat, neighbors_mat)
159
+ except ImportError:
160
+ print('Skipping Numba benchmarks')
161
+
127
162
  # Don't depend on the FAISS installation for benchmarks
128
163
  try:
129
164
  from faiss import IndexHNSWFlat, IndexIVFPQ
165
+
166
+ print('FAISS: HNSW')
167
+ index = IndexHNSWFlat(dim, connectivity)
168
+ index.hnsw.efSearch = expansion_search
169
+ index.hnsw.efConstruction = expansion_add
170
+ bench_faiss(index, vectors_mat, queries_mat, neighbors_mat)
171
+
172
+ print('FAISS: HNSW + IVFPQ')
173
+ # Number of inverted lists (number of partitions or cells).
174
+ nlist = 10000
175
+ nsegment = 16 # Number of segments for PQ (number of subquantizers).
176
+ nbit = 8 # Number of bits to encode each segment.
177
+ coarse_quantizer = IndexHNSWFlat(dim, connectivity)
178
+ index = IndexIVFPQ(coarse_quantizer, dim, nlist, nsegment, nbit)
179
+ index.train(vectors_mat)
180
+ index.nprobe = 10
181
+ bench_faiss(index, vectors_mat, queries_mat, neighbors_mat)
182
+
130
183
  except ImportError:
131
- return
132
-
133
- print('FAISS: HNSW')
134
- index = IndexHNSWFlat(dim, connectivity)
135
- index.hnsw.efSearch = expansion_search
136
- index.hnsw.efConstruction = expansion_add
137
- bench_faiss(index, vectors_mat, queries_mat, neighbors_mat)
138
-
139
- print('FAISS: HNSW + IVFPQ')
140
- nlist = 10000 # Number of inverted lists (number of partitions or cells).
141
- nsegment = 16 # Number of segments for PQ (number of subquantizers).
142
- nbit = 8 # Number of bits to encode each segment.
143
- coarse_quantizer = IndexHNSWFlat(dim, connectivity)
144
- index = IndexIVFPQ(coarse_quantizer, dim, nlist, nsegment, nbit)
145
- index.train(vectors_mat)
146
- index.nprobe = 10
147
- bench_faiss(index, vectors_mat, queries_mat, neighbors_mat)
184
+ print('Skipping FAISS benchmarks')
148
185
 
149
186
 
150
187
  if __name__ == '__main__':
@@ -1,6 +1,7 @@
1
1
  import os
2
2
  import time
3
3
  import numpy as np
4
+
4
5
  import fire
5
6
  import plotly.express as px
6
7
  import numpy as np