usearch 2.0.1 → 2.1.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.
@@ -0,0 +1,34 @@
1
+ FROM ubuntu:22.04
2
+ ENV DEBIAN_FRONTEND=noninteractive
3
+
4
+ ENV user_name="runner"
5
+ ARG TARGETPLATFORM
6
+ ARG docker_ip
7
+ ARG user_pass
8
+
9
+ RUN apt-get update && \
10
+ apt-get install -y --no-install-recommends python3.11 python3-pip cmake g++-12 build-essential libjemalloc-dev golang openssh-client sshpass && \
11
+ apt-get clean && \
12
+ rm -rf /var/lib/apt/lists/*
13
+
14
+ COPY . .
15
+
16
+ RUN cd golang && make -C ../c libusearch_c.so && \
17
+ mv ../c/libusearch_c.so libusearch.a && cp ../c/usearch.h usearch.h && \
18
+ go test -v && cd ..
19
+
20
+ RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \
21
+ export arch="amd"; \
22
+ elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
23
+ export arch="arm"; \
24
+ fi && \
25
+ version=$(cat VERSION) && \
26
+ mkdir -p usearch_"$arch"_"$version"/DEBIAN && \
27
+ touch usearch_"$arch"_"$version"/DEBIAN/control && \
28
+ mkdir -p usearch_"$arch"_"$version"/usr/local/lib && \
29
+ mkdir usearch_"$arch"_"$version"/usr/local/include && \
30
+ cp c/usearch.h usearch_"$arch"_"$version"/usr/local/include/ && \
31
+ cp golang/libusearch.a usearch_"$arch"_"$version"/usr/local/lib/ && \
32
+ echo "Package: usearch\nVersion: $version\nMaintainer: Ashot Vardanian\nArchitecture: "$arch"\nDescription: Faster & Smaller Single-File Search Engine for Vectors & Texts" > usearch_"$arch"_"$version"/DEBIAN/control && \
33
+ dpkg-deb --build usearch_"$arch"_"$version" && \
34
+ sshpass -p "$user_pass" scp -o StrictHostKeyChecking=no usearch_"$arch"_"$version".deb "$user_name"@"$docker_ip":/home/$user_name/work/usearch/usearch/
@@ -96,6 +96,62 @@ jobs:
96
96
  * Source code (tar.gz) : `${{ steps.hashes.outputs.tar_hash }}`
97
97
 
98
98
 
99
+ create_deb_packages_linux:
100
+ name: Create deb package for Linux on ${{ matrix.arch }}
101
+ needs: versioning
102
+ runs-on: ubuntu-latest
103
+ strategy:
104
+ matrix:
105
+ arch: ["linux/amd64", "linux/arm64"]
106
+ steps:
107
+ - uses: actions/checkout@v3
108
+ with:
109
+ persist-credentials: false
110
+ ref: 'main'
111
+ - run: git submodule update --init --recursive
112
+
113
+ - name: Set up QEMU
114
+ uses: docker/setup-qemu-action@v2
115
+
116
+ - name: Set up Docker Buildx
117
+ uses: docker/setup-buildx-action@v2
118
+
119
+ - name: Get docker daemon IP
120
+ id: dockerip
121
+ run: |
122
+ docker_ip=$(ip addr show docker0 | grep -Po 'inet \K[\d.]+') && \
123
+ echo "docker_ip=$docker_ip" >> "$GITHUB_OUTPUT"
124
+
125
+ - name: Set new password for runner user
126
+ id: userpass
127
+ run: |
128
+ user_pass="1122"
129
+ echo "runner:$user_pass" | sudo chpasswd
130
+ echo "user_pass=$user_pass" >> "$GITHUB_OUTPUT"
131
+
132
+ - name: Build Usearch lib
133
+ run: |
134
+ docker buildx create --use
135
+ docker buildx build \
136
+ --platform ${{ matrix.arch }} \
137
+ --build-arg docker_ip=${{ steps.dockerip.outputs.docker_ip }} \
138
+ --build-arg user_pass=${{ steps.userpass.outputs.user_pass }} \
139
+ --file .github/workflows/Dockerfile.libs \
140
+ --tag unum/ustore-deps:latest \
141
+ --load .
142
+
143
+ - name: Clear Docker buildx cache
144
+ run: docker buildx prune --all --force
145
+
146
+ - name: Upload archive to release Assets
147
+ uses: xresloader/upload-to-github-release@v1
148
+ env:
149
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
150
+ with:
151
+ file: "*.deb"
152
+ update_latest_release: true
153
+
154
+
99
155
  build_wheels:
100
156
  name: Build Wheels for ${{ matrix.os }}
101
157
  needs: versioning
package/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "usearch"
3
- version = "2.0.1"
3
+ version = "2.1.0"
4
4
  authors = ["Ash Vardanian <1983160+ashvardanian@users.noreply.github.com>"]
5
5
  description = "Smaller & Faster Single-File Vector Search Engine from Unum"
6
6
  edition = "2021"
package/README.md CHANGED
@@ -28,6 +28,7 @@ Euclidean • Angular • Bitwise • Haversine • User-Defined Metrics
28
28
  <a href="https://unum-cloud.github.io/usearch/c">C 99</a> •
29
29
  <a href="https://unum-cloud.github.io/usearch/objective-c">Objective-C</a> •
30
30
  <a href="https://unum-cloud.github.io/usearch/swift">Swift</a> •
31
+ <a href="https://unum-cloud.github.io/usearch/csharp">C#</a> •
31
32
  <a href="https://unum-cloud.github.io/usearch/golang">GoLang</a> •
32
33
  <a href="https://unum-cloud.github.io/usearch/wolfram">Wolfram</a>
33
34
  <br/>
@@ -38,6 +39,8 @@ Linux • MacOS • Windows • iOS • Docker • WebAssembly
38
39
  <a href="https://pypi.org/project/usearch/"> <img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dm/usearch?label=pypi%20downloads"> </a>
39
40
  <a href="https://www.npmjs.com/package/usearch"> <img alt="npm" src="https://img.shields.io/npm/dy/usearch?label=npm%20dowloads"> </a>
40
41
  <a href="https://crates.io/crates/usearch"> <img alt="Crates.io" src="https://img.shields.io/crates/d/usearch?label=crate%20downloads"> </a>
42
+ <a href="https://www.nuget.org/packages/Cloud.Unum.USearch"> <img alt="Nuget" src="https://img.shields.io/nuget/dt/Cloud.Unum.USearch?style=social&label=NuGet"> </a>
43
+ <a href="https://hub.docker.com/r/unum/usearch"> <img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/unum/usearch?style=social&label=Docker"> </a>
41
44
  <img alt="GitHub code size in bytes" src="https://img.shields.io/github/languages/code-size/unum-cloud/usearch">
42
45
  </div>
43
46
 
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 = '2.0.1'
7
+ version = '2.1.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/csharp/README.md CHANGED
@@ -3,17 +3,17 @@
3
3
  ## Installation
4
4
 
5
5
  ```sh
6
- dotnet add package Cloud.Unum.USearch -s https://apiint.nugettest.org/v3/index.json
6
+ dotnet add package Cloud.Unum.USearch
7
7
  ```
8
8
 
9
9
  ## Quickstart
10
10
 
11
- ```C#
11
+ ```csharp
12
12
  using System.Diagnostics;
13
13
  using Cloud.Unum.USearch;
14
14
 
15
15
  using var index = new USearchIndex(
16
- metricKind: MetricKind.Cos, //Choose cosine metric
16
+ metricKind: MetricKind.Cos, // Choose cosine metric
17
17
  quantization: ScalarKind.Float32, // Only quantization to Float32, Float64 is currently supported
18
18
  dimensions: 3, // Define the number of dimensions in input vectors
19
19
  connectivity: 16, // How frequent should the connections in the graph be, optional
@@ -29,21 +29,18 @@ Trace.Assert(index.Size() == 1);
29
29
  Trace.Assert(matches == 1);
30
30
  Trace.Assert(keys[0] == 42);
31
31
  Trace.Assert(distances[0] <= 0.001f);
32
- // USearchIndex obj created with "using statement" and implements IDisposable,
33
- // otherwise call it explicitly:
34
- // index.Dispose();
35
32
  ```
36
33
 
37
34
  ## Serialization
38
35
 
39
- ```C#
36
+ ```csharp
40
37
  index.Save("index.usearch")
41
38
 
42
39
  // Copy the whole index into memory
43
40
  using var indexLoaded = new USearchIndex("index.usearch");
44
41
 
45
42
  // Or view from disk without loading in memory
46
- // using var indexLoaded = new USearchIndex("index.usearch", view: True);
43
+ // using var indexLoaded = new USearchIndex("index.usearch", view: true);
47
44
 
48
45
  Trace.Assert(indexLoaded.Size() == 1);
49
46
  Trace.Assert(indexLoaded.Dimensions() == 3);
@@ -55,7 +52,7 @@ Trace.Assert(indexLoaded.Contains(42));
55
52
 
56
53
  Adding a batch of entries is identical to adding a single vector.
57
54
 
58
- ```C#
55
+ ```csharp
59
56
  using var index = new USearchIndex(MetricKind.Cos, ScalarKind.Float32, dimensions: 3);
60
57
 
61
58
  // Generate keys and random vectors
@@ -0,0 +1,6 @@
1
+ ==============
2
+ C# SDK
3
+ ==============
4
+
5
+
6
+ .. mdinclude:: ../../csharp/README.md
package/docs/index.rst CHANGED
@@ -14,6 +14,7 @@ Overview
14
14
  java/index
15
15
  c/index
16
16
  swift/index
17
+ csharp/index
17
18
  golang/index
18
19
  wolfram/index
19
20
 
package/golang/README.md CHANGED
@@ -2,51 +2,72 @@
2
2
 
3
3
  ## Installation
4
4
 
5
- ```golang
6
- import (
7
- "github.com/unum-cloud/usearch/golang-go"
8
- )
5
+ Download and install from the Debian package from the latest release.
6
+ Substitute `<release_tag>`, `<arch>`, and `<usearch_version>` with your settings.
7
+
8
+ ```
9
+ wget https://github.com/unum-cloud/usearch/releases/download/<release_tag>/usearch_<arch>_<usearch_version>.deb
10
+ dpkg -i usearch_<arch>_<usearch_version>.deb
9
11
  ```
10
12
 
11
13
  ## Quickstart
12
14
 
13
- ```golang
14
- package main
15
+ 1. Create a `go.mod` file:
15
16
 
16
- import (
17
- "fmt"
18
- "github.com/unum-cloud/usearch/golang-go"
19
- )
17
+ ```
18
+ module usearch_example
20
19
 
21
- func main() {
22
- dim := uint(128)
23
- conf := DefaultConfig(dim)
24
- ind, err := NewIndex(conf)
25
- if err != nil {
26
- panic("Failed to construct the index: %s", err)
27
- }
28
- defer ind.Destroy()
20
+ go <go_version>
21
+ ```
29
22
 
30
- err = ind.Reserve(100)
31
- if err != nil {
32
- panic("Failed to reserve capacity: %s", err)
33
- }
23
+ 2. Create an `example.go`:
34
24
 
35
- vec := make([]float32, dim)
36
- vec[0] = 40.0
37
- vec[1] = 2.0
25
+ ```golang
26
+ package main
38
27
 
39
- err = ind.Add(42, vec)
40
- if err != nil {
41
- panic("Failed to insert: %s", err)
42
- }
28
+ import (
29
+ "fmt"
30
+ usearch "github.com/unum-cloud/usearch/golang"
31
+ )
43
32
 
44
- keys, distances, err := ind.Search(vec, 10)
45
- if err != nil {
46
- panic("Failed to search: %s", err)
47
- }
48
- if keys[0] != 42 || distances[0] != 0.0 {
49
- panic("Expected result 42 with distance 0, got key %d with distance %f", keys[0], distances[0])
33
+ func main() {
34
+
35
+ // Create Index
36
+ vector_size := 3
37
+ vectors_count := 100
38
+ conf := usearch.DefaultConfig(uint(vector_size))
39
+ index,err := usearch.NewIndex(conf)
40
+ if err != nil {
41
+ panic("Failed to create Index")
42
+ }
43
+ defer index.Destroy()
44
+
45
+ // Add to Index
46
+ err = index.Reserve(uint(vectors_count))
47
+ for i := 0; i < vectors_count; i++ {
48
+ err = index.Add(usearch.Key(i), []float32{float32(i), float32(i+1), float32(i+2)})
49
+ if err != nil {
50
+ panic("Failed to add")
51
+ }
52
+ }
53
+
54
+ // Search
55
+ keys, distances, err := index.Search([]float32{0.0, 1.0, 2.0}, 3)
56
+ if err != nil {
57
+ panic("Failed to search")
58
+ }
59
+ fmt.Println(keys, distances)
50
60
  }
51
- }
52
- ```
61
+ ```
62
+
63
+ 3. Get USearch:
64
+
65
+ ```
66
+ go get github.com/unum-cloud/usearch/golang
67
+ ```
68
+
69
+ 4. Run:
70
+
71
+ ```
72
+ go run example.go
73
+ ```
package/golang/lib.go CHANGED
@@ -6,9 +6,8 @@ import (
6
6
  )
7
7
 
8
8
  /*
9
- #cgo CFLAGS: -I${SRCDIR}/../c/
10
- #cgo LDFLAGS: -L${SRCDIR}/. -Wl,-rpath,\$ORIGIN/ -lusearch_c
11
- #include <usearch.h>
9
+ #cgo LDFLAGS: -L. -lusearch
10
+ #include "usearch.h"
12
11
  #include <stdlib.h>
13
12
  */
14
13
  import "C"
@@ -91,6 +90,8 @@ type IndexConfig struct {
91
90
  ExpansionAdd uint
92
91
  // The @b optional expansion factor used for index construction during search operations.
93
92
  ExpansionSearch uint
93
+ // The @b optional multi flag.
94
+ Multi bool
94
95
  }
95
96
 
96
97
  func DefaultConfig(dimensions uint) IndexConfig {
@@ -101,6 +102,7 @@ func DefaultConfig(dimensions uint) IndexConfig {
101
102
  c.Connectivity = 0
102
103
  c.ExpansionAdd = 0
103
104
  c.ExpansionSearch = 0
105
+ c.Multi = false
104
106
  return c
105
107
  }
106
108
 
@@ -114,16 +116,18 @@ func NewIndex(conf IndexConfig) (index *Index, err error) {
114
116
  index = &Index{config: conf}
115
117
 
116
118
  conf = index.config
117
- dimensions := C.ulong(conf.Dimensions)
118
- connectivity := C.ulong(conf.Connectivity)
119
- expansion_add := C.ulong(conf.ExpansionAdd)
120
- expansion_search := C.ulong(conf.ExpansionSearch)
119
+ dimensions := C.size_t(conf.Dimensions)
120
+ connectivity := C.size_t(conf.Connectivity)
121
+ expansion_add := C.size_t(conf.ExpansionAdd)
122
+ expansion_search := C.size_t(conf.ExpansionSearch)
123
+ multi := C.bool(conf.Multi)
121
124
 
122
125
  options := C.struct_usearch_init_options_t{}
123
126
  options.dimensions = dimensions
124
127
  options.connectivity = connectivity
125
128
  options.expansion_add = expansion_add
126
129
  options.expansion_search = expansion_search
130
+ options.multi = multi
127
131
 
128
132
  // Map the metric kind to a C enum
129
133
  switch conf.Metric {
@@ -281,21 +285,21 @@ func (index *Index) Contains(key Key) (found bool, err error) {
281
285
  return found, nil
282
286
  }
283
287
 
284
- func (index *Index) Get(key Key) (vector []float32, err error) {
288
+ func (index *Index) Get(key Key, count uint) (vectors []float32, err error) {
285
289
  if index.opaque_handle == nil {
286
290
  panic("Index is uninitialized")
287
291
  }
288
292
 
289
- vector = make([]float32, index.config.Dimensions)
293
+ vectors = make([]float32, index.config.Dimensions * count)
290
294
  var errorMessage *C.char
291
- found := bool(C.usearch_get((C.usearch_index_t)(unsafe.Pointer(index.opaque_handle)), (C.usearch_key_t)(key), unsafe.Pointer(&vector[0]), C.usearch_scalar_f32_k, (*C.usearch_error_t)(&errorMessage)))
295
+ found := uint(C.usearch_get((C.usearch_index_t)(unsafe.Pointer(index.opaque_handle)), (C.usearch_key_t)(key), (C.size_t)(count), unsafe.Pointer(&vectors[0]), C.usearch_scalar_f32_k, (*C.usearch_error_t)(&errorMessage)))
292
296
  if errorMessage != nil {
293
297
  return nil, errors.New(C.GoString(errorMessage))
294
298
  }
295
- if !found {
299
+ if found == 0 {
296
300
  return nil, nil
297
301
  }
298
- return vector, nil
302
+ return vectors, nil
299
303
  }
300
304
 
301
305
  // Performs k-Approximate Nearest Neighbors Search for closest vectors to query.
@@ -409,7 +409,10 @@ template <typename allocator_at = std::allocator<byte_t>> class bitset_gt {
409
409
  ~bitset_gt() noexcept { reset(); }
410
410
 
411
411
  explicit operator bool() const noexcept { return slots_; }
412
- void clear() noexcept { std::memset(slots_, 0, count_ * sizeof(compressed_slot_t)); }
412
+ void clear() noexcept {
413
+ if (slots_)
414
+ std::memset(slots_, 0, count_ * sizeof(compressed_slot_t));
415
+ }
413
416
 
414
417
  void reset() noexcept {
415
418
  if (slots_)
@@ -857,7 +860,8 @@ class growing_hash_set_gt {
857
860
  std::size_t size() const noexcept { return count_; }
858
861
 
859
862
  void clear() noexcept {
860
- std::memset((void*)slots_, 0xFF, capacity_ * sizeof(element_t));
863
+ if (slots_)
864
+ std::memset((void*)slots_, 0xFF, capacity_ * sizeof(element_t));
861
865
  count_ = 0;
862
866
  }
863
867
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usearch",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "Smaller & Faster Single-File Vector Search Engine from Unum",
5
5
  "author": "Ash Vardanian",
6
6
  "license": "Apache 2.0",
package/wasmer.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name="unum/usearch"
3
- version="2.0.1"
3
+ version="2.1.0"
4
4
  description="Smaller & Faster Single-File Vector Search Engine from Unum"
5
5
  license="Apache-2.0"
6
6
  readme="README.md"