usearch 0.17.1 → 0.18.0

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.
@@ -42,13 +42,13 @@ jobs:
42
42
  run: pytest python/scripts/test.py
43
43
 
44
44
 
45
- test_python_36:
46
- name: Test Python 3.6
45
+ test_python_37:
46
+ name: Test Python 3.7
47
47
  runs-on: ${{ matrix.os }}
48
48
  strategy:
49
49
  matrix:
50
50
  os: [ubuntu-20.04]
51
- python-version: ["3.6"]
51
+ python-version: ["3.7"]
52
52
 
53
53
  steps:
54
54
  - uses: actions/checkout@v3
@@ -62,7 +62,7 @@ jobs:
62
62
  - name: Install dependencies
63
63
  run: |
64
64
  python -m pip install --upgrade pip
65
- pip install pytest numpy dataclasses
65
+ pip install pytest numpy
66
66
 
67
67
  - name: Build locally
68
68
  run: python -m pip install .
@@ -125,6 +125,8 @@ jobs:
125
125
 
126
126
  - name: Build wheels
127
127
  run: python -m cibuildwheel
128
+ env:
129
+ CIBW_SKIP: cp36-*
128
130
 
129
131
  - uses: actions/upload-artifact@v3
130
132
  with:
package/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "usearch"
3
- version = "0.17.1"
3
+ version = "0.18.0"
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/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.17.1'
7
+ version = '0.18.0'
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.17.1",
3
+ "version": "0.18.0",
4
4
  "description": "Smaller & Faster Single-File Vector Search Engine from Unum",
5
5
  "author": "Ashot Vardanian",
6
6
  "license": "Apache 2.0",
@@ -1,4 +1,7 @@
1
- from typing import Tuple, Any, Callable, Union, Optional, List, NamedTuple
1
+ from __future__ import annotations
2
+ from time import time_ns
3
+ from typing import Tuple, Any, Callable, Union, Optional, List
4
+ from dataclasses import dataclass, asdict
2
5
  from collections import defaultdict
3
6
 
4
7
  import numpy as np
@@ -7,17 +10,6 @@ from usearch.io import load_matrix
7
10
  from usearch.index import Index, Matches, MetricKind, MetricKindBitwise
8
11
 
9
12
 
10
- # For compatibility with Python 3.6
11
- try:
12
- from time import time_ns
13
- except ImportError:
14
- from datetime import datetime
15
-
16
- def time_ns():
17
- now = datetime.now()
18
- return int(now.timestamp() * 1e9)
19
-
20
-
21
13
  def random_vectors(
22
14
  count: int,
23
15
  metric: MetricKind = MetricKind.IP,
@@ -89,7 +81,8 @@ def measure_seconds(f: Callable) -> Tuple[float, Any]:
89
81
  return secs, result
90
82
 
91
83
 
92
- class Dataset(NamedTuple):
84
+ @dataclass
85
+ class Dataset:
93
86
 
94
87
  labels: np.ndarray
95
88
  vectors: np.ndarray
@@ -163,7 +156,8 @@ class Dataset(NamedTuple):
163
156
  return d
164
157
 
165
158
 
166
- class TaskResult(NamedTuple):
159
+ @dataclass
160
+ class TaskResult:
167
161
 
168
162
  add_operations: Optional[int] = None
169
163
  add_per_second: Optional[float] = None
@@ -190,7 +184,7 @@ class TaskResult(NamedTuple):
190
184
  def search_seconds(self) -> float:
191
185
  return self.search_operations / self.search_per_second
192
186
 
193
- def __add__(self, other):
187
+ def __add__(self, other: TaskResult):
194
188
  result = TaskResult()
195
189
  if self.add_operations and other.add_operations:
196
190
  result.add_operations = self.add_operations + other.add_operations
@@ -217,7 +211,8 @@ class TaskResult(NamedTuple):
217
211
  return result
218
212
 
219
213
 
220
- class AddTask(NamedTuple):
214
+ @dataclass
215
+ class AddTask:
221
216
 
222
217
  labels: np.ndarray
223
218
  vectors: np.ndarray
@@ -251,7 +246,7 @@ class AddTask(NamedTuple):
251
246
  self.labels = self.labels[new_order]
252
247
  self.vectors = self.vectors[new_order, :]
253
248
 
254
- def slices(self, batch_size: int) -> list:
249
+ def slices(self, batch_size: int) -> List[AddTask]:
255
250
  """Splits this dataset into smaller chunks."""
256
251
 
257
252
  return [
@@ -260,7 +255,7 @@ class AddTask(NamedTuple):
260
255
  vectors=self.vectors[start_row:start_row+batch_size, :],
261
256
  ) for start_row in range(0, self.count, batch_size)]
262
257
 
263
- def clusters(self, number_of_clusters: int) -> list:
258
+ def clusters(self, number_of_clusters: int) -> List[AddTask]:
264
259
  """Splits this dataset into smaller chunks."""
265
260
 
266
261
  from sklearn.cluster import KMeans
@@ -280,7 +275,8 @@ class AddTask(NamedTuple):
280
275
  ) for rows in partitioning.values()]
281
276
 
282
277
 
283
- class SearchTask(NamedTuple):
278
+ @dataclass
279
+ class SearchTask:
284
280
 
285
281
  queries: np.ndarray
286
282
  neighbors: np.ndarray
@@ -295,7 +291,7 @@ class SearchTask(NamedTuple):
295
291
  recall_at_one=results.recall_first(self.neighbors[:, 0].flatten()),
296
292
  )
297
293
 
298
- def slices(self, batch_size: int) -> list:
294
+ def slices(self, batch_size: int) -> List[SearchTask]:
299
295
  """Splits this dataset into smaller chunks."""
300
296
 
301
297
  return [
@@ -305,7 +301,8 @@ class SearchTask(NamedTuple):
305
301
  ) for start_row in range(0, self.queries.shape[0], batch_size)]
306
302
 
307
303
 
308
- class Evaluation(NamedTuple):
304
+ @dataclass
305
+ class Evaluation:
309
306
 
310
307
  tasks: List[Union[AddTask, SearchTask]]
311
308
  count: int
@@ -315,7 +312,7 @@ class Evaluation(NamedTuple):
315
312
  def for_dataset(
316
313
  dataset: Dataset,
317
314
  batch_size: int = 0,
318
- clusters: int = 1):
315
+ clusters: int = 1) -> Evaluation:
319
316
 
320
317
  tasks = []
321
318
  add = AddTask(
@@ -356,5 +353,5 @@ class Evaluation(NamedTuple):
356
353
  index.clear()
357
354
  return {
358
355
  **index.specs,
359
- **task_result._asdict(),
356
+ **asdict(task_result),
360
357
  }