usearch 0.11.0 → 0.11.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.11.0"
3
+ version = "0.11.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.11.0
1
+ 0.11.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.11.0'
7
+ version = '0.11.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.11.0",
3
+ "version": "0.11.1",
4
4
  "description": "Smaller & Faster Single-File Vector Search Engine from Unum",
5
5
  "author": "Ashot Vardanian",
6
6
  "license": "Apache 2.0",
@@ -1,8 +1,10 @@
1
- from typing import Union, Optional
1
+ from typing import Union, Optional, List
2
2
 
3
3
  import numpy as np
4
4
  from ucall.client import Client
5
5
 
6
+ from usearch.index import Matches
7
+
6
8
 
7
9
  def _vector_to_ascii(vector: np.ndarray) -> Optional[str]:
8
10
  if vector.dtype != np.int8 and vector.dtype != np.uint8 and vector.dtype != np.byte:
@@ -18,9 +20,6 @@ def _vector_to_ascii(vector: np.ndarray) -> Optional[str]:
18
20
  return ascii
19
21
 
20
22
 
21
- Triplet = tuple[np.ndarray, np.ndarray, np.ndarray]
22
-
23
-
24
23
  class IndexClient:
25
24
 
26
25
  def __init__(
@@ -53,8 +52,8 @@ class IndexClient:
53
52
  else:
54
53
  return self.add_many(labels, vectors)
55
54
 
56
- def search_one(self, vector: np.ndarray, count: int) -> Triplet:
57
- matches: list[dict] = []
55
+ def search_one(self, vector: np.ndarray, count: int) -> Matches:
56
+ matches: List[dict] = []
58
57
  vector = vector.flatten()
59
58
  ascii = _vector_to_ascii(vector)
60
59
  if ascii:
@@ -75,9 +74,9 @@ class IndexClient:
75
74
 
76
75
  return labels, distances, counts
77
76
 
78
- def search_many(self, vectors: np.ndarray, count: int) -> Triplet:
77
+ def search_many(self, vectors: np.ndarray, count: int) -> Matches:
79
78
  batch_size: int = vectors.shape[0]
80
- list_of_matches: list[list[dict]] = self.client.search_many(
79
+ list_of_matches: List[List[dict]] = self.client.search_many(
81
80
  vectors=vectors, count=count)
82
81
 
83
82
  labels = np.array((batch_size, count), dtype=np.uint32)
@@ -91,7 +90,7 @@ class IndexClient:
91
90
 
92
91
  return labels, distances, counts
93
92
 
94
- def search(self, vectors: np.ndarray, count: int) -> Triplet:
93
+ def search(self, vectors: np.ndarray, count: int) -> Matches:
95
94
  if vectors.ndim == 1 or (vectors.ndim == 2 and vectors.shape[0] == 1):
96
95
  return self.search_one(vectors, count)
97
96
  else:
@@ -4,7 +4,7 @@
4
4
  # into the primary `Index` class, connecting USearch with Numba.
5
5
  import os
6
6
  from math import sqrt
7
- from typing import Optional, Callable, Union
7
+ from typing import Optional, Callable, Union, NamedTuple, List
8
8
 
9
9
  import numpy as np
10
10
 
@@ -13,12 +13,17 @@ from usearch.compiled import SetsIndex as _CompiledSetsIndex
13
13
  from usearch.compiled import HashIndex as _CompiledHashIndex
14
14
  from usearch.compiled import DEFAULT_CONNECTIVITY, DEFAULT_EXPANSION_ADD, DEFAULT_EXPANSION_SEARCH
15
15
 
16
- Triplet = tuple[np.ndarray, np.ndarray, np.ndarray]
17
16
  SetsIndex = _CompiledSetsIndex
18
17
  HashIndex = _CompiledHashIndex
19
18
 
20
19
 
21
- def results_to_list(results: Triplet, row: int) -> list[dict]:
20
+ class Matches(NamedTuple):
21
+ labels: np.ndarray
22
+ distances: np.ndarray
23
+ counts: np.ndarray
24
+
25
+
26
+ def list_matches(results: Matches, row: int) -> List[dict]:
22
27
 
23
28
  count = results[2][row]
24
29
  labels = results[0][row, :count]
@@ -236,8 +241,11 @@ class Index:
236
241
 
237
242
  def search(
238
243
  self, vectors, k: int = 10, *,
239
- threads: int = 0, exact: bool = False) -> Triplet:
240
- return self._compiled.search(vectors, k, exact=exact, threads=threads)
244
+ threads: int = 0, exact: bool = False) -> Matches:
245
+ tuple_ = self._compiled.search(
246
+ vectors, k,
247
+ exact=exact, threads=threads)
248
+ return Matches(*tuple_)
241
249
 
242
250
  def __len__(self) -> int:
243
251
  return len(self._compiled)
@@ -4,20 +4,10 @@
4
4
  import os
5
5
  import argparse
6
6
  import numpy as np
7
+ from typing import List
7
8
 
8
9
  from ucall.rich_posix import Server
9
- from usearch.index import Index
10
-
11
- Triplet = tuple[np.ndarray, np.ndarray, np.ndarray]
12
-
13
-
14
- def _results_to_json(results: Triplet, row: int) -> list[dict]:
15
-
16
- count = results[2][row]
17
- labels = results[0][row, :count]
18
- distances = results[1][row, :count]
19
- return [{'label': int(label), 'distance': float(distance)}
20
- for label, distance in zip(labels, distances)]
10
+ from usearch.index import Index, list_matches
21
11
 
22
12
 
23
13
  def _ascii_to_vector(string: str) -> np.ndarray:
@@ -78,16 +68,16 @@ def serve(
78
68
  index.add(labels, vectors, threads=threads)
79
69
 
80
70
  @server
81
- def search_one(vector: np.ndarray, count: int) -> list[dict]:
71
+ def search_one(vector: np.ndarray, count: int) -> List[dict]:
82
72
  print('search', vector, count)
83
73
  vectors = vector.reshape(vector.shape[0], 1)
84
74
  results = index.search(vectors, count)
85
- return _results_to_json(results, 0)
75
+ return list_matches(results, 0)
86
76
 
87
77
  @server
88
- def search_many(vectors: np.ndarray, count: int) -> list[list[dict]]:
78
+ def search_many(vectors: np.ndarray, count: int) -> List[List[dict]]:
89
79
  results = index.search(vectors, count)
90
- return [_results_to_json(results, i) for i in range(vectors.shape[0])]
80
+ return [list_matches(results, i) for i in range(vectors.shape[0])]
91
81
 
92
82
  @server
93
83
  def add_ascii(label: int, string: str):